|
|
1.1 root 1: /*
2: * uumkdir.c
3: *
4: * Makes directories for uucico to write in.
5: *
6: */
7:
8: #include <sys/stat.h>
9: #include <sys/dir.h>
10: #include <sys/ino.h>
11: #include <pwd.h>
12: #include <signal.h>
13: #include <errno.h>
14: #include "dcp.h"
15:
16: #ifndef NULL
17: #define NULL ((char*) 0)
18: #endif
19:
20: #ifndef TRUE
21: #define TRUE (0 == 0)
22: #endif
23:
24: #define MAXDIR 32
25: #define equal(s1, s2) (strcmp(s1, s2) == 0)
26:
27: /*
28: * Masks by types of permissions.
29: */
30: #define AEXEC (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6))
31: #define AREAD (S_IREAD|(S_IREAD>>3)|(S_IREAD>>6))
32: #define AWRITE (S_IWRITE|(S_IWRITE>>3)|(S_IWRITE>>6))
33: #define ASUID (S_ISUID|S_ISGID)
34: #define ATEXT S_ISVTX
35:
36: /*
37: * Masks by types of users.
38: */
39: #define AOWN (S_ISUID|S_ISVTX|S_IREAD|S_IWRITE|S_IEXEC)
40: #define AGRP (S_ISGID|S_ISVTX|(S_IREAD>>3)|(S_IWRITE>>3)|(S_IEXEC>>3))
41: #define AOTH (S_ISVTX|(S_IREAD>>6)|(S_IWRITE>>6)|(S_IEXEC>>6))
42: #define AALL (AOWN|AGRP|AOTH)
43:
44: typedef
45: struct inpdir_s {
46: char * dir; /* dir string entered */
47: char * start; /* start of new dir in string */
48: char * end; /* end of dir string */
49: char * p; /* end of current parent string */
50: char * c; /* end of current child string */
51: } inpdir_t;
52:
53: char usage[] = "Usage: uumkdir [ -m mode ] [ -p ] dir ...\n";
54: char badsm[] = "uumkdir: badly formed symbolic mode\n";
55: char badom[] = "uumkdir: badly formed octal mode\n";
56:
57: long int new; /* bit-wise child dir condition */
58: short uid; /* user ID */
59: int interrupted; /* interrupt flag */
60: int endflag; /* end od dir string flag */
61: int pflag; /* p option flag */
62: int mflag; /* m option flag */
63: int mode = 0755; /* initial mode setup for m option */
64:
65: extern char *malloc();
66: extern char *strcpy();
67: extern char *strncpy();
68: extern char *strcat();
69:
70: /*
71: * Interrupts are handled to prevent the formation of mangled directories.
72: */
73:
74: main(argc, argv)
75: int argc;
76: register char ** argv;
77:
78: {
79: register int status = 0; /* condition of mkdir:
80: 0 - success, 1 - error */
81: inpdir_t dirs; /* structure with dir string info */
82: char * end; /* pointer to end of dir string */
83:
84: extern void fatal();
85: extern int catch();
86: extern int readmode();
87: extern int mkpath();
88: extern int error();
89:
90: if ( (setuid(0) < 0) || (setgid(0) < 0) )
91: fatal("uumkdir must be executed setuid root\n");
92:
93: catch(SIGINT);
94: catch(SIGHUP);
95: signal(SIGQUIT, SIG_IGN);
96:
97: while((--argc > 0) && ((*++argv)[0] == '-')) {
98: switch((*argv)[1]) {
99: case 'p':
100: if (pflag)
101: fatal(usage);
102: pflag = TRUE;
103: break;
104: case 'm':
105: if (mflag || (--argc <= 0))
106: fatal(usage);
107: uid = getuid();
108: mflag = TRUE;
109: mode = readmode(*++argv, mode);
110: break;
111: case 'v':
112: case 'V':
113: fatal("uumkdir: Version %s", VERSION);
114: default:
115: fatal(usage);
116: }
117: }
118: if (argc <= 0)
119: fatal(usage);
120: else {
121: for(; *argv ; ++argv) {
122: if (dirs.dir)
123: free(dirs.dir);
124: for(end = *argv ; *end != '\0' ; ++end)
125: ;
126: do {
127: if (end == *argv) {
128: error("bad argument (empty string)", 0);
129: exit(1);
130: }
131: } while(*--end == '/');
132: *++end = '\0';
133: if ((dirs.dir = malloc(end - *argv + 1)) == NULL) {
134: error("out of memory ", 0);
135: exit(1);
136: }
137: strcpy(dirs.dir, *argv);
138: dirs.end = dirs.dir + (end - *argv);
139: if (mkpath(&dirs) < 0)
140: status = 1; /* error */
141: if (interrupted)
142: exit(1);
143: }
144: }
145: exit(status);
146: }
147:
148: /**
149: * int
150: * mkpath(pdir)
151: * inpdir_t * pdir;
152: *
153: * Input: pdir - pointer to structure.
154: *
155: * Action: Create new directory and all necessary directories
156: * to new directory.
157: *
158: * Return: 0 if all directory creations are successful, else -1.
159: *
160: * Note: All directories created before an error is
161: * encountered are not removed from user's file.
162: */
163:
164: int
165: mkpath(pdir)
166: inpdir_t * pdir;
167: {
168: register char * childnam; /* dir name of child */
169: register char * child; /* path name of child */
170: register char * parent; /* path name of parent */
171: register int n;
172: int err; /* error response from dir creation */
173: int numdir; /* number of directories minus first
174: parent specified in full path name */
175: extern char * getparent();
176: extern char * getchild();
177: extern char * getpath();
178: extern int mkdir();
179: extern int setmod();
180: extern int error();
181:
182: numdir = 0;
183: new = 0L;
184: endflag = !TRUE;
185:
186: if ((child = malloc(pdir->end - pdir->dir + 1)) == NULL)
187: return(error("out of memory ", 0));
188: parent = getparent(pdir);
189: n = pdir->start - pdir->dir;
190: strncpy(child, pdir->dir, n);
191: child[n] = '\0';
192: do {
193: ++numdir;
194: if ((int)(childnam = getchild(pdir)) < 0) {
195: error("can't get dir name ", pdir->dir, 0);
196: break;
197: }
198: child = getpath(pdir, child);
199: if (pdir->c == pdir->end) {
200: /* Last child declared cannot be "." or "..". */
201: if (equal(childnam, ".") || equal(childnam, "..")) {
202: error(pdir->dir," not allowed", 0);
203: break;
204: }
205: /* Signal end of dir string. */
206: endflag = TRUE;
207: if (mkdir(parent, child) == -1)
208: break;
209: /* Signal new dir. */
210: new = (new << 1) | 1L;
211: numdir += MAXDIR;
212: } else {
213: new = (new << 1) | 0L;
214: if (!equal(childnam, ".") && !equal(childnam, "..")) {
215: if ((err = mkdir(parent, child)) == -1)
216: break;
217: else if (err == 0)
218: new |= 1L;
219: }
220: }
221: /* Get next parent. */
222: parent = getpath(pdir, parent);
223: pdir->p = pdir->c;
224: } while(numdir <= MAXDIR);
225: /* Set user-selected mode if available. */
226: if (mflag) {
227: if (setmod(parent, numdir, pdir->start, (pdir->p - 1)) < 0)
228: return(-1);
229: }
230: if (numdir > MAXDIR)
231: return(0);
232: else
233: return(-1);
234: }
235:
236: /**
237: * int
238: * setmod(ch, ndir, start, p)
239: * char * ch;
240: * char * start;
241: * char * p;
242: * int ndir;
243: *
244: * Input: ch - string holding all new dir names.
245: * start - start of new dir.
246: * p - end of new dir.
247: * ndir - number of directories tested.
248: *
249: * Action: Set mode of all new directories created.
250: *
251: * Return: 0 if all mode setups are successful, else -1.
252: *
253: * Note: None.
254: */
255:
256: int
257: setmod(ch, ndir, start, p)
258: char * ch;
259: char * start;
260: char * p;
261: int ndir;
262: {
263: char * c; /* pointer to end of dir string */
264: /* Get pointer to end of string. */
265: for(c = ch ; *c != '\0' ; ++c)
266: ;
267: if (ndir > MAXDIR)
268: ndir -= (MAXDIR - 1);
269: /* Reset to mode desired. */
270: while(--ndir > 0) {
271: /* Change dir mode if new directory. */
272: if ((new & 01L) == 1L)
273: if (chmod(ch, mode) < 0) {
274: write(2, ch, (c - ch));
275: write(2, ": ", 2);
276: write(2, sys_errlist[ errno ],
277: strlen(sys_errlist[ errno ]));
278: write(2, "\n", 1);
279: return(-1);
280: }
281: new = new >> 1;
282: /* Remove current dir name from string. */
283: for(++p ; (--p >= start) && (*p != '/') ; *--c = '\0')
284: ;
285: /* Remove trailing slashes. */
286: for(++p ; (--p >= start) && (*p == '/') ; *--c = '\0')
287: ;
288: }
289: return(0);
290: }
291:
292: /**
293: * char *
294: * getparent(pdir)
295: * inpdir_t * pdir;
296: *
297: * Input: pdir - pointer to structure.
298: *
299: * Action: Get parent to directory currently working on.
300: *
301: * Return: Pointer to parent string.
302: *
303: * Note: None.
304: */
305:
306: char *
307: getparent(pdir)
308: inpdir_t * pdir;
309: {
310: int found; /* 0: parent found, -1: parent not found */
311: int size; /* size of dir string in structure */
312: char * par; /* pointer to parent string */
313: char * tail; /* pointer to end of parent string */
314: extern int error();
315:
316: size = pdir->end - pdir->dir;
317: if ((par = malloc(size + 3)) == NULL) {
318: error("out of memory ", 0);
319: exit(1);
320: }
321: /* Copy structure string to parent and set tail to end of
322: * parent string.
323: */
324: strcpy(par, pdir->dir);
325: tail = par + size;
326: /* Search for parent string. */
327: do {
328: /* Remove last dir name in string. */
329: for(; (--tail >= par) && (*tail != '/') ; *tail = '\0')
330: ;
331: /* Remove trailing slashes. */
332: for(++tail ; (--tail > par) && (*tail == '/') ; *tail = '\0')
333: ;
334: /** Substitute "." for null path. */
335: if (++tail == par) {
336: *tail = '.';
337: *(tail + 1) = '/';
338: }
339: if ((found = access(par, 03)) == -1)
340: switch(errno) {
341: case ENOENT:
342: break;
343: case EACCES:
344: error("no permission to mkdir in ", par, 0);
345: exit(1);
346: default:
347: error("can't make ", pdir->dir, 0);
348: exit(1);
349: }
350: } while((found == -1) && pflag);
351: /* Set start of first child and pointer to end of first parent. */
352: pdir->start = pdir->p = pdir->dir + (tail - par);
353: return(par);
354: }
355:
356: /**
357: * char *
358: * getchild(pdir)
359: * inpdir_t * pdir;
360: *
361: * Input: pdir - pointer to structure.
362: *
363: * Action: Get current child dir name.
364: *
365: * Return: Pointer to child dir name.
366: *
367: * Note: If dir name found exceeds DIRSIZ in length, it will be
368: * truncated to DIRSIZ.
369: */
370:
371: char *
372: getchild(pdir)
373: inpdir_t * pdir;
374: {
375: static char nam[ DIRSIZ + 1 ]; /* dir name of child */
376: char * c; /* pointer to end of child name */
377: int i, j; /* working counters */
378: /* Increment to start of next dir name. */
379: for(i = 0, c = pdir->p ; (c < pdir->end) && (*c == '/') ; ++i, ++c)
380: ;
381: /* Increment to end of dir name. */
382: for(j = 0 ; (c < pdir->end) && (*c != '/') ; ++j, ++c)
383: ;
384: pdir->c = c;
385: /* Copy up to DIRSIZ length of child dir name to static memory. */
386: if (j > DIRSIZ)
387: j = DIRSIZ;
388: strncpy(nam, pdir->p + i, j);
389: nam[j] = '\0';
390: return(nam);
391: }
392:
393: /**
394: * char *
395: * getpath(pdir, dir)
396: * inpdir_t * pdir;
397: * char * dir;
398: *
399: * Input: pdir - pointer to structure.
400: * dir - current path name.
401: * Action: Get current path name of child.
402: * Return: Pointer to current path name.
403: * Note: None.
404: */
405:
406: char *
407: getpath(pdir, dir)
408: inpdir_t * pdir;
409: char * dir;
410: {
411: strncat(dir, pdir->p, (pdir->c - pdir->p));
412: return(strcat(dir, "\0"));
413: }
414:
415: /**
416: * int
417: * mkdir(parent, child)
418: * char * parent;
419: * char * child;
420: *
421: * Input: parent - pointer to dir path name to parent.
422: * child - pointer to dir path name to child.
423: * Action: Make a directory. If the parent exists and is writeable,
424: * the directory and its "." and ".." links are created.
425: * Return: 0 if successful, 1 if dir existed already and dir is
426: * not the last dir in string. Else -1.
427: * Note: None.
428: */
429:
430: int
431: mkdir(parent, child)
432: char * parent;
433: char * child;
434: {
435: extern char * concat();
436: extern int linkerr();
437: extern int error();
438: struct passwd *pw;
439:
440: /* Test if parent file is accessible by user. */
441: if (access(parent, 03))
442: switch(errno) {
443: case ENOENT:
444: error("parent dir ", parent, " doesn't exist", 0);
445: return(-1);
446: case EACCES:
447: error("no permission to mkdir in ", parent, 0);
448: return(-1);
449: default:
450: return(error("can't make ", child, 0));
451: }
452: /* Creat new directory. */
453: if (mknod(child, IFDIR | 0777, 0)) {
454: switch(errno) {
455: case EEXIST:
456: if (endflag)
457: return(error(child, " already exists", 0));
458: else
459: return(1);
460: case EPERM:
461: return(error("not the super-user", 0));
462: default:
463: return(error("can't make ", child, 0));
464: }
465: }
466: if (link(child, concat(child, "/.")))
467: return(linkerr(child, "."));
468: if (link(parent, concat(child, "/..")))
469: return(linkerr(child, ".."));
470: /* Set ownership of directory to user. */
471: if ((pw = getpwnam("uucp")) == NULL)
472: return -1;
473: if (chown(child, pw->pw_uid, pw->pw_gid) < 0)
474: return -1;
475: return(0);
476: }
477:
478: /**
479: * char *
480: * concat(s1, s2)
481: * char * s1, * s2;
482: * Input: s1, s2 - strings to be concatenated.
483: * Action: Join string s2 to string s1 to form a new string.
484: * Return: Pointer to start of concatenation of `s1' and `s2'.
485: * Note: None.
486: */
487:
488: char *
489: concat(s1, s2)
490: char * s1;
491: char * s2;
492: {
493: static char * str;
494: if (str)
495: free(str);
496: /* Allocate memory space for concatenated string. */
497: if ((str = malloc(strlen(s1) + strlen(s2) + 1)) == NULL) {
498: error("out of memory", 0);
499: exit(1);
500: }
501: strcpy(str, s1);
502: return(strcat(str, s2));
503: }
504:
505: /**
506: * int
507: * linkerr(dir, name)
508: * char * dir;
509: * char * name;
510: *
511: * input: dir - directory where linking failed.
512: * name - type of link failed, "." or "..".
513: * Action: Recover from link failure. In the event that "." or ".."
514: * cannot be created, remove all traces of the directory.
515: * return: -1.
516: * Note: none.
517: */
518:
519: int
520: linkerr(dir, name)
521: char * dir;
522: char * name;
523: {
524: extern char * concat();
525: extern int error();
526:
527: unlink(concat(dir, "/."));
528: unlink(concat(dir, "/.."));
529: unlink(dir);
530: return(error("link to '", name, "' failed", 0));
531: }
532:
533: /**
534: * int
535: * onintr()
536: *
537: * Input: None.
538: * Action: Reset SIGINT and SIGHUP and set interrupt counter.
539: * Return: Pointer to previous action on success, else -1.
540: * Note: None.
541: */
542:
543: int
544: onintr()
545: {
546: signal(SIGINT, SIG_IGN);
547: signal(SIGHUP, SIG_IGN);
548: ++interrupted;
549: }
550:
551: /**
552: * int
553: * catch(sig)
554: *
555: * Input: sig - signal caught.
556: * Action: Reset signals.
557: * Return: Pointer to previous action on success, else -1.
558: * Note: None.
559: */
560:
561: int
562: catch(sig)
563: {
564: extern int onintr();
565: if (signal(sig, SIG_IGN) == SIG_DFL)
566: signal(sig, onintr);
567: }
568:
569: /**
570: * int
571: * error(arg1)
572: * char * arg1;
573: *
574: * Input: arg1 - error message string.
575: * Action: Display error message.
576: * Return: -1.
577: * Note: None.
578: */
579:
580: int
581: error(arg1)
582: char * arg1;
583: {
584: register char ** p;
585: write(2, "mkdir: ", 7);
586: for(p = &arg1 ; *p != 0 ; ++p)
587: write(2, *p, strlen(*p));
588: write(2, "\n", 1);
589: return(-1);
590: }
591:
592: /**
593: * int
594: * readmode(s, mode)
595: * char * s;
596: * int mode;
597: *
598: * Input: s - string containing setting changes.
599: * mode - current setting of permission.
600: * Action: Read in the symbolic mode and set the variables `who', `op',
601: * and `mode'. Knows about the old octal modes as well.
602: * Return: New mode.
603: * Note: None.
604: */
605:
606: int
607: readmode(s, mode)
608: register char * s;
609: int mode;
610: {
611: register int c;
612: register int op;
613: register int m1, m2;
614: extern void fatal();
615: extern void checkmode();
616: extern int getumask();
617: extern int mrepl();
618:
619: if ((*s >= '0') && (*s <= '7')) {
620: mode = 0;
621: while(*s != '\0') {
622: if ((*s < '0') || (*s > '7'))
623: fatal(badom);
624: mode = (mode << 3) | (*s++)-'0';
625: }
626: checkmode(mode);
627: return(mode);
628: }
629: newsym:
630: for(m1 = 0 ;;) {
631: switch(*s++) {
632: case 'u': m1 |= AOWN; continue;
633: case 'g': m1 |= AGRP; continue;
634: case 'o': m1 |= AOTH; continue;
635: case 'a': m1 |= AALL; continue;
636: default : s--; break;
637: }
638: break;
639: }
640: if (m1 == 0)
641: m1 = AALL & ~getumask();
642: newop:
643: if (((c = *s++) == '=') || (c == '+') || (c == '-'))
644: op = c;
645: else
646: fatal(badsm);
647: for(m2 = 0 ;;) {
648: switch(*s++) {
649: case 'r': m2 |= AREAD; continue;
650: case 'w': m2 |= AWRITE; continue;
651: case 'x': m2 |= AEXEC; continue;
652: case 's': m2 |= ASUID; continue;
653: case 't': m2 |= ATEXT; continue;
654: case 'u': m2 |= mrepl(mode & AOWN); continue;
655: case 'g': m2 |= mrepl((mode & AGRP) << 3); continue;
656: case 'o': m2 |= mrepl((mode & AOTH) << 6); continue;
657: default : s--; break;
658: }
659: break;
660: }
661: switch(op) {
662: case '-': mode &= ~(m1 & m2); break;
663: case '+': mode |= m1 & m2; break;
664: case '=': mode = (mode & ~m1) | (m1 & m2); break;
665: }
666: if (*s == '\0') {
667: checkmode(mode);
668: return(mode);
669: }
670: if ((*s == '+') || (*s == '-') || (*s == '='))
671: goto newop;
672: if (*s++ == ',')
673: goto newsym;
674: fatal(badsm);
675: }
676:
677: /**
678: * int
679: * getumask()
680: *
681: * Input: None.
682: *
683: * Action: Get the value of the umask setting.
684: *
685: * Return: ????
686: *
687: * Note: None.
688: */
689:
690: int
691: getumask()
692:
693: {
694: register int omask;
695:
696: omask = umask(0);
697: umask(omask);
698: return(omask);
699: }
700:
701: /**
702: * void
703: * checkmode(mode)
704: * int mode;
705: *
706: * Input: mode - current setup of permission.
707: * Action: Check the mode to see if any problem bits are on.
708: * For now, this is S_ISVTX for non-super-users.
709: * Return: None.
710: * Note: None.
711: */
712:
713: void
714: checkmode(mode)
715: register int mode;
716: {
717: static char stickwarn[] =
718: "mkdir: Warning: non-super user may not set sticky bit\n";
719: if ((uid != 0) && (mode & S_ISVTX)) {
720: write(2, stickwarn, 54);
721: exit(1);
722: }
723: }
724:
725: /**
726: * int
727: * mrepl(m)
728: * int m;
729: * Input: m - mode setting to be replicated.
730: * Action: Replicate the 3-bits of the mode from the owner
731: * position to all positions.
732: * Return: Replicated mode setup.
733: * Note: None.
734: */
735:
736: int
737: mrepl(m)
738: register int m;
739: {
740: register int m1;
741:
742: m1 = m & AOWN;
743: m = m1 | (m1 >> 3) | (m1 >> 6);
744: if (m1 & S_ISUID)
745: m |= S_ISGID;
746: return(m);
747: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.