When I fixed the long-standing makedir() bugs in January, I had the code call
[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 "700" */
34     
35     /* Because mh-profile.man documents "Folder-Protect:" as an octal constant,
36        and we don't want to force the user to remember to include a leading
37        zero, we call atooi(folder_perms_ASCII) here rather than
38        strtoul(folder_perms_ASCII, NULL, 0).  Therefore, if anyone ever tries to
39        specify a mode in say, hex, they'll get garbage.  (I guess nmh uses its
40        atooi() function rather than calling strtoul() with a radix of 8 because
41        some ancient platforms are missing that functionality. */
42     folder_perms = atooi(folder_perms_ASCII);
43
44     /* Folders have definite desired permissions that are set -- we don't want
45        to interact with the umask.  Clear it temporarily. */
46     saved_umask = umask(0);
47
48     if (getuid () == geteuid ()) {
49         c = strncpy(path, dir, sizeof(path));     
50         
51         while (!had_an_error && (c = strchr((c + 1), '/')) != NULL) {   
52             *c = (char)0;
53             if (access(path, X_OK)) {
54                 if (errno != ENOENT){
55                     advise (dir, "unable to create directory");
56                     had_an_error = 1;
57                 }
58                 /* Create an outer directory. */
59                 if (mkdir(path, folder_perms)) {
60                     advise (dir, "unable to create directory");
61                     had_an_error = 1;
62                 }
63             }
64             *c = '/';
65         }
66
67         if (!had_an_error) {
68             /* Create the innermost nested subdirectory of the path we're being
69                asked to create. */
70             if (mkdir (dir, folder_perms) == -1) {
71                 advise (dir, "unable to create directory");
72                 had_an_error = 1;
73             }
74         }
75     }
76     else {
77         /* Ummm, why do we want to avoid creating directories with the effective
78            user ID?  None of the nmh tools are installed such that the effective
79            should be different from the real, and if some parent process made
80            the two be different, I don't see why it should be our job to enforce
81            the real UID.  Also, why the heck do we call the mkdir executable
82            rather than the library function in this case??  If we do want to
83            call the mkdir executable, we should at least be giving it -p (and
84            change the single chmod() call below) so it can successfully create
85            nested directories like the above code can.
86
87            -- Dan Harkless <dan-nmh@dilvish.speed.net> */
88         switch (pid = vfork()) {
89             case -1: 
90                 advise ("fork", "unable to");
91                 return 0;
92                 
93             case 0: 
94                 setgid (getgid ());
95                 setuid (getuid ());
96                 
97                 execl ("/bin/mkdir", "mkdir", dir, NULL);
98                 execl ("/usr/bin/mkdir", "mkdir", dir, NULL);
99                 fprintf (stderr, "unable to exec ");
100                 perror ("mkdir");
101                 _exit (-1);
102                 
103             default: 
104                 if (pidXwait(pid, "mkdir"))
105                     return 0;
106                 break;
107         }
108
109         chmod (dir, folder_perms);
110     }
111
112     umask(saved_umask);  /* put the user's umask back */
113
114     if (had_an_error)
115         return 0;  /* opposite of UNIX error return convention */
116     else
117         return 1;
118 }