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

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