Annotation of src/usr.bin/rdist/common.c, Revision 1.17
1.17 ! deraadt 1: /* $OpenBSD: common.c,v 1.16 2002/06/23 03:07:22 deraadt Exp $ */
1.3 deraadt 2:
1.1 dm 3: /*
4: * Copyright (c) 1983 Regents of the University of California.
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
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.17 ! deraadt 42: "$OpenBSD: common.c,v 1.16 2002/06/23 03:07:22 deraadt 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: */
299: static int sendcmdmsg(cmd, msg)
300: char cmd;
301: char *msg;
302: {
303: int len;
304:
305: if (rem_w < 0)
306: return(-1);
307:
308: /*
309: * All commands except C_NONE should have a newline
310: */
311: if (cmd != C_NONE && !strchr(msg + 1, '\n'))
312: (void) strcat(msg + 1, "\n");
313:
314: if (cmd == C_NONE)
315: len = strlen(msg);
316: else {
317: len = strlen(msg + 1) + 1;
318: msg[0] = cmd;
319: }
320:
321: debugmsg(DM_PROTO, ">>> Cmd = %c (\\%3.3o) Msg = \"%.*s\"",
322: cmd, cmd,
323: (cmd == C_NONE) ? len-1 : len-2,
324: (cmd == C_NONE) ? msg : msg + 1);
325:
326: return(!(xwrite(rem_w, msg, len) == len));
327: }
328:
329: /*
330: * Send a command message to the remote host.
331: * Called as sendcmd(char cmdchar, char *fmt, arg1, arg2, ...)
332: * The fmt and arg? arguments are optional.
333: */
334: #if defined(ARG_TYPE) && ARG_TYPE == ARG_STDARG
335: /*
336: * Stdarg frontend to sendcmdmsg()
337: */
338: extern int sendcmd(char cmd, char *fmt, ...)
339: {
340: static char buf[BUFSIZ];
341: va_list args;
342:
343: va_start(args, fmt);
344: if (fmt)
345: (void) vsprintf((cmd == C_NONE) ? buf : buf + 1, fmt, args);
346: else
347: buf[1] = CNULL;
348: va_end(args);
349:
350: return(sendcmdmsg(cmd, buf));
351: }
352: #endif /* ARG_TYPE == ARG_STDARG */
353:
354: #if defined(ARG_TYPE) && ARG_TYPE == ARG_VARARGS
355: /*
356: * Varargs frontend to sendcmdmsg()
357: */
358: extern int sendcmd(va_alist)
359: va_dcl
360: {
361: static char buf[BUFSIZ];
362: va_list args;
363: char cmd;
364: char *fmt;
365:
366: va_start(args);
367: /* XXX The "int" is necessary as a workaround for broken varargs */
368: cmd = (char) va_arg(args, int);
369: fmt = va_arg(args, char *);
370: if (fmt)
371: (void) vsprintf((cmd == C_NONE) ? buf : buf + 1, fmt, args);
372: else
373: buf[1] = CNULL;
374: va_end(args);
375:
376: return(sendcmdmsg(cmd, buf));
377: }
378: #endif /* ARG_TYPE == ARG_VARARGS */
379:
380: #if !defined(ARG_TYPE)
381: /*
382: * Stupid frontend to sendcmdmsg()
383: */
384: /*VARARGS2*/
385: extern int sendcmd(cmd, fmt, a1, a2, a3, a4, a5, a6, a7, a8)
386: char cmd;
387: char *fmt;
388: {
389: static char buf[BUFSIZ];
390:
391: if (fmt)
392: (void) sprintf((cmd == C_NONE) ? buf : buf + 1,
393: fmt, a1, a2, a3, a4, a5, a6, a7, a8);
394: else
395: buf[1] = CNULL;
396:
397: return(sendcmdmsg(cmd, buf));
398: }
399: #endif /* !ARG_TYPE */
400:
401: /*
402: * Internal variables and routines for reading lines from the remote.
403: */
404: static u_char rembuf[BUFSIZ];
405: static u_char *remptr;
406: static int remleft;
407:
408: #define remc() (--remleft < 0 ? remmore() : *remptr++)
409:
410: /*
411: * Back end to remote read()
412: */
413: static int remread(fd, buf, bufsiz)
414: int fd;
415: u_char *buf;
416: int bufsiz;
417: {
418: return(read(fd, (char *)buf, bufsiz));
419: }
420:
421: static int remmore()
422: {
423: (void) signal(SIGALRM, sighandler);
424: (void) alarm(rtimeout);
425:
426: remleft = remread(rem_r, rembuf, sizeof(rembuf));
427:
428: (void) alarm(0);
429:
430: if (remleft < 0)
431: return (-2); /* error */
432: if (remleft == 0)
433: return (-1); /* EOF */
434: remptr = rembuf;
435: remleft--;
436: return (*remptr++);
437: }
438:
439: /*
440: * Read an input line from the remote. Return the number of bytes
441: * stored (equivalent to strlen(p)). If `cleanup' is set, EOF at
442: * the beginning of a line is returned as EOF (-1); other EOFs, or
443: * errors, call cleanup() or lostconn(). In other words, unless
444: * the third argument is nonzero, this routine never returns failure.
445: */
446: extern int remline(buffer, space, doclean)
1.12 mpech 447: u_char *buffer;
1.1 dm 448: int space;
449: int doclean;
450: {
1.12 mpech 451: int c, left = space;
452: u_char *p = buffer;
1.1 dm 453:
454: if (rem_r < 0) {
455: error("Cannot read remote input: Remote descriptor not open.");
456: return(-1);
457: }
458:
459: while (left > 0) {
460: if ((c = remc()) < -1) { /* error */
461: if (doclean) {
462: finish();
463: /*NOTREACHED*/
464: }
465: lostconn();
466: /*NOTREACHED*/
467: }
468: if (c == -1) { /* got EOF */
469: if (doclean) {
470: if (left == space)
471: return (-1);/* signal proper EOF */
472: finish(); /* improper EOF */
473: /*NOTREACHED*/
474: }
475: lostconn();
476: /*NOTREACHED*/
477: }
478: if (c == '\n') {
479: *p = CNULL;
480:
481: if (debug) {
482: static char mbuf[BUFSIZ];
483:
1.17 ! deraadt 484: (void) snprintf(mbuf, sizeof mbuf,
1.1 dm 485: "<<< Cmd = %c (\\%3.3o) Msg = \"%s\"",
486: buffer[0], buffer[0],
487: buffer + 1);
488:
489: debugmsg(DM_PROTO, "%s", mbuf);
490: }
491:
492: return (space - left);
493: }
494: *p++ = c;
495: left--;
496: }
497:
498: /* this will probably blow the entire session */
499: error("remote input line too long");
500: p[-1] = CNULL; /* truncate */
501: return (space);
502: }
503:
504: /*
505: * Non-line-oriented remote read.
506: */
1.6 millert 507: int
1.1 dm 508: readrem(p, space)
509: char *p;
1.12 mpech 510: int space;
1.1 dm 511: {
512: if (remleft <= 0) {
513: /*
514: * Set remote time out alarm.
515: */
516: (void) signal(SIGALRM, sighandler);
517: (void) alarm(rtimeout);
518:
519: remleft = remread(rem_r, rembuf, sizeof(rembuf));
520:
521: (void) alarm(0);
522: remptr = rembuf;
523: }
524:
525: if (remleft <= 0)
526: return (remleft);
527: if (remleft < space)
528: space = remleft;
529:
530: bcopy((char *) remptr, p, space);
531:
532: remptr += space;
533: remleft -= space;
534:
535: return (space);
536: }
537:
538: /*
539: * Get the user name for the uid.
540: */
541: extern char *getusername(uid, file, opts)
542: UID_T uid;
543: char *file;
544: opt_t opts;
545: {
546: static char buf[100];
547: static UID_T lastuid = (UID_T)-1;
548: struct passwd *pwd = NULL;
549:
550: /*
551: * The value of opts may have changed so we always
552: * do the opts check.
553: */
554: if (IS_ON(opts, DO_NUMCHKOWNER)) {
1.17 ! deraadt 555: (void) snprintf(buf, sizeof buf, ":%u", uid);
1.1 dm 556: return(buf);
557: }
558:
559: /*
560: * Try to avoid getpwuid() call.
561: */
1.6 millert 562: if (lastuid == uid && buf[0] != '\0' && buf[0] != ':')
1.1 dm 563: return(buf);
564:
565: lastuid = uid;
566:
567: if ((pwd = getpwuid(uid)) == NULL) {
568: message(MT_WARNING,
1.16 deraadt 569: "%s: No password entry for uid %u", file, uid);
1.17 ! deraadt 570: (void) snprintf(buf, sizeof buf, ":%u", uid);
1.1 dm 571: } else
1.17 ! deraadt 572: (void) strlcpy(buf, pwd->pw_name, sizeof buf);
1.1 dm 573:
574: return(buf);
575: }
576:
577: /*
578: * Get the group name for the gid.
579: */
580: extern char *getgroupname(gid, file, opts)
581: GID_T gid;
582: char *file;
583: opt_t opts;
584: {
585: static char buf[100];
586: static GID_T lastgid = (GID_T)-1;
587: struct group *grp = NULL;
588:
589: /*
590: * The value of opts may have changed so we always
591: * do the opts check.
592: */
593: if (IS_ON(opts, DO_NUMCHKGROUP)) {
1.17 ! deraadt 594: (void) snprintf(buf, sizeof buf, ":%u", gid);
1.1 dm 595: return(buf);
596: }
597:
598: /*
599: * Try to avoid getgrgid() call.
600: */
1.6 millert 601: if (lastgid == gid && buf[0] != '\0' && buf[0] != ':')
1.1 dm 602: return(buf);
603:
604: lastgid = gid;
605:
606: if ((grp = (struct group *)getgrgid(gid)) == NULL) {
1.16 deraadt 607: message(MT_WARNING, "%s: No name for group %u", file, gid);
1.17 ! deraadt 608: (void) snprintf(buf, sizeof buf, ":%u", gid);
1.1 dm 609: } else
1.17 ! deraadt 610: (void) strlcpy(buf, grp->gr_name, sizeof buf);
1.1 dm 611:
612: return(buf);
613: }
614:
615: /*
616: * Read a response from the remote host.
617: */
618: extern int response()
619: {
620: static u_char resp[BUFSIZ];
621: u_char *s;
622: int n;
623:
624: debugmsg(DM_CALL, "response() start\n");
625:
626: n = remline(s = resp, sizeof(resp), 0);
627:
628: n--;
629: switch (*s++) {
630: case C_ACK:
631: debugmsg(DM_PROTO, "received ACK\n");
632: return(0);
633: case C_LOGMSG:
634: if (n > 0) {
635: message(MT_CHANGE, "%s", s);
636: return(1);
637: }
638: debugmsg(DM_PROTO, "received EMPTY logmsg\n");
639: return(0);
640: case C_NOTEMSG:
641: if (s)
642: message(MT_NOTICE, "%s", s);
643: return(response());
644:
645: default:
646: s--;
647: n++;
648: /* fall into... */
649:
650: case C_ERRMSG: /* Normal error message */
651: if (s)
652: message(MT_NERROR, "%s", s);
653: return(-1);
654:
655: case C_FERRMSG: /* Fatal error message */
656: if (s)
657: message(MT_FERROR, "%s", s);
658: finish();
659: }
660: /*NOTREACHED*/
661: }
662:
663: /*
664: * This should be in expand.c but the other routines call other modules
665: * that we don't want to load in.
666: *
667: * Expand file names beginning with `~' into the
668: * user's home directory path name. Return a pointer in buf to the
669: * part corresponding to `file'.
670: */
671: extern char *exptilde(ebuf, file)
672: char *ebuf;
1.12 mpech 673: char *file;
1.1 dm 674: {
1.12 mpech 675: char *s1, *s2, *s3;
1.1 dm 676: extern char *homedir;
677:
678: if (*file != '~') {
679: (void) strcpy(ebuf, file);
680: return(ebuf);
681: }
682: if (*++file == CNULL) {
683: s2 = homedir;
684: s3 = NULL;
685: } else if (*file == '/') {
686: s2 = homedir;
687: s3 = file;
688: } else {
689: s3 = file;
690: while (*s3 && *s3 != '/')
691: s3++;
692: if (*s3 == '/')
693: *s3 = CNULL;
694: else
695: s3 = NULL;
696: if (pw == NULL || strcmp(pw->pw_name, file) != 0) {
697: if ((pw = getpwnam(file)) == NULL) {
698: error("%s: unknown user name", file);
699: if (s3 != NULL)
700: *s3 = '/';
701: return(NULL);
702: }
703: }
704: if (s3 != NULL)
705: *s3 = '/';
706: s2 = pw->pw_dir;
707: }
1.6 millert 708: for (s1 = ebuf; (*s1++ = *s2++); )
1.1 dm 709: ;
710: s2 = --s1;
711: if (s3 != NULL) {
712: s2++;
1.6 millert 713: while ((*s1++ = *s3++))
1.1 dm 714: ;
715: }
716: return(s2);
717: }
718:
719: #if defined(DIRECT_RCMD)
720: /*
721: * Set our effective user id to the user running us.
722: * This should be the uid we do most of our work as.
723: */
724: extern int becomeuser()
725: {
726: int r = 0;
727:
728: #if defined(HAVE_SAVED_IDS)
729: r = seteuid(userid);
730: #else
731: r = setreuid(0, userid);
732: #endif /* HAVE_SAVED_IDS */
733:
734: if (r < 0)
1.16 deraadt 735: error("becomeuser %d failed: %s (ruid = %u euid = %u)",
1.1 dm 736: userid, SYSERR, getuid(), geteuid());
737:
738: return(r);
739: }
740: #endif /* DIRECT_RCMD */
741:
742: #if defined(DIRECT_RCMD)
743: /*
744: * Set our effective user id to "root" (uid = 0)
745: */
746: extern int becomeroot()
747: {
748: int r = 0;
749:
750: #if defined(HAVE_SAVED_IDS)
751: r = seteuid(0);
752: #else
753: r = setreuid(userid, 0);
754: #endif /* HAVE_SAVED_IDS */
755:
756: if (r < 0)
1.16 deraadt 757: error("becomeroot failed: %s (ruid = %u euid = %u)",
1.1 dm 758: SYSERR, getuid(), geteuid());
759:
760: return(r);
761: }
762: #endif /* DIRECT_RCMD */
763:
764: /*
765: * Set access and modify times of a given file
766: */
767: extern int setfiletime(file, atime, mtime)
768: char *file;
769: time_t atime;
770: time_t mtime;
771: {
772: #if SETFTIME_TYPE == SETFTIME_UTIMES
773: struct timeval tv[2];
774:
775: if (atime != 0 && mtime != 0) {
776: tv[0].tv_sec = atime;
777: tv[1].tv_sec = mtime;
778: tv[0].tv_usec = tv[1].tv_usec = (time_t) 0;
779: return(utimes(file, tv));
780: } else /* Set to current time */
1.6 millert 781: return(utimes(file, NULL));
1.1 dm 782:
783: #endif /* SETFTIME_UTIMES */
784:
785: #if SETFTIME_TYPE == SETFTIME_UTIME
786: struct utimbuf utbuf;
787:
788: if (atime != 0 && mtime != 0) {
789: utbuf.actime = atime;
790: utbuf.modtime = mtime;
791: return(utime(file, &utbuf));
792: } else /* Set to current time */
1.6 millert 793: return(utime(file, NULL));
1.1 dm 794: #endif /* SETFTIME_UTIME */
795:
796: #if !defined(SETFTIME_TYPE)
797: There is no "SETFTIME_TYPE" defined!
798: #endif /* SETFTIME_TYPE */
799: }
800:
801: /*
802: * Get version info
803: */
804: extern char *getversion()
805: {
806: static char buff[BUFSIZ];
807:
1.17 ! deraadt 808: (void) snprintf(buff, sizeof buff,
1.1 dm 809: "Version %s.%d (%s) - Protocol Version %d, Release %s, Patch level %d",
810: DISTVERSION, PATCHLEVEL, DISTSTATUS,
811: VERSION, DISTVERSION, PATCHLEVEL);
812:
813: return(buff);
814: }
815:
816: /*
817: * Execute a shell command to handle special cases.
818: * This is now common to both server and client
819: */
820: void runcommand(cmd)
821: char *cmd;
822: {
1.15 mpech 823: int fd[2];
1.1 dm 824: int status;
1.12 mpech 825: char *cp, *s;
1.1 dm 826: char sbuf[BUFSIZ], buf[BUFSIZ];
1.15 mpech 827: pid_t pid, i;
828:
1.1 dm 829: if (pipe(fd) < 0) {
830: error("pipe of %s failed: %s", cmd, SYSERR);
831: return;
832: }
833:
834: if ((pid = fork()) == 0) {
835: /*
836: * Return everything the shell commands print.
837: */
838: (void) close(0);
839: (void) close(1);
840: (void) close(2);
841: (void) open(_PATH_DEVNULL, O_RDONLY);
842: (void) dup(fd[PIPE_WRITE]);
843: (void) dup(fd[PIPE_WRITE]);
844: (void) close(fd[PIPE_READ]);
845: (void) close(fd[PIPE_WRITE]);
1.11 deraadt 846: (void) execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL);
1.1 dm 847: _exit(127);
848: }
849: (void) close(fd[PIPE_WRITE]);
850: s = sbuf;
851: *s++ = C_LOGMSG;
852: while ((i = read(fd[PIPE_READ], buf, sizeof(buf))) > 0) {
853: cp = buf;
854: do {
855: *s++ = *cp++;
856: if (cp[-1] != '\n') {
857: if (s < (char *) &sbuf[sizeof(sbuf)-1])
858: continue;
859: *s++ = '\n';
860: }
861: /*
862: * Throw away blank lines.
863: */
864: if (s == &sbuf[2]) {
865: s--;
866: continue;
867: }
868: if (isserver)
869: (void) xwrite(rem_w, sbuf, s - sbuf);
870: else {
871: *s = CNULL;
872: message(MT_INFO, "%s", sbuf+1);
873: }
874: s = &sbuf[1];
875: } while (--i);
876: }
877: if (s > (char *) &sbuf[1]) {
878: *s++ = '\n';
879: if (isserver)
880: (void) xwrite(rem_w, sbuf, s - sbuf);
881: else {
882: *s = CNULL;
883: message(MT_INFO, "%s", sbuf+1);
884: }
885: }
886: while ((i = wait(&status)) != pid && i != -1)
887: ;
888: if (i == -1)
889: status = -1;
890: (void) close(fd[PIPE_READ]);
891: if (status)
892: error("shell returned %d", status);
893: else if (isserver)
894: ack();
895: }
896:
897: /*
898: * Malloc with error checking
899: */
900: char *xmalloc(amt)
901: int amt;
902: {
903: char *ptr;
904: extern POINTER *malloc();
905:
906: if ((ptr = (char *)malloc(amt)) == NULL)
907: fatalerr("Cannot malloc %d bytes of memory.", amt);
908:
909: return(ptr);
910: }
911:
912: /*
913: * realloc with error checking
914: */
915: char *xrealloc(baseptr, amt)
916: char *baseptr;
917: unsigned int amt;
918: {
919: char *new;
920: extern POINTER *realloc();
921:
922: if ((new = (char *)realloc(baseptr, amt)) == NULL)
923: fatalerr("Cannot realloc %d bytes of memory.", amt);
924:
925: return(new);
926: }
927:
928: /*
929: * calloc with error checking
930: */
931: char *xcalloc(num, esize)
1.14 deraadt 932: unsigned int num;
933: unsigned int esize;
1.1 dm 934: {
935: char *ptr;
936: extern POINTER *calloc();
937:
938: if ((ptr = (char *)calloc(num, esize)) == NULL)
939: fatalerr("Cannot calloc %d * %d = %d bytes of memory.",
940: num, esize, num * esize);
941:
942: return(ptr);
1.8 millert 943: }
944:
945: /*
946: * Strdup with error checking
947: */
948: char *xstrdup(str)
949: char *str;
950: {
951: char *nstr;
952:
953: if ((nstr = strdup(str)) == NULL)
1.9 aaron 954: fatalerr("Cannot malloc %d bytes of memory.", strlen(str) + 1);
1.8 millert 955:
956: return(nstr);
1.1 dm 957: }
958:
959: /*
960: * Private version of basename()
961: */
962: extern char *xbasename(path)
963: char *path;
964: {
1.12 mpech 965: char *cp;
1.1 dm 966:
1.6 millert 967: if ((cp = strrchr(path, '/')))
1.1 dm 968: return(cp+1);
969: else
970: return(path);
971: }
972:
973: /*
1.10 provos 974: * Take a colon (':') separated path to a file and
1.1 dm 975: * search until a component of that path is found and
976: * return the found file name.
977: */
978: extern char *searchpath(path)
979: char *path;
980: {
1.12 mpech 981: char *cp;
982: char *file;
1.1 dm 983: struct stat statbuf;
984:
985: for (; ;) {
986: if (!path)
1.6 millert 987: return(NULL);
1.1 dm 988: file = path;
989: cp = strchr(path, ':');
990: if (cp) {
991: path = cp + 1;
992: *cp = CNULL;
993: } else
994: path = NULL;
995: if (stat(file, &statbuf) == 0)
996: return(file);
997: /* Put back what we zapped */
998: if (path)
999: *cp = ':';
1000: }
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: }