possible buffer overflow; bug report 4.3BSD-tahoe/usr.sbin/3
[unix-history] / usr / src / usr.bin / rdist / docmd.c
CommitLineData
7172eb74
DF
1/*
2 * Copyright (c) 1983 Regents of the University of California.
0718fb71
KB
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
b36fc510
KB
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
7172eb74
DF
16 */
17
b6b5501c 18#ifndef lint
567e65c3 19static char sccsid[] = "@(#)docmd.c 5.4 (Berkeley) %G%";
0718fb71 20#endif /* not lint */
b6b5501c
RC
21
22#include "defs.h"
0fccdfef 23#include <setjmp.h>
bbdda833 24#include <netdb.h>
b6b5501c 25
0fccdfef 26FILE *lfp; /* log file for recording files updated */
4085f36f 27struct subcmd *subcmds; /* list of sub-commands for current cmd */
0fccdfef
RC
28jmp_buf env;
29
30int cleanup();
31int lostconn();
32
33/*
34 * Do the commands in cmds (initialized by yyparse).
35 */
78a18ca3
RC
36docmds(dhosts, argc, argv)
37 char **dhosts;
0fccdfef
RC
38 int argc;
39 char **argv;
40{
41 register struct cmd *c;
86d7a5c5
RC
42 register struct namelist *f;
43 register char **cpp;
0fccdfef
RC
44 extern struct cmd *cmds;
45
46 signal(SIGHUP, cleanup);
47 signal(SIGINT, cleanup);
48 signal(SIGQUIT, cleanup);
49 signal(SIGTERM, cleanup);
50
51 for (c = cmds; c != NULL; c = c->c_next) {
e4b2c01a 52 if (dhosts != NULL && *dhosts != NULL) {
78a18ca3
RC
53 for (cpp = dhosts; *cpp; cpp++)
54 if (strcmp(c->c_name, *cpp) == 0)
55 goto fndhost;
56 continue;
57 }
58 fndhost:
86d7a5c5
RC
59 if (argc) {
60 for (cpp = argv; *cpp; cpp++) {
61 if (c->c_label != NULL &&
4085f36f 62 strcmp(c->c_label, *cpp) == 0) {
86d7a5c5
RC
63 cpp = NULL;
64 goto found;
65 }
66 for (f = c->c_files; f != NULL; f = f->n_next)
67 if (strcmp(f->n_name, *cpp) == 0)
68 goto found;
69 }
70 continue;
71 } else
72 cpp = NULL;
73 found:
0fccdfef
RC
74 switch (c->c_type) {
75 case ARROW:
86d7a5c5 76 doarrow(cpp, c->c_files, c->c_name, c->c_cmds);
0fccdfef
RC
77 break;
78 case DCOLON:
86d7a5c5 79 dodcolon(cpp, c->c_files, c->c_name, c->c_cmds);
0fccdfef
RC
80 break;
81 default:
82 fatal("illegal command type %d\n", c->c_type);
83 }
84 }
85 closeconn();
86}
b6b5501c
RC
87
88/*
82572cb6 89 * Process commands for sending files to other machines.
b6b5501c 90 */
86d7a5c5
RC
91doarrow(filev, files, rhost, cmds)
92 char **filev;
0fccdfef 93 struct namelist *files;
9d560577 94 char *rhost;
0fccdfef 95 struct subcmd *cmds;
b6b5501c 96{
0fccdfef
RC
97 register struct namelist *f;
98 register struct subcmd *sc;
86d7a5c5 99 register char **cpp;
a3e6fd64 100 int n, ddir, opts = options;
b6b5501c
RC
101
102 if (debug)
9d560577 103 printf("doarrow(%x, %s, %x)\n", files, rhost, cmds);
b6b5501c 104
024fde5b
RC
105 if (files == NULL) {
106 error("no files to be updated\n");
107 return;
108 }
e8109cf8 109
4085f36f 110 subcmds = cmds;
0fccdfef 111 ddir = files->n_next != NULL; /* destination is a directory */
d0bd9bfc
RC
112 if (nflag)
113 printf("updating host %s\n", rhost);
114 else {
346dad94 115 if (setjmp(env))
0fccdfef
RC
116 goto done;
117 signal(SIGPIPE, lostconn);
9d560577 118 if (!makeconn(rhost))
0fccdfef
RC
119 return;
120 if ((lfp = fopen(tmpfile, "w")) == NULL) {
121 fatal("cannot open %s\n", tmpfile);
122 exit(1);
b6b5501c 123 }
0fccdfef
RC
124 }
125 for (f = files; f != NULL; f = f->n_next) {
86d7a5c5 126 if (filev) {
0fccdfef 127 for (cpp = filev; *cpp; cpp++)
86d7a5c5 128 if (strcmp(f->n_name, *cpp) == 0)
0fccdfef
RC
129 goto found;
130 if (!nflag)
131 (void) fclose(lfp);
132 continue;
b6b5501c 133 }
0fccdfef 134 found:
0fccdfef
RC
135 n = 0;
136 for (sc = cmds; sc != NULL; sc = sc->sc_next) {
137 if (sc->sc_type != INSTALL)
138 continue;
139 n++;
140 install(f->n_name, sc->sc_name,
141 sc->sc_name == NULL ? 0 : ddir, sc->sc_options);
a3e6fd64 142 opts = sc->sc_options;
b6b5501c 143 }
0fccdfef
RC
144 if (n == 0)
145 install(f->n_name, NULL, 0, options);
b6b5501c 146 }
0fccdfef
RC
147done:
148 if (!nflag) {
346dad94 149 (void) signal(SIGPIPE, cleanup);
0fccdfef
RC
150 (void) fclose(lfp);
151 lfp = NULL;
152 }
153 for (sc = cmds; sc != NULL; sc = sc->sc_next)
154 if (sc->sc_type == NOTIFY)
9d560577 155 notify(tmpfile, rhost, sc->sc_args, 0);
a3e6fd64 156 if (!nflag) {
b6b5501c 157 (void) unlink(tmpfile);
a3e6fd64
RC
158 for (; ihead != NULL; ihead = ihead->nextp) {
159 free(ihead);
160 if ((opts & IGNLNKS) || ihead->count == 0)
161 continue;
162 log(lfp, "%s: Warning: missing links\n",
163 ihead->pathname);
164 }
165 }
b6b5501c
RC
166}
167
168/*
169 * Create a connection to the rdist server on the machine rhost.
170 */
171makeconn(rhost)
172 char *rhost;
173{
6e6d779a 174 register char *ruser, *cp;
0fccdfef 175 static char *cur_host = NULL;
bbdda833
RC
176 static int port = -1;
177 char tuser[20];
6e6d779a 178 int n;
b6b5501c 179 extern char user[];
80babee1 180 extern int userid;
b6b5501c 181
0fccdfef
RC
182 if (debug)
183 printf("makeconn(%s)\n", rhost);
184
346dad94
RC
185 if (cur_host != NULL && rem >= 0) {
186 if (strcmp(cur_host, rhost) == 0)
187 return(1);
188 closeconn();
346dad94 189 }
bbdda833
RC
190 cur_host = rhost;
191 cp = index(rhost, '@');
192 if (cp != NULL) {
193 char c = *cp;
194
195 *cp = '\0';
196 strncpy(tuser, rhost, sizeof(tuser)-1);
197 *cp = c;
198 rhost = cp + 1;
199 ruser = tuser;
200 if (*ruser == '\0')
201 ruser = user;
202 else if (!okname(ruser))
b6b5501c
RC
203 return(0);
204 } else
205 ruser = user;
0fccdfef
RC
206 if (!qflag)
207 printf("updating host %s\n", rhost);
567e65c3 208 (void) sprintf(buf, "%s -Server%s", _PATH_RDIST, qflag ? " -q" : "");
bbdda833
RC
209 if (port < 0) {
210 struct servent *sp;
211
212 if ((sp = getservbyname("shell", "tcp")) == NULL)
213 fatal("shell/tcp: unknown service");
214 port = sp->s_port;
215 }
b6b5501c
RC
216
217 if (debug) {
bbdda833 218 printf("port = %d, luser = %s, ruser = %s\n", ntohs(port), user, ruser);
b6b5501c
RC
219 printf("buf = %s\n", buf);
220 }
221
82572cb6 222 fflush(stdout);
80babee1 223 setreuid(userid, 0);
bbdda833 224 rem = rcmd(&rhost, port, user, ruser, buf, 0);
80babee1 225 setreuid(0, userid);
b6b5501c
RC
226 if (rem < 0)
227 return(0);
6e6d779a
RC
228 cp = buf;
229 if (read(rem, cp, 1) != 1)
230 lostconn();
231 if (*cp == 'V') {
232 do {
233 if (read(rem, cp, 1) != 1)
234 lostconn();
235 } while (*cp++ != '\n' && cp < &buf[BUFSIZ]);
236 *--cp = '\0';
237 cp = buf;
238 n = 0;
239 while (*cp >= '0' && *cp <= '9')
240 n = (n * 10) + (*cp++ - '0');
0392d90c 241 if (*cp == '\0' && n == VERSION)
6e6d779a 242 return(1);
a3e6fd64
RC
243 error("connection failed: version numbers don't match (local %d, remote %d)\n", VERSION, n);
244 } else
245 error("connection failed: version numbers don't match\n");
0392d90c 246 closeconn();
6e6d779a 247 return(0);
b6b5501c
RC
248}
249
0fccdfef
RC
250/*
251 * Signal end of previous connection.
252 */
253closeconn()
254{
9d560577
RC
255 if (debug)
256 printf("closeconn()\n");
257
0fccdfef
RC
258 if (rem >= 0) {
259 (void) write(rem, "\2\n", 2);
260 (void) close(rem);
261 rem = -1;
262 }
263}
264
265lostconn()
266{
346dad94
RC
267 if (iamremote)
268 cleanup();
269 log(lfp, "rdist: lost connection\n");
0fccdfef
RC
270 longjmp(env, 1);
271}
272
e8109cf8
RC
273okname(name)
274 register char *name;
b6b5501c 275{
e8109cf8
RC
276 register char *cp = name;
277 register int c;
b6b5501c 278
e8109cf8
RC
279 do {
280 c = *cp;
281 if (c & 0200)
282 goto bad;
283 if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
284 goto bad;
285 cp++;
286 } while (*cp);
287 return(1);
288bad:
289 error("invalid user name %s\n", name);
290 return(0);
82572cb6
RC
291}
292
d6bccb44
RC
293time_t lastmod;
294FILE *tfp;
295extern char target[], *tp;
3024eb6f 296
82572cb6
RC
297/*
298 * Process commands for comparing files to time stamp files.
299 */
86d7a5c5
RC
300dodcolon(filev, files, stamp, cmds)
301 char **filev;
0fccdfef
RC
302 struct namelist *files;
303 char *stamp;
304 struct subcmd *cmds;
82572cb6 305{
0fccdfef
RC
306 register struct subcmd *sc;
307 register struct namelist *f;
82572cb6 308 register char **cpp;
f7770429
RC
309 struct timeval tv[2];
310 struct timezone tz;
82572cb6 311 struct stat stb;
82572cb6
RC
312
313 if (debug)
0fccdfef 314 printf("dodcolon()\n");
82572cb6 315
d6bccb44 316 if (files == NULL) {
024fde5b
RC
317 error("no files to be updated\n");
318 return;
319 }
0fccdfef
RC
320 if (stat(stamp, &stb) < 0) {
321 error("%s: %s\n", stamp, sys_errlist[errno]);
d6bccb44
RC
322 return;
323 }
324 if (debug)
0fccdfef 325 printf("%s: %d\n", stamp, stb.st_mtime);
3db8aa13 326
4085f36f 327 subcmds = cmds;
3db8aa13
RC
328 lastmod = stb.st_mtime;
329 if (nflag || (options & VERIFY))
330 tfp = NULL;
331 else {
332 if ((tfp = fopen(tmpfile, "w")) == NULL) {
0fccdfef 333 error("%s: %s\n", stamp, sys_errlist[errno]);
d6bccb44
RC
334 return;
335 }
3db8aa13
RC
336 (void) gettimeofday(&tv[0], &tz);
337 tv[1] = tv[0];
338 (void) utimes(stamp, tv);
339 }
f7770429 340
0fccdfef 341 for (f = files; f != NULL; f = f->n_next) {
86d7a5c5 342 if (filev) {
82572cb6 343 for (cpp = filev; *cpp; cpp++)
86d7a5c5 344 if (strcmp(f->n_name, *cpp) == 0)
82572cb6
RC
345 goto found;
346 continue;
347 }
348 found:
349 tp = NULL;
0fccdfef 350 cmptime(f->n_name);
82572cb6 351 }
f7770429 352
d6bccb44
RC
353 if (tfp != NULL)
354 (void) fclose(tfp);
0fccdfef
RC
355 for (sc = cmds; sc != NULL; sc = sc->sc_next)
356 if (sc->sc_type == NOTIFY)
357 notify(tmpfile, NULL, sc->sc_args, lastmod);
d6bccb44
RC
358 if (!nflag && !(options & VERIFY))
359 (void) unlink(tmpfile);
82572cb6
RC
360}
361
362/*
363 * Compare the mtime of file to the list of time stamps.
364 */
365cmptime(name)
366 char *name;
367{
82572cb6
RC
368 struct stat stb;
369
370 if (debug)
371 printf("cmptime(%s)\n", name);
372
4085f36f 373 if (except(name))
82572cb6
RC
374 return;
375
d6bccb44
RC
376 if (nflag) {
377 printf("comparing dates: %s\n", name);
378 return;
379 }
380
82572cb6
RC
381 /*
382 * first time cmptime() is called?
383 */
384 if (tp == NULL) {
e8109cf8
RC
385 if (exptilde(target, name) == NULL)
386 return;
82572cb6
RC
387 tp = name = target;
388 while (*tp)
389 tp++;
390 }
391 if (access(name, 4) < 0 || stat(name, &stb) < 0) {
392 error("%s: %s\n", name, sys_errlist[errno]);
393 return;
394 }
395
396 switch (stb.st_mode & S_IFMT) {
397 case S_IFREG:
398 break;
399
400 case S_IFDIR:
401 rcmptime(&stb);
402 return;
403
404 default:
405 error("%s: not a plain file\n", name);
406 return;
407 }
408
d6bccb44
RC
409 if (stb.st_mtime > lastmod)
410 log(tfp, "new: %s\n", name);
82572cb6
RC
411}
412
413rcmptime(st)
414 struct stat *st;
415{
416 register DIR *d;
417 register struct direct *dp;
418 register char *cp;
419 char *otp;
420 int len;
421
422 if (debug)
423 printf("rcmptime(%x)\n", st);
424
425 if ((d = opendir(target)) == NULL) {
426 error("%s: %s\n", target, sys_errlist[errno]);
427 return;
428 }
429 otp = tp;
430 len = tp - target;
431 while (dp = readdir(d)) {
432 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
433 continue;
434 if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
435 error("%s/%s: Name too long\n", target, dp->d_name);
436 continue;
437 }
438 tp = otp;
439 *tp++ = '/';
440 cp = dp->d_name;
441 while (*tp++ = *cp++)
442 ;
443 tp--;
444 cmptime(target);
445 }
446 closedir(d);
447 tp = otp;
448 *tp = '\0';
b6b5501c
RC
449}
450
451/*
452 * Notify the list of people the changes that were made.
f7770429
RC
453 * rhost == NULL if we are mailing a list of changes compared to at time
454 * stamp file.
b6b5501c 455 */
f7770429 456notify(file, rhost, to, lmod)
3024eb6f 457 char *file, *rhost;
0fccdfef 458 register struct namelist *to;
f7770429 459 time_t lmod;
b6b5501c
RC
460{
461 register int fd, len;
462 FILE *pf, *popen();
463 struct stat stb;
464
d6bccb44 465 if ((options & VERIFY) || to == NULL)
b6b5501c
RC
466 return;
467 if (!qflag) {
82572cb6 468 printf("notify ");
3024eb6f
RC
469 if (rhost)
470 printf("@%s ", rhost);
b6b5501c
RC
471 prnames(to);
472 }
473 if (nflag)
474 return;
475
82572cb6
RC
476 if ((fd = open(file, 0)) < 0) {
477 error("%s: %s\n", file, sys_errlist[errno]);
478 return;
479 }
480 if (fstat(fd, &stb) < 0) {
481 error("%s: %s\n", file, sys_errlist[errno]);
482 (void) close(fd);
483 return;
484 }
485 if (stb.st_size == 0) {
486 (void) close(fd);
b6b5501c
RC
487 return;
488 }
489 /*
490 * Create a pipe to mailling program.
491 */
567e65c3
KB
492 (void)sprintf(buf, "%s -oi -t", _PATH_SENDMAIL);
493 pf = popen(buf, "w");
3024eb6f 494 if (pf == NULL) {
567e65c3 495 error("notify: \"%s\" failed\n", _PATH_SENDMAIL);
3024eb6f
RC
496 (void) close(fd);
497 return;
498 }
b6b5501c
RC
499 /*
500 * Output the proper header information.
501 */
502 fprintf(pf, "From: rdist (Remote distribution program)\n");
503 fprintf(pf, "To:");
0fccdfef
RC
504 if (!any('@', to->n_name) && rhost != NULL)
505 fprintf(pf, " %s@%s", to->n_name, rhost);
f7770429 506 else
0fccdfef
RC
507 fprintf(pf, " %s", to->n_name);
508 to = to->n_next;
b6b5501c 509 while (to != NULL) {
0fccdfef
RC
510 if (!any('@', to->n_name) && rhost != NULL)
511 fprintf(pf, ", %s@%s", to->n_name, rhost);
82572cb6 512 else
0fccdfef
RC
513 fprintf(pf, ", %s", to->n_name);
514 to = to->n_next;
b6b5501c
RC
515 }
516 putc('\n', pf);
f7770429
RC
517 if (rhost != NULL)
518 fprintf(pf, "Subject: files updated by rdist from %s to %s\n",
519 host, rhost);
520 else
521 fprintf(pf, "Subject: files updated after %s\n", ctime(&lmod));
b6b5501c
RC
522 putc('\n', pf);
523
524 while ((len = read(fd, buf, BUFSIZ)) > 0)
525 (void) fwrite(buf, 1, len, pf);
526 (void) close(fd);
527 (void) pclose(pf);
528}
529
b6b5501c 530/*
d6bccb44 531 * Return true if name is in the list.
b6b5501c 532 */
d6bccb44 533inlist(list, file)
0fccdfef 534 struct namelist *list;
b6b5501c
RC
535 char *file;
536{
0fccdfef 537 register struct namelist *nl;
b6b5501c 538
0fccdfef
RC
539 for (nl = list; nl != NULL; nl = nl->n_next)
540 if (!strcmp(file, nl->n_name))
e8109cf8 541 return(1);
b6b5501c
RC
542 return(0);
543}
544
e8109cf8 545/*
4085f36f 546 * Return TRUE if file is in the exception list.
e8109cf8 547 */
4085f36f
RC
548except(file)
549 char *file;
b6b5501c 550{
4085f36f
RC
551 register struct subcmd *sc;
552 register struct namelist *nl;
b6b5501c 553
e8109cf8 554 if (debug)
4085f36f 555 printf("except(%s)\n", file);
e8109cf8 556
4085f36f
RC
557 for (sc = subcmds; sc != NULL; sc = sc->sc_next) {
558 if (sc->sc_type != EXCEPT && sc->sc_type != PATTERN)
e8109cf8 559 continue;
0fccdfef 560 for (nl = sc->sc_args; nl != NULL; nl = nl->n_next) {
4085f36f
RC
561 if (sc->sc_type == EXCEPT) {
562 if (!strcmp(file, nl->n_name))
563 return(1);
564 continue;
0fccdfef 565 }
4085f36f
RC
566 re_comp(nl->n_name);
567 if (re_exec(file) > 0)
568 return(1);
e8109cf8
RC
569 }
570 }
4085f36f 571 return(0);
b6b5501c
RC
572}
573
574char *
575colon(cp)
576 register char *cp;
577{
578
579 while (*cp) {
580 if (*cp == ':')
581 return(cp);
582 if (*cp == '/')
583 return(0);
584 cp++;
585 }
586 return(0);
587}