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