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