[BACK]Return to common.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / rdist

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: }