Annotation of src/usr.bin/rdist/common.c, Revision 1.24
1.24 ! krw 1: /* $OpenBSD: common.c,v 1.23 2009/10/27 23:59:42 deraadt Exp $ */
1.3 deraadt 2:
1.1 dm 3: /*
4: * Copyright (c) 1983 Regents of the University of California.
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
1.21 millert 15: * 3. Neither the name of the University nor the names of its contributors
1.1 dm 16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
31:
1.20 millert 32: #include "defs.h"
1.1 dm 33:
34: /*
35: * Things common to both the client and server.
36: */
37:
38: #if defined(NEED_UTIME_H)
39: #include <utime.h>
40: #endif /* defined(NEED_UTIME_H) */
1.20 millert 41: #include <sys/wait.h>
1.6 millert 42: #include <sys/socket.h>
1.1 dm 43:
44: /*
45: * Variables common to both client and server
46: */
47: char host[MAXHOSTNAMELEN]; /* Name of this host */
48: UID_T userid = (UID_T)-1; /* User's UID */
49: GID_T groupid = (GID_T)-1; /* User's GID */
50: char *homedir = NULL; /* User's $HOME */
51: char *locuser = NULL; /* Local User's name */
52: int isserver = FALSE; /* We're the server */
53: int amchild = 0; /* This PID is a child */
54: int do_fork = 1; /* Fork child process */
55: char *currenthost = NULL; /* Current client hostname */
56: char *progname = NULL; /* Name of this program */
57: int rem_r = -1; /* Client file descriptor */
58: int rem_w = -1; /* Client file descriptor */
59: struct passwd *pw = NULL; /* Local user's pwd entry */
1.20 millert 60: volatile sig_atomic_t contimedout = FALSE; /* Connection timed out */
1.1 dm 61: int proto_version = -1; /* Protocol version */
62: int rtimeout = RTIMEOUT; /* Response time out */
63: jmp_buf finish_jmpbuf; /* Finish() jmp buffer */
1.2 dm 64: int setjmp_ok = FALSE; /* setjmp()/longjmp() status */
1.1 dm 65: char **realargv; /* Real main() argv */
66: int realargc; /* Real main() argc */
67: opt_t options = 0; /* Global install options */
1.20 millert 68: char defowner[64] = "bin"; /* Default owner */
69: char defgroup[64] = "bin"; /* Default group */
70:
71: static int sendcmdmsg(int, char *, size_t);
1.24 ! krw 72: static ssize_t remread(int, u_char *, size_t);
1.20 millert 73: static int remmore(void);
1.1 dm 74:
75: /*
76: * Front end to write() that handles partial write() requests.
77: */
1.20 millert 78: WRITE_RETURN_T
79: xwrite(int fd, void *buf, WRITE_AMT_T len)
1.1 dm 80: {
81: WRITE_AMT_T nleft = len;
82: WRITE_RETURN_T nwritten;
1.12 mpech 83: char *ptr = buf;
1.1 dm 84:
85: while (nleft > 0) {
86: if ((nwritten = write(fd, ptr, nleft)) <= 0) {
87: return nwritten;
88: }
89: nleft -= nwritten;
90: ptr += nwritten;
91: }
92:
93: return len;
94: }
95:
96: /*
97: * Do run-time initialization
98: */
1.20 millert 99: int
100: init(int argc, char **argv, char **envp)
1.1 dm 101: {
1.12 mpech 102: int i;
1.1 dm 103:
1.13 millert 104: #ifdef SIGSEGV_CHECK
1.1 dm 105: if (!isserver)
106: (void) signal(SIGSEGV, sighandler);
1.13 millert 107: #endif
1.1 dm 108:
109: /*
110: * Save a copy of our argc and argv before setargs() overwrites them
111: */
112: realargc = argc;
113: realargv = (char **) xmalloc(sizeof(char *) * (argc+1));
114: for (i = 0; i < argc; i++)
1.8 millert 115: realargv[i] = xstrdup(argv[i]);
1.1 dm 116:
1.6 millert 117: #if defined(SETARGS)
1.1 dm 118: setargs_settup(argc, argv, envp);
119: #endif /* SETARGS */
120:
121: pw = getpwuid(userid = getuid());
122: if (pw == NULL) {
1.16 deraadt 123: error("Your user id (%u) is not known to this system.",
1.1 dm 124: getuid());
125: return(-1);
126: }
127:
1.20 millert 128: debugmsg(DM_MISC, "UserID = %u pwname = '%s' home = '%s'\n",
1.1 dm 129: userid, pw->pw_name, pw->pw_dir);
1.8 millert 130: homedir = xstrdup(pw->pw_dir);
131: locuser = xstrdup(pw->pw_name);
1.1 dm 132: groupid = pw->pw_gid;
133: gethostname(host, sizeof(host));
1.20 millert 134: #if 0
1.1 dm 135: if ((cp = strchr(host, '.')) != NULL)
136: *cp = CNULL;
1.20 millert 137: #endif
1.1 dm 138:
139: /*
140: * If we're not root, disable paranoid ownership checks
141: * since normal users cannot chown() files.
142: */
143: if (!isserver && userid != 0) {
144: FLAG_ON(options, DO_NOCHKOWNER);
145: FLAG_ON(options, DO_NOCHKGROUP);
146: }
147:
148: return(0);
149: }
150:
151: /*
152: * Finish things up before ending.
153: */
1.20 millert 154: void
155: finish(void)
1.1 dm 156: {
157: extern jmp_buf finish_jmpbuf;
158:
159: debugmsg(DM_CALL,
160: "finish() called: do_fork = %d amchild = %d isserver = %d",
161: do_fork, amchild, isserver);
1.20 millert 162: cleanup(0);
1.1 dm 163:
164: /*
165: * There's no valid finish_jmpbuf for the rdist master parent.
166: */
167: if (!do_fork || amchild || isserver) {
1.2 dm 168:
169: if (!setjmp_ok) {
170: #ifdef DEBUG_SETJMP
171: error("attemping longjmp() without target");
172: abort();
173: #else
174: exit(1);
175: #endif
176: }
177:
1.1 dm 178: longjmp(finish_jmpbuf, 1);
179: /*NOTREACHED*/
180: error("Unexpected failure of longjmp() in finish()");
181: exit(2);
182: } else
183: exit(1);
184: }
185:
186: /*
187: * Handle lost connections
188: */
1.20 millert 189: void
190: lostconn(void)
1.1 dm 191: {
192: /* Prevent looping */
193: (void) signal(SIGPIPE, SIG_IGN);
194:
195: rem_r = rem_w = -1; /* Ensure we don't try to send to server */
196: checkhostname();
197: error("Lost connection to %s",
198: (currenthost) ? currenthost : "(unknown)");
199:
200: finish();
201: }
202:
1.13 millert 203: #ifdef SIGSEGV_CHECK
1.1 dm 204: /*
205: * Do a core dump
206: */
1.20 millert 207: void
208: coredump(void)
1.1 dm 209: {
1.20 millert 210: error("Segmentation violation - dumping core [PID = %d, %s]",
211: getpid(),
1.1 dm 212: (isserver) ? "isserver" : ((amchild) ? "amchild" : "parent"));
213: abort();
214: /*NOTREACHED*/
215: fatalerr("Abort failed - no core dump. Exiting...");
216: }
1.13 millert 217: #endif
1.1 dm 218:
219: /*
220: * General signal handler
221: */
1.20 millert 222: void
223: sighandler(int sig)
1.1 dm 224: {
1.7 millert 225: int save_errno = errno;
226:
1.1 dm 227: debugmsg(DM_CALL, "sighandler() received signal %d\n", sig);
228:
229: switch (sig) {
230: case SIGALRM:
231: contimedout = TRUE;
232: checkhostname();
233: error("Response time out");
234: finish();
235: break;
236:
237: case SIGPIPE:
238: lostconn();
239: break;
240:
241: case SIGFPE:
242: debug = !debug;
243: break;
244:
1.13 millert 245: #ifdef SIGSEGV_CHECK
1.1 dm 246: case SIGSEGV:
247: coredump();
248: break;
1.13 millert 249: #endif
1.1 dm 250:
251: case SIGHUP:
252: case SIGINT:
253: case SIGQUIT:
254: case SIGTERM:
255: finish();
256: break;
257:
258: default:
259: fatalerr("No signal handler defined for signal %d.", sig);
260: }
1.7 millert 261: errno = save_errno;
1.1 dm 262: }
263:
264: /*
265: * Function to actually send the command char and message to the
266: * remote host.
267: */
1.20 millert 268: static int
269: sendcmdmsg(int cmd, char *msg, size_t msgsize)
1.1 dm 270: {
271: int len;
272:
273: if (rem_w < 0)
274: return(-1);
275:
276: /*
277: * All commands except C_NONE should have a newline
278: */
279: if (cmd != C_NONE && !strchr(msg + 1, '\n'))
1.18 millert 280: (void) strlcat(msg + 1, "\n", msgsize - 1);
1.1 dm 281:
282: if (cmd == C_NONE)
283: len = strlen(msg);
284: else {
285: len = strlen(msg + 1) + 1;
286: msg[0] = cmd;
287: }
288:
289: debugmsg(DM_PROTO, ">>> Cmd = %c (\\%3.3o) Msg = \"%.*s\"",
290: cmd, cmd,
291: (cmd == C_NONE) ? len-1 : len-2,
292: (cmd == C_NONE) ? msg : msg + 1);
293:
294: return(!(xwrite(rem_w, msg, len) == len));
295: }
296:
297: /*
298: * Send a command message to the remote host.
299: * Called as sendcmd(char cmdchar, char *fmt, arg1, arg2, ...)
300: * The fmt and arg? arguments are optional.
301: */
302: #if defined(ARG_TYPE) && ARG_TYPE == ARG_STDARG
303: /*
304: * Stdarg frontend to sendcmdmsg()
305: */
1.20 millert 306: int
307: sendcmd(char cmd, char *fmt, ...)
1.1 dm 308: {
309: static char buf[BUFSIZ];
310: va_list args;
311:
312: va_start(args, fmt);
313: if (fmt)
1.18 millert 314: (void) vsnprintf(buf + (cmd != C_NONE),
1.20 millert 315: sizeof(buf) - (cmd != C_NONE), fmt, args);
1.1 dm 316: else
317: buf[1] = CNULL;
318: va_end(args);
319:
1.18 millert 320: return(sendcmdmsg(cmd, buf, sizeof(buf)));
1.1 dm 321: }
322: #endif /* ARG_TYPE == ARG_STDARG */
323:
324: #if defined(ARG_TYPE) && ARG_TYPE == ARG_VARARGS
325: /*
326: * Varargs frontend to sendcmdmsg()
327: */
1.20 millert 328: int
329: sendcmd(va_alist)
1.1 dm 330: va_dcl
331: {
332: static char buf[BUFSIZ];
333: va_list args;
334: char cmd;
335: char *fmt;
336:
337: va_start(args);
338: /* XXX The "int" is necessary as a workaround for broken varargs */
339: cmd = (char) va_arg(args, int);
340: fmt = va_arg(args, char *);
341: if (fmt)
1.18 millert 342: (void) vsnprintf(buf + (cmd != C_NONE),
1.20 millert 343: sizeof(buf) - (cmd != C_NONE), fmt, args);
1.1 dm 344: else
345: buf[1] = CNULL;
346: va_end(args);
347:
1.18 millert 348: return(sendcmdmsg(cmd, buf, sizeof(buf)));
1.1 dm 349: }
350: #endif /* ARG_TYPE == ARG_VARARGS */
351:
352: /*
353: * Internal variables and routines for reading lines from the remote.
354: */
355: static u_char rembuf[BUFSIZ];
356: static u_char *remptr;
1.24 ! krw 357: static ssize_t remleft;
1.1 dm 358:
359: #define remc() (--remleft < 0 ? remmore() : *remptr++)
360:
361: /*
362: * Back end to remote read()
363: */
1.24 ! krw 364: static ssize_t
! 365: remread(int fd, u_char *buf, size_t bufsiz)
1.1 dm 366: {
367: return(read(fd, (char *)buf, bufsiz));
368: }
369:
1.20 millert 370: static int
371: remmore(void)
1.1 dm 372: {
373: (void) signal(SIGALRM, sighandler);
374: (void) alarm(rtimeout);
375:
376: remleft = remread(rem_r, rembuf, sizeof(rembuf));
377:
378: (void) alarm(0);
379:
380: if (remleft < 0)
381: return (-2); /* error */
382: if (remleft == 0)
383: return (-1); /* EOF */
384: remptr = rembuf;
385: remleft--;
386: return (*remptr++);
387: }
388:
389: /*
390: * Read an input line from the remote. Return the number of bytes
391: * stored (equivalent to strlen(p)). If `cleanup' is set, EOF at
392: * the beginning of a line is returned as EOF (-1); other EOFs, or
393: * errors, call cleanup() or lostconn(). In other words, unless
394: * the third argument is nonzero, this routine never returns failure.
395: */
1.20 millert 396: int
397: remline(u_char *buffer, int space, int doclean)
1.1 dm 398: {
1.12 mpech 399: int c, left = space;
400: u_char *p = buffer;
1.1 dm 401:
402: if (rem_r < 0) {
403: error("Cannot read remote input: Remote descriptor not open.");
404: return(-1);
405: }
406:
407: while (left > 0) {
408: if ((c = remc()) < -1) { /* error */
409: if (doclean) {
410: finish();
411: /*NOTREACHED*/
412: }
413: lostconn();
414: /*NOTREACHED*/
415: }
416: if (c == -1) { /* got EOF */
417: if (doclean) {
418: if (left == space)
419: return (-1);/* signal proper EOF */
420: finish(); /* improper EOF */
421: /*NOTREACHED*/
422: }
423: lostconn();
424: /*NOTREACHED*/
425: }
426: if (c == '\n') {
427: *p = CNULL;
428:
429: if (debug) {
430: static char mbuf[BUFSIZ];
431:
1.20 millert 432: (void) snprintf(mbuf, sizeof(mbuf),
1.1 dm 433: "<<< Cmd = %c (\\%3.3o) Msg = \"%s\"",
434: buffer[0], buffer[0],
435: buffer + 1);
436:
437: debugmsg(DM_PROTO, "%s", mbuf);
438: }
439:
440: return (space - left);
441: }
442: *p++ = c;
443: left--;
444: }
445:
446: /* this will probably blow the entire session */
447: error("remote input line too long");
448: p[-1] = CNULL; /* truncate */
449: return (space);
450: }
451:
452: /*
453: * Non-line-oriented remote read.
454: */
1.24 ! krw 455: ssize_t
! 456: readrem(char *p, ssize_t space)
1.1 dm 457: {
458: if (remleft <= 0) {
459: /*
460: * Set remote time out alarm.
461: */
462: (void) signal(SIGALRM, sighandler);
463: (void) alarm(rtimeout);
464:
465: remleft = remread(rem_r, rembuf, sizeof(rembuf));
466:
467: (void) alarm(0);
468: remptr = rembuf;
469: }
470:
471: if (remleft <= 0)
472: return (remleft);
473: if (remleft < space)
474: space = remleft;
475:
1.20 millert 476: memcpy(p, remptr, space);
1.1 dm 477:
478: remptr += space;
479: remleft -= space;
480:
481: return (space);
482: }
483:
484: /*
485: * Get the user name for the uid.
486: */
1.20 millert 487: char *
488: getusername(UID_T uid, char *file, opt_t opts)
1.1 dm 489: {
490: static char buf[100];
491: static UID_T lastuid = (UID_T)-1;
492: struct passwd *pwd = NULL;
493:
494: /*
495: * The value of opts may have changed so we always
496: * do the opts check.
497: */
498: if (IS_ON(opts, DO_NUMCHKOWNER)) {
1.20 millert 499: (void) snprintf(buf, sizeof(buf), ":%u", uid);
1.1 dm 500: return(buf);
501: }
502:
503: /*
504: * Try to avoid getpwuid() call.
505: */
1.6 millert 506: if (lastuid == uid && buf[0] != '\0' && buf[0] != ':')
1.1 dm 507: return(buf);
508:
509: lastuid = uid;
510:
511: if ((pwd = getpwuid(uid)) == NULL) {
1.20 millert 512: if (IS_ON(opts, DO_DEFOWNER) && !isserver)
513: (void) strlcpy(buf, defowner, sizeof(buf));
514: else {
515: message(MT_WARNING,
516: "%s: No password entry for uid %u", file, uid);
517: (void) snprintf(buf, sizeof(buf), ":%u", uid);
518: }
519: } else {
520: (void) strlcpy(buf, pwd->pw_name, sizeof(buf));
521: }
1.1 dm 522:
523: return(buf);
524: }
525:
526: /*
527: * Get the group name for the gid.
528: */
1.20 millert 529: char *
530: getgroupname(GID_T gid, char *file, opt_t opts)
1.1 dm 531: {
532: static char buf[100];
533: static GID_T lastgid = (GID_T)-1;
534: struct group *grp = NULL;
535:
536: /*
537: * The value of opts may have changed so we always
538: * do the opts check.
539: */
540: if (IS_ON(opts, DO_NUMCHKGROUP)) {
1.20 millert 541: (void) snprintf(buf, sizeof(buf), ":%u", gid);
1.1 dm 542: return(buf);
543: }
544:
545: /*
546: * Try to avoid getgrgid() call.
547: */
1.6 millert 548: if (lastgid == gid && buf[0] != '\0' && buf[0] != ':')
1.1 dm 549: return(buf);
550:
551: lastgid = gid;
552:
553: if ((grp = (struct group *)getgrgid(gid)) == NULL) {
1.20 millert 554: if (IS_ON(opts, DO_DEFGROUP) && !isserver)
555: (void) strlcpy(buf, defgroup, sizeof(buf));
556: else {
557: message(MT_WARNING, "%s: No name for group %u",
558: file, gid);
559: (void) snprintf(buf, sizeof(buf), ":%u", gid);
560: }
1.1 dm 561: } else
1.20 millert 562: (void) strlcpy(buf, grp->gr_name, sizeof(buf));
1.1 dm 563:
564: return(buf);
565: }
566:
567: /*
568: * Read a response from the remote host.
569: */
1.20 millert 570: int
571: response(void)
1.1 dm 572: {
573: static u_char resp[BUFSIZ];
574: u_char *s;
575: int n;
576:
577: debugmsg(DM_CALL, "response() start\n");
578:
579: n = remline(s = resp, sizeof(resp), 0);
580:
581: n--;
582: switch (*s++) {
583: case C_ACK:
584: debugmsg(DM_PROTO, "received ACK\n");
585: return(0);
586: case C_LOGMSG:
587: if (n > 0) {
588: message(MT_CHANGE, "%s", s);
589: return(1);
590: }
591: debugmsg(DM_PROTO, "received EMPTY logmsg\n");
592: return(0);
593: case C_NOTEMSG:
594: if (s)
595: message(MT_NOTICE, "%s", s);
596: return(response());
597:
598: default:
599: s--;
600: n++;
601: /* fall into... */
602:
603: case C_ERRMSG: /* Normal error message */
604: if (s)
605: message(MT_NERROR, "%s", s);
606: return(-1);
607:
608: case C_FERRMSG: /* Fatal error message */
609: if (s)
610: message(MT_FERROR, "%s", s);
611: finish();
1.20 millert 612: return(-1);
1.1 dm 613: }
614: /*NOTREACHED*/
615: }
616:
617: /*
618: * This should be in expand.c but the other routines call other modules
619: * that we don't want to load in.
620: *
621: * Expand file names beginning with `~' into the
622: * user's home directory path name. Return a pointer in buf to the
623: * part corresponding to `file'.
624: */
1.20 millert 625: char *
626: exptilde(char *ebuf, char *file, size_t ebufsize)
1.1 dm 627: {
1.18 millert 628: char *pw_dir, *rest;
629: size_t len;
1.1 dm 630: extern char *homedir;
631:
632: if (*file != '~') {
1.18 millert 633: notilde:
634: (void) strlcpy(ebuf, file, ebufsize);
1.1 dm 635: return(ebuf);
636: }
637: if (*++file == CNULL) {
1.18 millert 638: pw_dir = homedir;
639: rest = NULL;
1.1 dm 640: } else if (*file == '/') {
1.18 millert 641: pw_dir = homedir;
642: rest = file;
1.1 dm 643: } else {
1.18 millert 644: rest = file;
645: while (*rest && *rest != '/')
646: rest++;
647: if (*rest == '/')
648: *rest = CNULL;
1.1 dm 649: else
1.18 millert 650: rest = NULL;
1.1 dm 651: if (pw == NULL || strcmp(pw->pw_name, file) != 0) {
652: if ((pw = getpwnam(file)) == NULL) {
653: error("%s: unknown user name", file);
1.18 millert 654: if (rest != NULL)
655: *rest = '/';
1.1 dm 656: return(NULL);
657: }
658: }
1.18 millert 659: if (rest != NULL)
660: *rest = '/';
661: pw_dir = pw->pw_dir;
662: }
663: if ((len = strlcpy(ebuf, pw_dir, ebufsize)) >= ebufsize)
664: goto notilde;
665: pw_dir = ebuf + len;
666: if (rest != NULL) {
667: pw_dir++;
668: if ((len = strlcat(ebuf, rest, ebufsize)) >= ebufsize)
669: goto notilde;
1.1 dm 670: }
1.18 millert 671: return(pw_dir);
1.1 dm 672: }
673:
674: #if defined(DIRECT_RCMD)
675: /*
676: * Set our effective user id to the user running us.
677: * This should be the uid we do most of our work as.
678: */
1.20 millert 679: int
680: becomeuser(void)
1.1 dm 681: {
682: int r = 0;
683:
684: #if defined(HAVE_SAVED_IDS)
685: r = seteuid(userid);
686: #else
687: r = setreuid(0, userid);
688: #endif /* HAVE_SAVED_IDS */
689:
690: if (r < 0)
1.20 millert 691: error("becomeuser %u failed: %s (ruid = %u euid = %u)",
1.1 dm 692: userid, SYSERR, getuid(), geteuid());
693:
694: return(r);
695: }
696: #endif /* DIRECT_RCMD */
697:
698: #if defined(DIRECT_RCMD)
699: /*
700: * Set our effective user id to "root" (uid = 0)
701: */
1.20 millert 702: int
703: becomeroot(void)
1.1 dm 704: {
705: int r = 0;
706:
707: #if defined(HAVE_SAVED_IDS)
708: r = seteuid(0);
709: #else
710: r = setreuid(userid, 0);
711: #endif /* HAVE_SAVED_IDS */
712:
713: if (r < 0)
1.16 deraadt 714: error("becomeroot failed: %s (ruid = %u euid = %u)",
1.1 dm 715: SYSERR, getuid(), geteuid());
716:
717: return(r);
718: }
719: #endif /* DIRECT_RCMD */
720:
721: /*
722: * Set access and modify times of a given file
723: */
1.20 millert 724: int
725: setfiletime(char *file, time_t atime, time_t mtime)
1.1 dm 726: {
727: #if SETFTIME_TYPE == SETFTIME_UTIMES
728: struct timeval tv[2];
729:
730: if (atime != 0 && mtime != 0) {
731: tv[0].tv_sec = atime;
732: tv[1].tv_sec = mtime;
733: tv[0].tv_usec = tv[1].tv_usec = (time_t) 0;
734: return(utimes(file, tv));
735: } else /* Set to current time */
1.6 millert 736: return(utimes(file, NULL));
1.1 dm 737:
738: #endif /* SETFTIME_UTIMES */
739:
740: #if SETFTIME_TYPE == SETFTIME_UTIME
741: struct utimbuf utbuf;
742:
743: if (atime != 0 && mtime != 0) {
744: utbuf.actime = atime;
745: utbuf.modtime = mtime;
746: return(utime(file, &utbuf));
747: } else /* Set to current time */
1.6 millert 748: return(utime(file, NULL));
1.1 dm 749: #endif /* SETFTIME_UTIME */
750:
751: #if !defined(SETFTIME_TYPE)
752: There is no "SETFTIME_TYPE" defined!
753: #endif /* SETFTIME_TYPE */
754: }
755:
756: /*
757: * Get version info
758: */
1.20 millert 759: char *
760: getversion(void)
1.1 dm 761: {
762: static char buff[BUFSIZ];
763:
1.20 millert 764: (void) snprintf(buff, sizeof(buff),
1.1 dm 765: "Version %s.%d (%s) - Protocol Version %d, Release %s, Patch level %d",
766: DISTVERSION, PATCHLEVEL, DISTSTATUS,
767: VERSION, DISTVERSION, PATCHLEVEL);
768:
769: return(buff);
770: }
771:
772: /*
773: * Execute a shell command to handle special cases.
774: * This is now common to both server and client
775: */
1.20 millert 776: void
777: runcommand(char *cmd)
1.1 dm 778: {
1.20 millert 779: ssize_t nread;
780: pid_t pid, wpid;
1.12 mpech 781: char *cp, *s;
1.1 dm 782: char sbuf[BUFSIZ], buf[BUFSIZ];
1.20 millert 783: int fd[2], status;
784:
1.1 dm 785: if (pipe(fd) < 0) {
786: error("pipe of %s failed: %s", cmd, SYSERR);
787: return;
788: }
789:
790: if ((pid = fork()) == 0) {
791: /*
792: * Return everything the shell commands print.
793: */
794: (void) close(0);
795: (void) close(1);
796: (void) close(2);
797: (void) open(_PATH_DEVNULL, O_RDONLY);
798: (void) dup(fd[PIPE_WRITE]);
799: (void) dup(fd[PIPE_WRITE]);
800: (void) close(fd[PIPE_READ]);
801: (void) close(fd[PIPE_WRITE]);
1.11 deraadt 802: (void) execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL);
1.1 dm 803: _exit(127);
804: }
805: (void) close(fd[PIPE_WRITE]);
806: s = sbuf;
807: *s++ = C_LOGMSG;
1.20 millert 808: while ((nread = read(fd[PIPE_READ], buf, sizeof(buf))) > 0) {
1.1 dm 809: cp = buf;
810: do {
811: *s++ = *cp++;
812: if (cp[-1] != '\n') {
813: if (s < (char *) &sbuf[sizeof(sbuf)-1])
814: continue;
815: *s++ = '\n';
816: }
817: /*
818: * Throw away blank lines.
819: */
820: if (s == &sbuf[2]) {
821: s--;
822: continue;
823: }
824: if (isserver)
825: (void) xwrite(rem_w, sbuf, s - sbuf);
826: else {
827: *s = CNULL;
828: message(MT_INFO, "%s", sbuf+1);
829: }
830: s = &sbuf[1];
1.20 millert 831: } while (--nread);
1.1 dm 832: }
833: if (s > (char *) &sbuf[1]) {
834: *s++ = '\n';
835: if (isserver)
836: (void) xwrite(rem_w, sbuf, s - sbuf);
837: else {
838: *s = CNULL;
839: message(MT_INFO, "%s", sbuf+1);
840: }
841: }
1.20 millert 842: while ((wpid = wait(&status)) != pid && wpid != -1)
1.1 dm 843: ;
1.20 millert 844: if (wpid == -1)
1.1 dm 845: status = -1;
846: (void) close(fd[PIPE_READ]);
847: if (status)
848: error("shell returned %d", status);
849: else if (isserver)
850: ack();
851: }
852:
853: /*
854: * Malloc with error checking
855: */
1.20 millert 856: char *
857: xmalloc(size_t amt)
1.1 dm 858: {
859: char *ptr;
860:
861: if ((ptr = (char *)malloc(amt)) == NULL)
862: fatalerr("Cannot malloc %d bytes of memory.", amt);
863:
864: return(ptr);
865: }
866:
867: /*
868: * realloc with error checking
869: */
1.20 millert 870: char *
871: xrealloc(char *baseptr, size_t amt)
1.1 dm 872: {
873: char *new;
874:
875: if ((new = (char *)realloc(baseptr, amt)) == NULL)
876: fatalerr("Cannot realloc %d bytes of memory.", amt);
877:
878: return(new);
879: }
880:
881: /*
882: * calloc with error checking
883: */
1.20 millert 884: char *
885: xcalloc(size_t num, size_t esize)
1.1 dm 886: {
887: char *ptr;
888:
889: if ((ptr = (char *)calloc(num, esize)) == NULL)
890: fatalerr("Cannot calloc %d * %d = %d bytes of memory.",
891: num, esize, num * esize);
892:
893: return(ptr);
1.8 millert 894: }
895:
896: /*
897: * Strdup with error checking
898: */
1.20 millert 899: char *
900: xstrdup(const char *str)
1.8 millert 901: {
1.20 millert 902: size_t len = strlen(str) + 1;
903: char *nstr = (char *) malloc(len);
1.8 millert 904:
1.20 millert 905: if (nstr == NULL)
906: fatalerr("Cannot malloc %u bytes of memory.", len);
1.8 millert 907:
1.20 millert 908: return(memcpy(nstr, str, len));
1.1 dm 909: }
910:
911: /*
912: * Private version of basename()
913: */
1.20 millert 914: char *
915: xbasename(char *path)
1.1 dm 916: {
1.12 mpech 917: char *cp;
1.1 dm 918:
1.20 millert 919: if ((cp = strrchr(path, '/')) != NULL)
1.1 dm 920: return(cp+1);
921: else
922: return(path);
923: }
924:
925: /*
1.10 provos 926: * Take a colon (':') separated path to a file and
1.1 dm 927: * search until a component of that path is found and
928: * return the found file name.
929: */
1.20 millert 930: char *
931: searchpath(char *path)
1.1 dm 932: {
1.12 mpech 933: char *file;
1.19 millert 934: char *space;
935: int found;
1.1 dm 936: struct stat statbuf;
937:
1.19 millert 938: for (found = 0; !found && (file = strsep(&path, ":")) != NULL; ) {
939: if ((space = strchr(file, ' ')) != NULL)
940: *space = CNULL;
941: found = stat(file, &statbuf) == 0;
942: if (space)
943: *space = ' '; /* Put back what we zapped */
1.1 dm 944: }
1.19 millert 945: return (file);
1.1 dm 946: }
947:
948: /*
949: * Set line buffering.
950: */
1.20 millert 951: int
952: mysetlinebuf(FILE *fp)
1.1 dm 953: {
954: #if SETBUF_TYPE == SETBUF_SETLINEBUF
1.20 millert 955: return(setlinebuf(fp));
1.1 dm 956: #endif /* SETBUF_SETLINEBUF */
957: #if SETBUF_TYPE == SETBUF_SETVBUF
1.20 millert 958: return(setvbuf(stdout, NULL, _IOLBF, BUFSIZ));
1.1 dm 959: #endif /* SETBUF_SETVBUF */
960: #if !defined(SETBUF_TYPE)
961: No SETBUF_TYPE is defined!
962: #endif /* SETBUF_TYPE */
963: }