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