[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.20

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