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

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