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

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