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