|
|
1.1 root 1: /* idistd2.c -- the non remote operations parts of the protocol */
2:
3: /*
4: * $Header: /f/osi/others/idist/RCS/idistd2.c,v 7.0 89/11/23 21:58:33 mrose Rel $
5: *
6: * Parts of the idist server which are not mixed up with remote
7: * operations but depend on the defined types.
8: *
9: * Julian Onions <[email protected]>
10: * Nottingham University Computer Science.
11: *
12: *
13: * $Log: idistd2.c,v $
14: * Revision 7.0 89/11/23 21:58:33 mrose
15: * Release 6.0
16: *
17: */
18:
19: #ifndef lint
20: static char *rcsid = "$Header: /f/osi/others/idist/RCS/idistd2.c,v 7.0 89/11/23 21:58:33 mrose Rel $";
21: #endif
22:
23: #include "defs.h"
24: #include "Idist-types.h"
25:
26: char *tp, *stp[128];
27:
28: extern int catname;
29: extern char target[];
30: extern FILE *cfile;
31: extern struct type_Idist_FileSpec *cfiletype;
32: extern int oumask;
33: extern char utmpfile[];
34: extern char *tmpname;
35: extern struct type_Idist_IA5List *ia5list;
36:
37: static char *cannon ();
38: static struct type_Idist_IA5List *str2ia5list ();
39: static int compare ();
40: extern struct type_Idist_FileSpec *makefs ();
41: extern struct type_Idist_QueryResult *query ();
42: extern struct type_Idist_FileList *do_listcdir ();
43:
44: doexec (cmd)
45: char *cmd;
46: {
47: int fd[2], status, pid, i;
48: char buf[BUFSIZ];
49:
50: if (pipe(fd) < 0)
51: return NOTOK;
52:
53: if ((pid = vfork ()) == 0) {
54: /*
55: * Return everything the shell commands print.
56: */
57: (void) close(0);
58: (void) close(1);
59: (void) close(2);
60: (void) open("/dev/null", 0);
61: (void) dup(fd[1]);
62: (void) dup(fd[1]);
63: (void) close(fd[0]);
64: (void) close(fd[1]);
65: execl("/bin/sh", "sh", "-c", cmd, 0);
66: _exit(127);
67: }
68: if (pid == -1)
69: return NOTOK;
70:
71: (void) close(fd[1]);
72:
73: while ((i = read(fd[0], buf, sizeof(buf))) > 0) {
74: addtoia5 (buf, i);
75: }
76:
77: while ((i = wait(&status)) != pid && i != -1)
78: ;
79: if (i == -1)
80: status = -1;
81: (void) close(fd[0]);
82:
83: return OK;
84: }
85:
86: do_symlink (fs)
87: struct type_Idist_FileSpec *fs;
88: {
89: char *new, old[BUFSIZ], *linkname;
90: int i;
91:
92: new = qb2str (fs -> filename);
93: linkname = cannon (new);
94: free (new);
95:
96: new = qb2str (fs -> linkname);
97: (void) strcpy (old, new);
98: free (new);
99:
100:
101: if (symlink (old, linkname) < 0) {
102: if (errno != ENOENT || chkparent (linkname) < 0 ||
103: symlink (old, linkname) < 0) {
104: nadvise (linkname, "Can't symlink %s to", old);
105: return NOTOK;
106: }
107: }
108:
109: if (bit_on (fs -> fileopts, bit_Idist_Options_compare)) {
110: char tbuf[BUFSIZ];
111:
112: if ((i = readlink (target, tbuf, BUFSIZ)) >= 0 &&
113: i == fs -> filesize &&
114: strncmp (old, tbuf, fs -> filesize) == 0) {
115: (void) unlink (linkname);
116: return OK;
117: }
118: if (bit_on (fs -> fileopts, bit_Idist_Options_verify)) {
119: (void) unlink (linkname);
120: note ("need to update: %s", target);
121: return OK;
122: }
123: }
124:
125: if (rename (linkname, target) < 0) {
126: nadvise (target, "can't rename %s to", linkname);
127: (void) unlink (linkname);
128: return NOTOK;
129: }
130: if (bit_on (fs -> fileopts, bit_Idist_Options_compare))
131: note ("updated %s\n", target);
132: return OK;
133: }
134:
135: static char *cannon (name)
136: char *name;
137: {
138: static char nname[BUFSIZ];
139: char *cp;
140: extern char *tmpname;
141:
142: if (catname)
143: (void) sprintf (tp, "/%s", name);
144: if((cp = rindex (target, '/')) == NULL)
145: (void) strcpy (nname, tmpname);
146: else if (cp == target)
147: (void) sprintf (nname, "/%s", tmpname);
148: else {
149: *cp = '\0';
150: (void) sprintf (nname, "%s/%s", target, tmpname);
151: *cp = '/';
152: }
153: return nname;
154: }
155:
156: /*
157: * Check to see if parent directory exists and create one if not.
158: */
159: chkparent(name)
160: char *name;
161: {
162: register char *cp;
163: struct stat stb;
164:
165: cp = rindex(name, '/');
166: if (cp == NULL || cp == name)
167: return(0);
168: *cp = '\0';
169: if (lstat(name, &stb) < 0) {
170: if (errno == ENOENT && chkparent(name) >= 0 &&
171: mkdir(name, 0777 & ~oumask) >= 0) {
172: *cp = '/';
173: return(0);
174: }
175: } else if (ISDIR(stb.st_mode)) {
176: *cp = '/';
177: return(0);
178: }
179: *cp = '/';
180: return(-1);
181: }
182:
183: do_rfile (fs)
184: struct type_Idist_FileSpec *fs;
185: {
186: char *name, *p;
187:
188: p = qb2str (fs -> filename);
189: name = cannon (p);
190: free (p);
191:
192: if ((cfile = fopen (name, "w")) == NULL) {
193: if (errno != ENOENT || chkparent (name) < 0 ||
194: (cfile = fopen (name, "w")) == NULL) {
195: nadvise (name, "Can't create file");
196: return NOTOK;
197: }
198: }
199: (void) fchmod (fileno (cfile), fs -> filemode);
200:
201: return OK;
202: }
203:
204: do_hardlink (fs)
205: struct type_Idist_FileSpec *fs;
206: {
207: char *new;
208: char *cp;
209: char old[BUFSIZ];
210: struct stat stb;
211: int exists = 0;
212:
213: new = qb2str (fs -> filename);
214: cp = qb2str (fs -> linkname);
215: if (exptilde (old, cp) == NULL) {
216: free (cp);
217: free (new);
218: return NOTOK;
219: }
220: free (cp);
221:
222: if (catname)
223: (void) sprintf (tp, "/%s", new);
224: free (new);
225:
226: if (lstat(target, &stb) == 0) {
227: int mode = stb.st_mode & S_IFMT;
228: if (mode != S_IFREG && mode != S_IFLNK) {
229: nadvise (NULLCP, "%s: not a regular file",
230: host, target);
231: return NOTOK;
232: }
233: exists = 1;
234: }
235: if (chkparent(target) < 0 ) {
236: nadvise("chkparent", "%s (no parent)", target);
237: return NOTOK;
238: }
239: if (exists && (unlink(target) < 0)) {
240: nadvise ("unlink", "%s", target);
241: return NOTOK;
242: }
243: if (link(old, target) < 0) {
244: nadvise (old, "can't link %s to", target);
245: return NOTOK;
246: }
247: return OK;
248: }
249:
250: do_direct (fs)
251: struct type_Idist_FileSpec *fs;
252: {
253: char *cp, *name;
254: struct stat stb;
255:
256: cp = name = qb2str (fs -> filename);
257:
258: if (catname >= sizeof(stp)) {
259: nadvise (NULLCP, "Too many directory levels");
260: free (name);
261: return NOTOK;
262: }
263:
264: stp[catname] = tp;
265: if (catname++) {
266: *tp ++ = '/';
267: while (*tp++ = *cp ++)
268: ;
269: tp --;
270: }
271:
272: if (bit_on (fs -> fileopts, bit_Idist_Options_verify)) {
273: free (name);
274: return OK;
275: }
276:
277: if (lstat (target, &stb) == 0) {
278: if ((stb.st_mode & S_IFMT) == S_IFDIR) {
279: if ((stb.st_mode & 07777) == fs -> filemode) {
280: free (name);
281: return OK;
282: }
283: note ("%s remote node %o != local mode %o",
284: target, stb.st_mode & 07777, fs -> filemode);
285: free (name);
286: return OK;
287: }
288: errno = ENOTDIR;
289: }
290: else if (errno == ENOENT && (mkdir (target, fs -> filemode) == 0 ||
291: chkparent (target) == 0 &&
292: mkdir (target, fs -> filemode) == 0)) {
293: char *owner = qb2str (fs -> fileowner);
294: char *group = qb2str (fs -> filegroup);
295:
296: if (chog (target, owner, group, fs -> filemode) == 0) {
297: free (owner);
298: free (group);
299: free (name);
300: return OK;
301: }
302: free (owner);
303: free (group);
304: }
305: free (name);
306: nadvise (target, "Can't install directory");
307: tp = stp[--catname];
308: *tp = '\0';
309: return NOTOK;
310: }
311:
312: /*
313: * Remove a file or directory (recursively) and send back an acknowledge
314: * or an error message.
315: */
316: remove(str)
317: char *str;
318: {
319: DIR *d;
320: struct direct *dp;
321: struct stat stb;
322: char buf[BUFSIZ];
323: int result = OK;
324:
325: if (lstat (str, &stb) < 0) {
326: nadvise (str, "Can't stat file");
327: return NOTOK;
328: }
329:
330: switch (stb.st_mode & S_IFMT) {
331: case S_IFREG:
332: case S_IFLNK:
333: if (unlink(str) < 0) {
334: nadvise (str, "Can't unlink");
335: return NOTOK;
336: }
337: note ("removed: %s", str);
338: return OK;
339:
340: case S_IFDIR:
341: break;
342:
343: default:
344: nadvise (NULLCP, "%s: not a plain file", target);
345: return NOTOK;
346: }
347:
348: if ((d = opendir(str)) == NULL) {
349: nadvise (str, "Can't open directory");
350: return NOTOK;
351: }
352:
353: while (dp = readdir(d)) {
354: if (strcmp(dp->d_name, ".") == 0 ||
355: strcmp(dp->d_name, "..") == 0)
356: continue;
357: (void) sprintf (buf, "%s/%s", str, dp -> d_name);
358: result = remove(buf) == OK ? result : NOTOK;
359: }
360: closedir(d);
361: if (rmdir(str) < 0) {
362: nadvise (str, "Can't remove directory", str);
363: return NOTOK;
364: }
365: note ("removed: %s", str);
366: return result;
367: }
368:
369:
370: addtoia5 (str, len)
371: char *str;
372: int len;
373: {
374: struct type_Idist_IA5List **ia5p;
375:
376: for (ia5p = &ia5list; *ia5p; ia5p = &(*ia5p) -> next)
377: continue;
378:
379: *ia5p = str2ia5list (str, len);
380: }
381:
382: struct type_Idist_QueryResult *query (str)
383: char *str;
384: {
385: struct type_Idist_QueryResult *qr;
386: struct stat stb;
387:
388: qr = (struct type_Idist_QueryResult *) malloc (sizeof *qr);
389: if (qr == NULL)
390: adios ("memory", "out of");
391:
392: if (catname)
393: (void) sprintf (tp, "/%s", str);
394:
395: if (lstat (target, &stb) < 0) {
396: if (errno == ENOENT) {
397: qr -> offset = type_Idist_QueryResult_doesntExist;
398: }
399: else {
400: nadvise ("failed", "lstat");
401: free (( char *) qr);
402: qr = NULL;
403: }
404: *tp = '\0';
405: return qr;
406: }
407: qr -> offset = type_Idist_QueryResult_doesExist;
408: switch (stb.st_mode & S_IFMT) {
409: case S_IFREG:
410: case S_IFDIR:
411: case S_IFLNK:
412: qr -> un.doesExist = makefs (stb.st_mode & S_IFMT, 0,
413: stb.st_mode & 07777, stb.st_size,
414: stb.st_mtime, "", "", str, "");
415: break;
416:
417: default:
418: nadvise (NULLCP, "%s: not a file or directory", str);
419: free ((char *)qr);
420: qr = NULL;
421: }
422: *tp = '\0';
423: return qr;
424: }
425:
426: static struct type_Idist_IA5List *str2ia5list (s, len)
427: char *s;
428: int len;
429: {
430: register struct type_Idist_IA5List *ia5;
431:
432: if ((ia5 = (struct type_Idist_IA5List *) calloc (1, sizeof *ia5))
433: == NULL)
434: return NULL;
435:
436: if ((ia5 -> IA5String = str2qb (s, len, 1)) == NULL) {
437: free ((char *) ia5);
438: return NULL;
439: }
440:
441: return ia5;
442: }
443:
444: struct type_Idist_FileList *do_listcdir ()
445: {
446: DIR *d;
447: register struct direct *dp;
448: struct type_Idist_FileList *base, **flp;
449: char buf[BUFSIZ];
450: struct stat stb;
451:
452: base = NULL;
453: flp = &base;
454:
455: if ((d = opendir (target)) == NULL) {
456: nadvise (target, "Can't open directory");
457: return NULL;
458: }
459:
460: while (dp = readdir (d)) {
461: if (strcmp (dp -> d_name, ".") == 0 ||
462: strcmp (dp -> d_name, "..") == 0)
463: continue;
464: (void) sprintf (buf, "%s/%s", target, dp -> d_name);
465: if (lstat (buf, &stb) < 0) {
466: nadvise (buf, "Can't stat");
467: continue;
468: }
469: switch (stb.st_mode & S_IFMT) {
470: case S_IFDIR:
471: case S_IFLNK:
472: case S_IFREG:
473: break;
474: default: /* skip sockets, fifos et al... */
475: continue;
476: }
477: if ((*flp = (struct type_Idist_FileList *)
478: malloc (sizeof **flp)) == NULL)
479: adios ("memory", "out of");
480:
481: (*flp) -> FileSpec = makefs (stb.st_mode & S_IFMT, 0,
482: stb.st_mode & 07777, stb.st_size,
483: stb.st_mtime, "", "",
484: dp->d_name, "");
485: (*flp) -> next = NULL;
486: flp = &(*flp) -> next;
487: }
488: closedir (d);
489: return base;
490: }
491:
492: fixup ()
493: {
494: struct timeval tvp[2];
495: char *new, *p;
496: char *owner, *group;
497: long convtime ();
498:
499: p = qb2str (cfiletype -> filename);
500: new = cannon (p);
501: free (p);
502:
503: if (bit_on (cfiletype -> fileopts, bit_Idist_Options_compare)) {
504: if (compare (target, new) == OK) {
505: (void) unlink (new);
506: return OK;
507: }
508: if (bit_on (cfiletype -> fileopts, bit_Idist_Options_verify)) {
509: (void) unlink (new);
510: note ("need to update: %s", target);
511: return OK;
512: }
513: }
514:
515: tvp[1].tv_sec =
516: tvp[0].tv_sec =
517: convtime (cfiletype -> filemtime);
518: tvp[0].tv_usec = tvp[1].tv_usec = 0;
519: if (utimes (new, tvp) < 0)
520: nadvise (new, "utimes failed on");
521:
522: owner = qb2str (cfiletype -> fileowner);
523: group = qb2str (cfiletype -> filegroup);
524:
525: if (chog (new, owner, group, cfiletype -> filemode) < 0) {
526: free (owner);
527: free (group);
528: (void) unlink (new);
529: return NOTOK;
530: }
531: free (owner);
532: free (group);
533:
534: if (rename (new, target) < 0) {
535: nadvise (target, "Can't rename %s to", new);
536: return NOTOK;
537: }
538: if (bit_on (cfiletype -> fileopts, bit_Idist_Options_compare))
539: note ("updated %s", target);
540: free_Idist_FileSpec (cfiletype);
541: cfiletype = NULL;
542: return OK;
543: }
544:
545: static int compare (f1, f2)
546: char *f1, *f2;
547: {
548: FILE *fp1, *fp2;
549: char buf1[BUFSIZ], buf2[BUFSIZ]; /* these two had
550: better be identical */
551: int n1, n2;
552:
553: if ((fp1 = fopen (f1, "r")) == NULL) {
554: nadvise (f1, "Can't reopen file");
555: return NOTOK;
556: }
557: if ((fp2 = fopen (f2, "r")) == NULL) {
558: nadvise (f2, "Can't reopend file");
559: (void) fclose (fp1);
560: return NOTOK;
561: }
562: for (;;) {
563: n1 = fread (buf1, sizeof buf1[0], sizeof buf1, fp1);
564: n2 = fread (buf2, sizeof buf2[0], sizeof buf2, fp2);
565: if (n1 != n2 || n1 == 0)
566: break;
567: if (bcmp (buf1, buf2, n1) != 0)
568: break;
569: }
570:
571: (void) fclose (fp1);
572: (void) fclose (fp2);
573: return n1 == 0 ? OK : NOTOK;
574: }
575:
576:
577: /*
578: * Change owner, group and mode of file.
579: */
580: chog(file, owner, group, mode)
581: char *file, *owner, *group;
582: int mode;
583: {
584: register int i;
585: int uid, gid;
586: extern char user[];
587: extern int userid;
588:
589: uid = userid;
590: if (userid == 0) {
591: if (*owner == ':') {
592: uid = atoi(owner + 1);
593: } else if (pw == NULL || strcmp(owner, pw->pw_name) != 0) {
594: if ((pw = getpwnam(owner)) == NULL) {
595: if (mode & 04000) {
596: note("%s: unknown login name, clearing setuid",
597: host, owner);
598: mode &= ~04000;
599: uid = 0;
600: }
601: } else
602: uid = pw->pw_uid;
603: } else
604: uid = pw->pw_uid;
605: if (*group == ':') {
606: gid = atoi(group + 1);
607: goto ok;
608: }
609: } else if ((mode & 04000) && strcmp(user, owner) != 0)
610: mode &= ~04000;
611: gid = -1;
612: if (gr == NULL || strcmp(group, gr->gr_name) != 0) {
613: if ((*group == ':' && (getgrgid(gid = atoi(group + 1)) == NULL))
614: || ((gr = getgrnam(group)) == NULL)) {
615: if (mode & 02000) {
616: note("%s: unknown group", group);
617: mode &= ~02000;
618: }
619: } else
620: gid = gr->gr_gid;
621: } else
622: gid = gr->gr_gid;
623: if (userid && gid >= 0) {
624: if (gr) for (i = 0; gr->gr_mem[i] != NULL; i++)
625: if (!(strcmp(user, gr->gr_mem[i])))
626: goto ok;
627: mode &= ~02000;
628: gid = -1;
629: }
630: ok:
631: if (userid == 0 && chown(file, uid, gid) < 0 )
632: nadvise (file, "chown failed on");
633: if ((mode & 06000) && chmod(file, mode) < 0) {
634: nadvise (file, "chmod to 0%o failed on", mode);
635: }
636: return(0);
637: }
638:
639: cleanup ()
640: {
641: char *p, *temp;
642:
643: if (cfiletype) {
644: p = qb2str (cfiletype -> filename);
645: temp = cannon (p);
646: (void) unlink (temp);
647: }
648: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.