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

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