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

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