Fixed multiple bugs in makedir(). First off, when creating nested folders, it
[mmh] / sbr / makedir.c
1
2 /*
3  * makedir.c -- make a directory
4  *
5  * $Id$
6  */
7
8 /*
9  * Modified to try recursive create.
10  */
11
12 #include <h/mh.h>
13 #include <errno.h>
14 #include <sys/param.h>
15 #include <sys/file.h>
16
17 extern int errno;
18         
19 int
20 makedir (char *dir)
21 {
22     char            path[PATH_MAX];
23     char*           folder_perms_ASCII;
24     int             had_an_error = 0;
25     mode_t          folder_perms, saved_umask;
26     pid_t           pid;
27     register char*  c;
28
29     context_save();     /* save the context file */
30     fflush(stdout);
31
32     if (!(folder_perms_ASCII = context_find ("folder-protect")))
33         folder_perms_ASCII = foldprot;  /* defaults to "0700" */
34     
35     /* Call strtoul() with radix=0, which means it'll determine the base by
36        looking at the first digit.  That way it'll know "0700" is an octal
37        constant (and if someone gets wacky and changes the representation to hex
38        it'll still work). */
39     folder_perms = strtoul(folder_perms_ASCII, NULL, 0);
40
41     /* Folders have definite desired permissions that are set -- we don't want
42        to interact with the umask.  Clear it temporarily. */
43     saved_umask = umask(0);
44
45     if (getuid () == geteuid ()) {
46         c = strncpy(path, dir, sizeof(path));     
47         
48         while (!had_an_error && (c = strchr((c + 1), '/')) != NULL) {   
49             *c = (char)0;
50             if (access(path, X_OK)) {
51                 if (errno != ENOENT){
52                     advise (dir, "unable to create directory");
53                     had_an_error = 1;
54                 }
55                 /* Create an outer directory. */
56                 if (mkdir(path, folder_perms)) {
57                     advise (dir, "unable to create directory");
58                     had_an_error = 1;
59                 }
60             }
61             *c = '/';
62         }
63
64         if (!had_an_error) {
65             /* Create the innermost nested subdirectory of the path we're being
66                asked to create. */
67             if (mkdir (dir, folder_perms) == -1) {
68                 advise (dir, "unable to create directory");
69                 had_an_error = 1;
70             }
71         }
72     }
73     else {
74         /* Ummm, why do we want to avoid creating directories with the effective
75            user ID?  None of the nmh tools are installed such that the effective
76            should be different from the real, and if some parent process made
77            the two be different, I don't see why it should be our job to enforce
78            the real UID.  Also, why the heck do we call the mkdir executable
79            rather than the library function in this case??  If we do want to
80            call the mkdir executable, we should at least be giving it -p (and
81            change the single chmod() call below) so it can successfully create
82            nested directories like the above code can.
83
84            -- Dan Harkless <dan-nmh@dilvish.speed.net> */
85         switch (pid = vfork()) {
86             case -1: 
87                 advise ("fork", "unable to");
88                 return 0;
89                 
90             case 0: 
91                 setgid (getgid ());
92                 setuid (getuid ());
93                 
94                 execl ("/bin/mkdir", "mkdir", dir, NULL);
95                 execl ("/usr/bin/mkdir", "mkdir", dir, NULL);
96                 fprintf (stderr, "unable to exec ");
97                 perror ("mkdir");
98                 _exit (-1);
99                 
100             default: 
101                 if (pidXwait(pid, "mkdir"))
102                     return 0;
103                 break;
104         }
105
106         chmod (dir, folder_perms);
107     }
108
109     umask(saved_umask);  /* put the user's umask back */
110
111     if (had_an_error)
112         return 0;  /* opposite of UNIX error return convention */
113     else
114         return 1;
115 }