Imported Upstream version 2.4.5p1
[debian/amanda] / common-src / file.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1997-1998 University of Maryland at College Park
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of U.M. not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  U.M. makes no representations about the
13  * suitability of this software for any purpose.  It is provided "as is"
14  * without express or implied warranty.
15  *
16  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Author: AMANDA core development group.
24  */
25 /*
26  * $Id: file.c,v 1.14.4.6.4.2.2.5.2.1 2005/09/20 21:31:52 jrjackson Exp $
27  *
28  * file and directory bashing routines
29  */
30
31 #include "amanda.h"
32 #include "util.h"
33
34 uid_t client_uid = (uid_t) -1;
35 gid_t client_gid = (gid_t) -1;
36
37 /* Make a directory (internal function).
38 ** If the directory already exists then we pretend we created it.
39 ** XXX - I'm not sure about the use of the chown() stuff.  On most systems
40 **       it will do nothing - only root is permitted to change the owner
41 **       of a file.
42 */
43 int mk1dir(dir, mode, uid, gid)
44 char *dir;      /* directory to create */
45 int mode;       /* mode for new directory */
46 uid_t uid;      /* uid for new directory */
47 gid_t gid;      /* gid for new directory */
48 {
49     int rc;     /* return code */
50
51     rc = 0;     /* assume the best */
52
53     if(mkdir(dir, mode) == 0) {
54         chmod(dir, mode);       /* mkdir() is affected by the umask */
55         chown(dir, uid, gid);   /* XXX - no-op on most systems? */
56     } else {                    /* maybe someone beat us to it */
57         int serrno;
58
59         serrno = errno;
60         if(access(dir, F_OK) != 0) rc = -1;
61         errno = serrno; /* pass back the real error */
62     }
63
64     return rc;
65 }
66
67
68 /*
69  * Make a directory hierarchy given an entry to be created (by the caller)
70  * in the new target.  In other words, create all the directories down to
71  * the last element, but not the last element.  So a (potential) file name
72  * may be passed to mkpdir and all the parents of that file will be created.
73  */
74 int mkpdir(file, mode, uid, gid)
75 char *file;     /* file to create parent directories for */
76 int mode;       /* mode for new directories */
77 uid_t uid;      /* uid for new directories */
78 gid_t gid;      /* gid for new directories */
79 {
80     char *dir = NULL, *p;
81     int rc;     /* return code */
82
83     rc = 0;
84
85     dir = stralloc(file);       /* make a copy we can play with */
86
87     p = strrchr(dir, '/');
88     if(p != dir && p != NULL) { /* got a '/' or a simple name */
89         *p = '\0';
90
91         if(access(dir, F_OK) != 0) {    /* doesn't exist */
92             if(mkpdir(dir, mode, uid, gid) != 0 ||
93                mk1dir(dir, mode, uid, gid) != 0) rc = -1; /* create failed */
94         }
95     }
96
97     amfree(dir);
98     return rc;
99 }
100
101
102 /* Remove as much of a directory hierarchy as possible.
103 ** Notes:
104 **  - assumes that rmdir() on a non-empty directory will fail!
105 **  - stops deleting before topdir, ie: topdir will not be removed
106 **  - if file is not under topdir this routine will not notice
107 */
108 int rmpdir(file, topdir)
109 char *file;     /* directory hierarchy to remove */
110 char *topdir;   /* where to stop removing */
111 {
112     int rc;
113     char *p, *dir = NULL;
114
115     if(strcmp(file, topdir) == 0) return 0; /* all done */
116
117     rc = rmdir(file);
118     if (rc != 0) switch(errno) {
119 #ifdef ENOTEMPTY
120 #if ENOTEMPTY != EEXIST                 /* AIX makes these the same */
121         case ENOTEMPTY:
122 #endif
123 #endif
124         case EEXIST:    /* directory not empty */
125             return 0; /* cant do much more */
126         case ENOENT:    /* it has already gone */
127             rc = 0; /* ignore */
128             break;
129         case ENOTDIR:   /* it was a file */
130             rc = unlink(file);
131             break;
132         }
133
134     if(rc != 0) return -1; /* unexpected error */
135
136     dir = stralloc(file);
137
138     p = strrchr(dir, '/');
139     if(p == dir) rc = 0; /* no /'s */
140     else {
141         *p = '\0';
142
143         rc = rmpdir(dir, topdir);
144     }
145
146     amfree(dir);
147
148     return rc;
149 }
150
151
152 /*
153  *=====================================================================
154  * Do Amanda setup for all programs.
155  *
156  * void amanda_setup (int argc, char **argv, int setup_flags)
157  *
158  * entry:       setup_flags (see AMANDA_SETUP_FLAG_xxx)
159  * exit:        none
160  *=====================================================================
161  */
162
163 void
164 amanda_setup (argc, argv, setup_flags)
165     int                 argc;
166     char                **argv;
167     int                 setup_flags;
168 {
169 }
170
171 /*
172  *=====================================================================
173  * Change directory to a "safe" location and set some base environment.
174  *
175  * void safe_cd (void)
176  *
177  * entry:       client_uid and client_gid set to CLIENT_LOGIN information
178  * exit:        none
179  *
180  * Set a default umask of 0077.
181  *
182  * Create the Amada debug directory (if defined) and the Amanda temp
183  * directory.
184  *
185  * Try to chdir to the Amanda debug directory first, but it must be owned
186  * by the Amanda user and not allow rwx to group or other.  Otherwise,
187  * try the same thing to the Amanda temp directory.
188  *
189  * If that is all OK, call save_core().
190  *
191  * Otherwise, cd to "/" so if we take a signal we cannot drop core
192  * unless the system administrator has made special arrangements (e.g.
193  * pre-created a core file with the right ownership and permissions).
194  *=====================================================================
195  */
196
197 void
198 safe_cd()
199 {
200     int                 cd_ok = 0;
201     struct stat         sbuf;
202     struct passwd       *pwent;
203     char                *d;
204
205     if(client_uid == (uid_t) -1 && (pwent = getpwnam(CLIENT_LOGIN)) != NULL) {
206         client_uid = pwent->pw_uid;
207         client_gid = pwent->pw_gid;
208         endpwent();
209     }
210
211     (void) umask(0077);
212
213     if (client_uid != (uid_t) -1) {
214 #if defined(AMANDA_DBGDIR)
215         d = stralloc2(AMANDA_DBGDIR, "/.");
216         (void) mkpdir(d, 02700, client_uid, client_gid);
217         amfree(d);
218 #endif
219         d = stralloc2(AMANDA_TMPDIR, "/.");
220         (void) mkpdir(d, 02700, client_uid, client_gid);
221         amfree(d);
222     }
223
224 #if defined(AMANDA_DBGDIR)
225     if (chdir(AMANDA_DBGDIR) != -1
226         && stat(".", &sbuf) != -1
227         && (sbuf.st_mode & 0777) == 0700        /* drwx------ */
228         && sbuf.st_uid == client_uid) {         /* owned by Amanda user */
229         cd_ok = 1;                              /* this is a good place to be */
230     }
231 #endif
232     if (! cd_ok
233         && chdir(AMANDA_TMPDIR) != -1
234         && stat(".", &sbuf) != -1
235         && (sbuf.st_mode & 0777) == 0700        /* drwx------ */
236         && sbuf.st_uid == client_uid) {         /* owned by Amanda user */
237         cd_ok = 1;                              /* this is a good place to be */
238     }
239     if(cd_ok) {
240         save_core();                            /* save any old core file */
241     } else {
242         (void) chdir("/");                      /* assume this works */
243     }
244 }
245
246 /*
247  *=====================================================================
248  * Close all file descriptors except stdin, stdout and stderr.  Make
249  * sure they are open.
250  *
251  * void safe_fd (fd_start, fd_count)
252  *
253  * entry:       fd_start - start of fd-s to leave alone (or -1)
254  *              fd_count - count of fd-s to leave alone
255  * exit:        none
256  *
257  * On exit, all three standard file descriptors will be open and pointing
258  * someplace (either what we were handed or /dev/null) and all other
259  * file descriptors (up to FD_SETSIZE) will be closed.
260  *=====================================================================
261  */
262
263 void
264 safe_fd(fd_start, fd_count)
265     int                 fd_start;
266     int                 fd_count;
267 {
268     int                 fd;
269
270     for(fd = 0; fd < FD_SETSIZE; fd++) {
271         if (fd < 3) {
272             /*
273              * Open three file descriptors.  If stdin, stdout and stderr
274              * are normal, i.e. open, we will open descriptor numbers
275              * 3 or higher which the rest of this loop will turn right
276              * around and close.  If one of the standard descriptors
277              * is not open it will end up pointing to /dev/null and the
278              * rest of the loop will leave it alone.
279              *
280              * This avoids, for instance, someone running us with stderr
281              * closed so that when we open some other file, messages
282              * sent to stderr do not accidentally get written to the
283              * wrong file.
284              */
285             (void) open("/dev/null", O_RDWR);
286         } else {
287             /*
288              * Make sure nobody spoofs us with a lot of extra open files
289              * that would cause an open we do to get a very high file
290              * descriptor, which in turn might be used as an index into
291              * an array (e.g. an fd_set).
292              */
293             if (fd < fd_start || fd >= fd_start + fd_count) {
294                 close(fd);
295             }
296         }
297     }
298
299 }
300
301 /*
302  *=====================================================================
303  * Save an existing core file.
304  *
305  * void save_core (void)
306  *
307  * entry:       none
308  * exit:        none
309  *
310  * Renames:
311  *
312  *      "core"          to "coreYYYYMMDD",
313  *      "coreYYYYMMDD"  to "coreYYYYMMDDa",
314  *      "coreYYYYMMDDa" to "coreYYYYMMDDb",
315  *      ...
316  *
317  * ... where YYYYMMDD is the modification time of the original file.
318  * If it gets that far, an old "coreYYYYMMDDz" is thrown away.
319  *=====================================================================
320  */
321
322 void
323 save_core()
324 {
325     struct stat sbuf;
326
327     if(stat("core", &sbuf) != -1) {
328         char *ts;
329         char suffix[2];
330         char *old, *new;
331
332         ts = construct_datestamp((time_t *)&sbuf.st_mtime);
333         suffix[0] = 'z';
334         suffix[1] = '\0';
335         old = vstralloc("core", ts, suffix, NULL);
336         new = NULL;
337         while(ts[0] != '\0') {
338             amfree(new);
339             new = old;
340             if(suffix[0] == 'a') {
341                 suffix[0] = '\0';
342             } else if(suffix[0] == '\0') {
343                 ts[0] = '\0';
344             } else {
345                 suffix[0]--;
346             }
347             old = vstralloc("core", ts, suffix, NULL);
348             (void)rename(old, new);         /* it either works ... */
349         }
350         amfree(ts);
351         amfree(old);
352         amfree(new);
353     }
354 }
355
356 /*
357 ** Sanitise a file name.
358 ** 
359 ** Convert all funny characters to '_' so that we can use,
360 ** for example, disk names as part of file names.
361 ** Notes: 
362 **  - there is a many-to-one mapping between input and output
363 ** XXX - We only look for '/' and ' ' at the moment.  May
364 ** XXX - be we should also do all unprintables.
365 */
366 char *sanitise_filename(inp)
367 char *inp;
368 {
369     char *buf;
370     int buf_size;
371     char *s, *d;
372     int ch;
373
374     buf_size = 2 * strlen(inp) + 1;             /* worst case */
375     buf = alloc(buf_size);
376     d = buf;
377     s = inp;
378     while((ch = *s++) != '\0') {
379         if(ch == '_') {
380             if(d >= buf + buf_size) {
381                 return NULL;                    /* cannot happen */
382             }
383             *d++ = '_';                         /* convert _ to __ to try */
384                                                 /* and ensure unique output */
385         } else if(ch == '/' || isspace(ch)) {
386             ch = '_';   /* convert "bad" to "_" */
387         }
388         if(d >= buf + buf_size) {
389             return NULL;                        /* cannot happen */
390         }
391         *d++ = ch;
392     }
393     if(d >= buf + buf_size) {
394         return NULL;                            /* cannot happen */
395     }
396     *d = '\0';
397
398     return buf;
399 }
400
401 /*
402  *=====================================================================
403  * Get the next line of input from a stdio file.
404  *
405  * char *agets (FILE *f)
406  *
407  * entry:       f = stdio stream to read
408  * exit:        returns a pointer to an alloc'd string or NULL at EOF
409  *              or error (errno will be zero on EOF).
410  *
411  * Notes:       the newline, if read, is removed from the string
412  *              the caller is responsible for free'ing the string
413  *=====================================================================
414  */
415
416 char *
417 debug_agets(s, l, file)
418     char *s;
419     int l;
420     FILE *file;
421 {
422     char *line = NULL, *line_ptr;
423     size_t line_size, size_save;
424     int line_free, line_len;
425     char *cp;
426     char *f;
427
428     malloc_enter(dbmalloc_caller_loc(s, l));
429
430 #define AGETS_LINE_INCR 128
431
432     line_size = AGETS_LINE_INCR;
433     line = debug_alloc (s, l, line_size);
434     line_free = line_size;
435     line_ptr = line;
436     line_len = 0;
437
438     while ((f = fgets(line_ptr, line_free, file)) != NULL) {
439         /*
440          * Note that we only have to search what we just read, not
441          * the whole buffer.
442          */
443         if ((cp = strchr (line_ptr, '\n')) != NULL) {
444             line_len += cp - line_ptr;
445             *cp = '\0';                         /* zap the newline */
446             break;                              /* got to end of line */
447         }
448         line_len += line_free - 1;              /* bytes read minus '\0' */
449         size_save = line_size;
450         if (line_size < 256 * AGETS_LINE_INCR) {
451             line_size *= 2;
452         } else {
453             line_size += 256 * AGETS_LINE_INCR;
454         }
455         cp = debug_alloc (s, l, line_size);     /* get more space */
456         memcpy (cp, line, size_save);           /* copy old to new */
457         free (line);                            /* and release the old */
458         line = cp;
459         line_ptr = line + size_save - 1;        /* start at the null byte */
460         line_free = line_size - line_len;       /* and we get to use it */
461     }
462     /*
463      * Return what we got even if there was not a newline.  Only
464      * report done (NULL) when no data was processed.
465      */
466     if (f == NULL && line_len == 0) {
467         amfree (line);
468         line = NULL;                            /* redundant, but clear */
469         if(!ferror(file)) {
470             errno = 0;                          /* flag EOF vs error */
471         }
472     }
473     malloc_leave(dbmalloc_caller_loc(s, l));
474     return line;
475 }
476
477 /*
478  *=====================================================================
479  * Find/create a buffer for a particular file descriptor for use with
480  * areads().
481  *
482  * void areads_getbuf (char *file, int line, int fd)
483  *
484  * entry:       file, line = caller source location
485  *              fd = file descriptor to look up
486  * exit:        returns a pointer to the buffer, possibly new
487  *=====================================================================
488  */
489
490 static struct areads_buffer {
491     char *buffer;
492     char *endptr;
493     ssize_t bufsize;
494 } *areads_buffer = NULL;
495 static int areads_bufcount = 0;
496 static ssize_t areads_bufsize = BUFSIZ;         /* for the test program */
497
498 static void
499 areads_getbuf(s, l, fd)
500     char *s;
501     int l;
502     int fd;
503 {
504     struct areads_buffer *new;
505     ssize_t size;
506
507     assert(fd >= 0);
508     if(fd >= areads_bufcount) {
509         size = (fd + 1) * sizeof(*areads_buffer);
510         new = (struct areads_buffer *) debug_alloc(s, l, size);
511         memset((char *)new, 0, size);
512         if(areads_buffer) {
513             size = areads_bufcount * sizeof(*areads_buffer);
514             memcpy(new, areads_buffer, size);
515         }
516         amfree(areads_buffer);
517         areads_buffer = new;
518         areads_bufcount = fd + 1;
519     }
520     if(areads_buffer[fd].buffer == NULL) {
521         areads_buffer[fd].bufsize = areads_bufsize;
522         areads_buffer[fd].buffer = debug_alloc(s, l,
523                                                areads_buffer[fd].bufsize + 1);
524         areads_buffer[fd].buffer[0] = '\0';
525         areads_buffer[fd].endptr = areads_buffer[fd].buffer;
526     }
527 }
528
529 /*
530  *=====================================================================
531  * Return the amount of data still in an areads buffer.
532  *
533  * ssize_t areads_dataready (int fd)
534  *
535  * entry:       fd = file descriptor to release buffer for
536  * exit:        returns number of bytes of data ready to process
537  *=====================================================================
538  */
539
540 ssize_t
541 areads_dataready(fd)
542     int fd;
543 {
544     ssize_t r = 0;
545
546     if(fd >= 0 && fd < areads_bufcount && areads_buffer[fd].buffer != NULL) {
547         r = (ssize_t) (areads_buffer[fd].endptr - areads_buffer[fd].buffer);
548     }
549     return r;
550 }
551
552 /*
553  *=====================================================================
554  * Release a buffer for a particular file descriptor used by areads().
555  *
556  * void areads_relbuf (int fd)
557  *
558  * entry:       fd = file descriptor to release buffer for
559  * exit:        none
560  *=====================================================================
561  */
562
563 void
564 areads_relbuf(fd)
565     int fd;
566 {
567     if(fd >= 0 && fd < areads_bufcount) {
568         amfree(areads_buffer[fd].buffer);
569         areads_buffer[fd].endptr = NULL;
570         areads_buffer[fd].bufsize = 0;
571     }
572 }
573
574 /*
575  *=====================================================================
576  * Get the next line of input from a file descriptor.
577  *
578  * char *areads (int fd)
579  *
580  * entry:       fd = file descriptor to read
581  * exit:        returns a pointer to an alloc'd string or NULL at EOF
582  *              or error (errno will be zero on EOF).
583  *
584  * Notes:       the newline, if read, is removed from the string
585  *              the caller is responsible for free'ing the string
586  *=====================================================================
587  */
588
589 char *
590 debug_areads (s, l, fd)
591     char *s;
592     int l;
593     int fd;
594 {
595     char *nl;
596     char *line;
597     char *buffer;
598     char *endptr;
599     char *newbuf;
600     ssize_t buflen;
601     ssize_t size;
602     ssize_t r;
603
604     malloc_enter(dbmalloc_caller_loc(s, l));
605
606     if(fd < 0) {
607         errno = EBADF;
608         return NULL;
609     }
610     areads_getbuf(s, l, fd);
611     buffer = areads_buffer[fd].buffer;
612     endptr = areads_buffer[fd].endptr;
613     buflen = areads_buffer[fd].bufsize - (endptr - buffer);
614     while((nl = strchr(buffer, '\n')) == NULL) {
615         /*
616          * No newline yet, so get more data.
617          */
618         if (buflen == 0) {
619             if ((size = areads_buffer[fd].bufsize) < 256 * areads_bufsize) {
620                 size *= 2;
621             } else {
622                 size += 256 * areads_bufsize;
623             }
624             newbuf = debug_alloc(s, l, size + 1);
625             memcpy (newbuf, buffer, areads_buffer[fd].bufsize + 1);
626             amfree(areads_buffer[fd].buffer);
627             buffer = NULL;
628             areads_buffer[fd].buffer = newbuf;
629             areads_buffer[fd].endptr = newbuf + areads_buffer[fd].bufsize;
630             areads_buffer[fd].bufsize = size;
631             buffer = areads_buffer[fd].buffer;
632             endptr = areads_buffer[fd].endptr;
633             buflen = areads_buffer[fd].bufsize - (endptr - buffer);
634         }
635         if ((r = read(fd, endptr, buflen)) <= 0) {
636             if(r == 0) {
637                 errno = 0;              /* flag EOF instead of error */
638             }
639             malloc_leave(dbmalloc_caller_loc(s, l));
640             return NULL;
641         }
642         endptr[r] = '\0';               /* we always leave room for this */
643         endptr += r;
644         buflen -= r;
645     }
646     *nl++ = '\0';
647     line = stralloc(buffer);
648     size = endptr - nl;                 /* data still left in buffer */
649     memmove(buffer, nl, size);
650     areads_buffer[fd].endptr = buffer + size;
651     areads_buffer[fd].endptr[0] = '\0';
652     malloc_leave(dbmalloc_caller_loc(s, l));
653     return line;
654 }
655
656 #ifdef TEST
657
658 int main(argc, argv)
659         int argc;
660         char **argv;
661 {
662         int rc;
663         int fd;
664         char *name;
665         char *top;
666         char *file;
667         char *line;
668
669         safe_fd(-1, 0);
670
671         set_pname("file test");
672
673         name = "/tmp/a/b/c/d/e";
674         if (argc > 2 && argv[1][0] != '\0') {
675                 name = argv[1];
676         }
677         top = "/tmp";
678         if (argc > 3 && argv[2][0] != '\0') {
679                 name = argv[2];
680         }
681         file = "/etc/hosts";
682         if (argc > 4 && argv[3][0] != '\0') {
683                 name = argv[3];
684         }
685
686         fprintf(stderr, "Create parent directories of %s ...", name);
687         rc = mkpdir(name, 02777, (uid_t)-1, (gid_t)-1);
688         if (rc == 0)
689                 fprintf(stderr, " done\n");
690         else {
691                 perror("failed");
692                 return rc;
693         }
694
695         fprintf(stderr, "Delete %s back to %s ...", name, top);
696         rc = rmpdir(name, top);
697         if (rc == 0)
698                 fprintf(stderr, " done\n");
699         else {
700                 perror("failed");
701                 return rc;
702         }
703
704         fprintf(stderr, "areads dump of %s ...", file);
705         if ((fd = open (file, 0)) < 0) {
706                 perror(file);
707                 return 1;
708         }
709         areads_bufsize = 1;                     /* force buffer overflow */
710         while ((line = areads(fd)) != NULL) {
711                 puts(line);
712                 amfree(line);
713         }
714         aclose(fd);
715         fprintf(stderr, " done.\n");
716
717         fprintf(stderr, "Finished.\n");
718         return 0;
719 }
720
721 #endif