[BACK]Return to identd.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / libexec / identd

Annotation of src/libexec/identd/identd.c, Revision 1.22

1.22    ! christos    1: /* $NetBSD: identd.c,v 1.21 2004/01/31 22:03:31 christos Exp $ */
1.8       mrg         2:
1.1       cgd         3: /*
1.20      christos    4:  * identd.c - TCP/IP Ident protocol server.
                      5:  *
                      6:  * This software is in the public domain.
                      7:  * Written by Peter Postma <peter@pointless.nl>
                      8:  */
                      9:
                     10: #include <sys/types.h>
                     11: #include <sys/socket.h>
                     12: #include <sys/stat.h>
                     13: #include <sys/param.h>
                     14: #include <sys/sysctl.h>
                     15: #include <sys/wait.h>
                     16:
                     17: #include <netinet/in.h>
                     18: #include <netinet/ip_var.h>
                     19: #include <netinet/tcp.h>
                     20: #include <netinet/tcp_timer.h>
                     21: #include <netinet/tcp_var.h>
                     22:
                     23: #include <arpa/inet.h>
1.9       msaitoh    24:
                     25: #include <ctype.h>
1.20      christos   26: #include <err.h>
1.9       msaitoh    27: #include <errno.h>
1.20      christos   28: #include <fcntl.h>
                     29: #include <grp.h>
1.9       msaitoh    30: #include <netdb.h>
1.20      christos   31: #include <poll.h>
                     32: #include <pwd.h>
1.9       msaitoh    33: #include <signal.h>
1.20      christos   34: #include <stdio.h>
                     35: #include <stdlib.h>
                     36: #include <string.h>
                     37: #include <syslog.h>
                     38: #include <unistd.h>
                     39:
1.22    ! christos   40: __RCSID("$NetBSD: identd.c,v 1.21 2004/01/31 22:03:31 christos Exp $");
1.21      christos   41:
1.20      christos   42: #define OPSYS_NAME      "UNIX"
                     43: #define IDENT_SERVICE   "auth"
                     44: #define TIMEOUT         30      /* seconds */
                     45:
                     46: static int   idhandle(int, const char *, const char *, const char *,
                     47:                const char *, int);
                     48: static void  idparse(int, int, int, const char *, const char *, const char *);
                     49: static void  iderror(int, int, int, const char *);
                     50: static const char *gethost(struct sockaddr_storage *);
                     51: static int  *socketsetup(const char *, const char *, int);
                     52: static int   sysctl_getuid(struct sockaddr_storage *, socklen_t, uid_t *);
                     53: static int   check_noident(const char *);
                     54: static int   check_userident(const char *, char *, size_t);
                     55: static void  random_string(char *, size_t);
                     56: static void  change_format(const char *, struct passwd *, char *, size_t);
                     57: static void  timeout_handler(int);
                     58: static void  waitchild(int);
                     59: static void  fatal(const char *);
                     60:
                     61: static int   bflag, eflag, fflag, Fflag, iflag, Iflag;
                     62: static int   lflag, Lflag, nflag, Nflag, rflag;
                     63:
                     64: int
                     65: main(int argc, char *argv[])
                     66: {
                     67:        int IPv4or6, ch, *socks, timeout;
                     68:        char *address, *charset, *fmt;
                     69:        const char *osname, *portno;
                     70:        char *p;
                     71:        char user[LOGIN_NAME_MAX];
                     72:        struct group *grp;
                     73:        struct passwd *pw;
                     74:        gid_t gid;
                     75:        uid_t uid;
                     76:
                     77:        IPv4or6 = AF_UNSPEC;
                     78:        osname = OPSYS_NAME;
                     79:        portno = IDENT_SERVICE;
                     80:        timeout = TIMEOUT;
                     81:        address = NULL;
                     82:        charset = NULL;
                     83:        fmt = NULL;
                     84:        socks = NULL;
                     85:        gid = uid = 0;
                     86:        bflag = eflag = fflag = Fflag = iflag = Iflag = 0;
                     87:        lflag = Lflag = nflag = Nflag = rflag = 0;
                     88:
                     89:        /* Started from a tty? then run as daemon */
                     90:        if (isatty(0))
                     91:                bflag = 1;
                     92:
                     93:        /* Parse arguments */
                     94:        while ((ch = getopt(argc, argv, "46a:bceF:f:g:IiL:lNno:p:rt:u:")) != -1)
                     95:                switch (ch) {
                     96:                case '4':
                     97:                        IPv4or6 = AF_INET;
                     98:                        break;
                     99:                case '6':
                    100:                        IPv4or6 = AF_INET6;
                    101:                        break;
                    102:                case 'a':
                    103:                        address = optarg;
                    104:                        break;
                    105:                case 'b':
                    106:                        bflag = 1;
                    107:                        break;
                    108:                case 'c':
                    109:                        charset = optarg;
                    110:                        break;
                    111:                case 'e':
                    112:                        eflag = 1;
                    113:                        break;
                    114:                case 'F':
                    115:                        Fflag = 1;
                    116:                        fmt = optarg;
                    117:                        break;
                    118:                case 'f':
                    119:                        fflag = 1;
                    120:                        (void)strlcpy(user, optarg, sizeof(user));
                    121:                        break;
                    122:                case 'g':
                    123:                        gid = (gid_t)strtol(optarg, &p, 0);
                    124:                        if (*p != '\0') {
                    125:                                if ((grp = getgrnam(optarg)) != NULL)
                    126:                                        gid = grp->gr_gid;
                    127:                                else
                    128:                                        errx(1, "No such group '%s'", optarg);
                    129:                        }
                    130:                        break;
                    131:                case 'I':
                    132:                        Iflag = 1;
                    133:                        /* FALLTHROUGH */
                    134:                case 'i':
                    135:                        iflag = 1;
                    136:                        break;
                    137:                case 'L':
                    138:                        Lflag = 1;
                    139:                        (void)strlcpy(user, optarg, sizeof(user));
                    140:                        break;
                    141:                case 'l':
                    142:                        lflag = 1;
                    143:                        break;
                    144:                case 'N':
                    145:                        Nflag = 1;
                    146:                        break;
                    147:                case 'n':
                    148:                        nflag = 1;
                    149:                        break;
                    150:                case 'o':
                    151:                        osname = optarg;
                    152:                        break;
                    153:                case 'p':
                    154:                        portno = optarg;
                    155:                        break;
                    156:                case 'r':
                    157:                        rflag = 1;
                    158:                        break;
                    159:                case 't':
                    160:                        timeout = (int)strtol(optarg, &p, 0);
                    161:                        if (*p != '\0')
                    162:                                errx(1, "Invalid timeout value '%s'", optarg);
                    163:                        break;
                    164:                case 'u':
                    165:                        uid = (uid_t)strtol(optarg, &p, 0);
                    166:                        if (*p != '\0') {
                    167:                                if ((pw = getpwnam(optarg)) != NULL) {
                    168:                                        uid = pw->pw_uid;
                    169:                                        gid = pw->pw_gid;
                    170:                                } else
                    171:                                        errx(1, "No such user '%s'", optarg);
                    172:                        }
                    173:                        break;
                    174:                default:
                    175:                        exit(1);
                    176:                }
                    177:
                    178:        if (lflag)
                    179:                openlog("identd", LOG_PID, LOG_DAEMON);
                    180:
                    181:        /* Setup sockets if -b flag */
                    182:        if (bflag) {
                    183:                socks = socketsetup(address, portno, IPv4or6);
                    184:                if (socks == NULL)
                    185:                        return 1;
                    186:        }
                    187:
                    188:        /* Switch to another uid/gid ? */
                    189:        if (gid && setgid(gid) == -1) {
                    190:                if (lflag)
                    191:                        syslog(LOG_ERR, "setgid: %m");
                    192:                if (bflag)
                    193:                        warn("setgid");
                    194:                exit(1);
                    195:        }
                    196:        if (uid && setuid(uid) == -1) {
                    197:                if (lflag)
                    198:                        syslog(LOG_ERR, "setuid: %m");
                    199:                if (bflag)
                    200:                        warn("setuid");
                    201:                exit(1);
                    202:        }
                    203:
                    204:        /* Daemonize, setup pollfds and start mainloop if -b flag */
                    205:        if (bflag) {
                    206:                int fd, i, nfds, rv;
                    207:                struct pollfd *rfds;
                    208:
                    209:                (void)signal(SIGCHLD, waitchild);
                    210:                (void)daemon(0, 0);
                    211:
                    212:                rfds = malloc(*socks * sizeof(struct pollfd));
                    213:                if (rfds == NULL)
                    214:                        fatal("malloc");
                    215:                nfds = *socks;
                    216:                for (i = 0; i < nfds; i++) {
                    217:                        rfds[i].fd = socks[i+1];
                    218:                        rfds[i].events = POLLIN;
                    219:                        rfds[i].revents = 0;
                    220:                }
                    221:                /* Mainloop for daemon */
                    222:                for (;;) {
                    223:                        rv = poll(rfds, nfds, INFTIM);
                    224:                        if (rv < 0 && errno == EINTR)
                    225:                                continue;
                    226:                        if (rv < 0)
                    227:                                fatal("poll");
                    228:                        for (i = 0; i < nfds; i++) {
                    229:                                if (rfds[i].revents & POLLIN) {
                    230:                                        fd = accept(rfds[i].fd, NULL, NULL);
                    231:                                        if (fd < 0) {
                    232:                                                if (lflag)
                    233:                                                        syslog(LOG_ERR,
                    234:                                                            "accept: %m");
                    235:                                                continue;
                    236:                                        }
                    237:                                        switch (fork()) {
                    238:                                        case -1:        /* error */
                    239:                                                if (lflag)
                    240:                                                        syslog(LOG_ERR,
                    241:                                                            "fork: %m");
                    242:                                                (void)sleep(1);
                    243:                                                break;
                    244:                                        case 0:         /* child */
                    245:                                                (void)idhandle(fd, charset,
                    246:                                                    fmt, osname, user, timeout);
                    247:                                                _exit(0);
                    248:                                        default:        /* parent */
                    249:                                                (void)close(fd);
                    250:                                        }
                    251:                                }
                    252:                        }
                    253:                }
                    254:        } else
                    255:                (void)idhandle(STDIN_FILENO, charset, fmt, osname, user,
                    256:                    timeout);
                    257:
                    258:        return 0;
                    259: }
                    260:
                    261: static int
                    262: idhandle(int fd, const char *charset, const char *fmt, const char *osname,
                    263:     const char *user, int timeout)
                    264: {
                    265:        struct sockaddr_storage ss[2];
1.22    ! christos  266:        char userbuf[LOGIN_NAME_MAX];   /* actual user name (or numeric uid) */
        !           267:        char idbuf[LOGIN_NAME_MAX];     /* name to be used in response */
1.20      christos  268:        char buf[BUFSIZ], *p;
                    269:        int n, lport, fport;
                    270:        struct passwd *pw;
                    271:        socklen_t len;
                    272:        uid_t uid;
                    273:
                    274:        lport = fport = 0;
                    275:
                    276:        (void)strlcpy(idbuf, user, sizeof(idbuf));
                    277:        (void)signal(SIGALRM, timeout_handler);
                    278:        (void)alarm(timeout);
                    279:
                    280:        /* Get foreign internet address */
                    281:        len = sizeof(ss[0]);
                    282:        if (getpeername(fd, (struct sockaddr *)&ss[0], &len) < 0)
                    283:                fatal("getpeername");
                    284:
                    285:        if (lflag)
                    286:                syslog(LOG_INFO, "Connection from %s", gethost(&ss[0]));
                    287:
                    288:        /* Get local internet address */
                    289:        len = sizeof(ss[1]);
                    290:        if (getsockname(fd, (struct sockaddr *)&ss[1], &len) < 0)
                    291:                fatal("getsockname");
                    292:
                    293:        /* Be sure to have the same address family's */
                    294:        if (ss[0].ss_family != ss[1].ss_family) {
                    295:                if (lflag)
                    296:                        syslog(LOG_ERR, "Foreign/local AF are different!");
                    297:                return 1;
                    298:        }
                    299:
                    300:        /* Receive data from the client */
                    301:        if ((n = recv(fd, buf, sizeof(buf) - 1, 0)) < 0) {
                    302:                fatal("recv");
                    303:        } else if (n == 0) {
                    304:                if (lflag)
                    305:                        syslog(LOG_NOTICE, "recv: EOF");
                    306:                iderror(fd, 0, 0, "UNKNOWN-ERROR");
                    307:                return 1;
                    308:        }
                    309:        buf[n] = '\0';
                    310:
                    311:        /* Get local and remote ports from the received data */
                    312:        p = buf;
                    313:        while (*p != '\0' && isspace(*p))
                    314:                p++;
                    315:        if ((p = strtok(p, " \t,")) != NULL) {
                    316:                lport = atoi(p);
                    317:                if ((p = strtok(NULL, " \t,")) != NULL)
                    318:                        fport = atoi(p);
                    319:        }
                    320:
                    321:        /* Are the ports valid? */
                    322:        if (lport < 1 || lport > 65535 || fport < 1 || fport > 65535) {
                    323:                if (lflag)
                    324:                        syslog(LOG_NOTICE, "Invalid port(s): %d, %d from %s",
                    325:                            lport, fport, gethost(&ss[0]));
                    326:                iderror(fd, 0, 0, eflag ? "UNKNOWN-ERROR" : "INVALID-PORT");
                    327:                return 1;
                    328:        }
                    329:
                    330:        /* If there is a 'lie' user enabled, then handle it now and quit */
                    331:        if (Lflag) {
                    332:                if (lflag)
                    333:                        syslog(LOG_NOTICE, "Lying with name %s to %s",
                    334:                            idbuf, gethost(&ss[0]));
                    335:                idparse(fd, lport, fport, charset, osname, idbuf);
                    336:                return 0;
                    337:        }
                    338:
                    339:        /* Protocol dependent stuff */
                    340:        switch (ss[0].ss_family) {
                    341:        case AF_INET:
                    342:                ((struct sockaddr_in *)&ss[0])->sin_port = htons(fport);
                    343:                ((struct sockaddr_in *)&ss[1])->sin_port = htons(lport);
                    344:                break;
                    345:        case AF_INET6:
                    346:                ((struct sockaddr_in6 *)&ss[0])->sin6_port = htons(fport);
                    347:                ((struct sockaddr_in6 *)&ss[1])->sin6_port = htons(lport);
                    348:                break;
                    349:        default:
                    350:                if (lflag)
                    351:                        syslog(LOG_ERR, "Unsupported protocol, proto no. %d",
                    352:                            ss[0].ss_family);
                    353:                return 1;
                    354:        }
                    355:
                    356:        /* Do sysctl call */
                    357:        if (sysctl_getuid(ss, sizeof(ss), &uid) == -1) {
                    358:                if (lflag)
                    359:                        syslog(LOG_ERR, "sysctl: %m");
                    360:                if (fflag) {
                    361:                        if (lflag)
                    362:                                syslog(LOG_NOTICE, "Using fallback name %s "
                    363:                                    "to %s", idbuf, gethost(&ss[0]));
                    364:                        idparse(fd, lport, fport, charset, osname, idbuf);
                    365:                        return 0;
                    366:                }
                    367:                iderror(fd, lport, fport, eflag ? "UNKNOWN-ERROR" : "NO-USER");
                    368:                return 1;
                    369:        }
                    370:
1.22    ! christos  371:        /* Fill in userbuf with user name if possible, else numeric uid */
1.20      christos  372:        if ((pw = getpwuid(uid)) == NULL) {
                    373:                if (lflag)
                    374:                        syslog(LOG_ERR, "Couldn't map uid (%u) to name", uid);
1.22    ! christos  375:                (void)snprintf(userbuf, sizeof(userbuf), "%u", uid);
        !           376:        } else {
        !           377:                if (lflag)
        !           378:                    syslog(LOG_INFO, "Successfull lookup: %d, %d: %s for %s",
        !           379:                        lport, fport, pw->pw_name, gethost(&ss[0]));
        !           380:                (void)strlcpy(userbuf, pw->pw_name, sizeof(userbuf));
1.20      christos  381:        }
                    382:
                    383:        /* No ident enabled? */
1.22    ! christos  384:        if (Nflag && pw && check_noident(pw->pw_dir)) {
1.20      christos  385:                if (lflag)
                    386:                        syslog(LOG_NOTICE, "Returning HIDDEN-USER for user %s"
                    387:                            " to %s", pw->pw_name, gethost(&ss[0]));
                    388:                iderror(fd, lport, fport, "HIDDEN-USER");
                    389:                return 1;
                    390:        }
                    391:
                    392:        /* User ident enabled ? */
1.22    ! christos  393:        if (iflag && pw && check_userident(pw->pw_dir, idbuf, sizeof(idbuf))) {
1.20      christos  394:                if (!Iflag) {
1.22    ! christos  395:                        if ((strspn(idbuf, "0123456789") &&
1.20      christos  396:                            getpwuid(atoi(idbuf)) != NULL)
1.22    ! christos  397:                            || (getpwnam(idbuf) != NULL)) {
        !           398:                                if (lflag)
        !           399:                                        syslog(LOG_NOTICE,
        !           400:                                            "Ignoring user-specified '%s' for "
        !           401:                                            "user %s", idbuf, userbuf);
1.20      christos  402:                                (void)strlcpy(idbuf, userbuf, sizeof(idbuf));
1.22    ! christos  403:                        }
1.20      christos  404:                }
                    405:                if (lflag)
1.22    ! christos  406:                        syslog(LOG_NOTICE, "Returning user-specified '%s' for "
1.20      christos  407:                            "user %s to %s", idbuf, userbuf, gethost(&ss[0]));
                    408:                idparse(fd, lport, fport, charset, osname, idbuf);
                    409:                return 0;
                    410:        }
                    411:
                    412:        /* Send random crap? */
                    413:        if (rflag) {
                    414:                /* Random number or string? */
                    415:                if (nflag)
                    416:                        (void)snprintf(idbuf, sizeof(idbuf), "%u",
                    417:                            (unsigned int)(arc4random() % 65535));
                    418:                else
                    419:                        random_string(idbuf, sizeof(idbuf));
                    420:
                    421:                if (lflag)
                    422:                        syslog(LOG_NOTICE, "Returning random '%s' for user %s"
1.22    ! christos  423:                            " to %s", idbuf, userbuf, gethost(&ss[0]));
1.20      christos  424:                idparse(fd, lport, fport, charset, osname, idbuf);
                    425:                return 0;
                    426:        }
                    427:
                    428:        /* Return number? */
                    429:        if (nflag)
                    430:                (void)snprintf(idbuf, sizeof(idbuf), "%u", uid);
                    431:        else
1.22    ! christos  432:                (void)strlcpy(idbuf, userbuf, sizeof(idbuf));
1.20      christos  433:
                    434:        if (Fflag) {
                    435:                /* RFC 1413 says that 512 is the limit */
                    436:                change_format(fmt, pw, buf, 512);
                    437:                idparse(fd, lport, fport, charset, osname, buf);
                    438:        } else
                    439:                idparse(fd, lport, fport, charset, osname, idbuf);
                    440:
                    441:        return 0;
                    442: }
                    443:
                    444: /* Send/parse the ident result */
                    445: static void
                    446: idparse(int fd, int lport, int fport, const char *charset, const char *osname,
                    447:     const char *user)
                    448: {
                    449:        char *p;
1.9       msaitoh   450:
1.20      christos  451:        if (asprintf(&p, "%d , %d : USERID : %s%s%s : %s\r\n", lport, fport,
                    452:            osname, charset ? " , " : "", charset ? charset : "", user) < 0)
                    453:                fatal("asprintf");
                    454:        if (send(fd, p, strlen(p), 0) < 0) {
                    455:                free(p);
                    456:                fatal("send");
                    457:        }
                    458:        free(p);
                    459: }
1.1       cgd       460:
1.20      christos  461: /* Return a specified ident error */
                    462: static void
                    463: iderror(int fd, int lport, int fport, const char *error)
                    464: {
                    465:        char *p;
1.1       cgd       466:
1.20      christos  467:        if (asprintf(&p, "%d , %d : ERROR : %s\r\n", lport, fport, error) < 0)
                    468:                fatal("asprintf");
                    469:        if (send(fd, p, strlen(p), 0) < 0) {
                    470:                free(p);
                    471:                fatal("send");
                    472:        }
                    473:        free(p);
                    474: }
1.1       cgd       475:
1.20      christos  476: /* Return the IP address of the connecting host */
                    477: static const char *
                    478: gethost(struct sockaddr_storage *ss)
                    479: {
                    480:        static char host[NI_MAXHOST];
1.8       mrg       481:
1.20      christos  482:        if (getnameinfo((struct sockaddr *)ss, ss->ss_len, host,
                    483:            sizeof(host), NULL, 0, NI_NUMERICHOST) == 0)
                    484:                return host;
1.9       msaitoh   485:
1.20      christos  486:        return "UNKNOWN";
1.9       msaitoh   487: }
1.1       cgd       488:
1.20      christos  489: /* Setup sockets, for daemon mode */
                    490: static int *
                    491: socketsetup(const char *address, const char *port, int af)
                    492: {
                    493:        struct addrinfo hints, *res, *res0;
                    494:        int error, maxs, *s, *socks, y = 1;
                    495:        const char *cause = NULL;
                    496:
                    497:        (void)memset(&hints, 0, sizeof(hints));
                    498:        hints.ai_flags = AI_PASSIVE;
                    499:        hints.ai_family = af;
                    500:        hints.ai_socktype = SOCK_STREAM;
                    501:        error = getaddrinfo(address, port, &hints, &res0);
                    502:        if (error) {
                    503:                if (lflag)
                    504:                        syslog(LOG_ERR, "getaddrinfo: %s", gai_strerror(error));
                    505:                errx(1, "%s", gai_strerror(error));
                    506:                /*NOTREACHED*/
                    507:        }
                    508:
                    509:        /* Count max number of sockets we may open */
                    510:        for (maxs = 0, res = res0; res != NULL; res = res->ai_next)
                    511:                maxs++;
                    512:
                    513:        socks = malloc((maxs + 1) * sizeof(int));
                    514:        if (socks == NULL) {
                    515:                if (lflag)
                    516:                        syslog(LOG_ERR, "malloc: %m");
                    517:                err(1, "malloc");
                    518:                /* NOTREACHED */
                    519:        }
                    520:
                    521:        *socks = 0;
                    522:        s = socks + 1;
                    523:        for (res = res0; res != NULL; res = res->ai_next) {
                    524:                *s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
                    525:                if (*s < 0) {
                    526:                        cause = "socket";
                    527:                        continue;
                    528:                }
                    529:                (void)setsockopt(*s, SOL_SOCKET, SO_REUSEADDR, &y, sizeof(y));
                    530:                if (bind(*s, res->ai_addr, res->ai_addrlen) < 0) {
                    531:                        cause = "bind";
                    532:                        (void)close(*s);
                    533:                        continue;
                    534:                }
                    535:                if (listen(*s, 5) < 0) {
                    536:                        cause = "listen";
                    537:                        (void)close(*s);
                    538:                        continue;
                    539:                }
                    540:                *socks = *socks + 1;
                    541:                s++;
                    542:        }
                    543:
                    544:        if (*socks == 0) {
                    545:                free(socks);
                    546:                if (lflag)
                    547:                        syslog(LOG_ERR, "%s: %m", cause);
                    548:                err(1, "%s", cause);
                    549:                /* NOTREACHED */
                    550:        }
                    551:        if (res0)
                    552:                freeaddrinfo(res0);
1.9       msaitoh   553:
1.20      christos  554:        return socks;
1.1       cgd       555: }
                    556:
1.20      christos  557: /* Return the UID for the connection owner */
                    558: static int
                    559: sysctl_getuid(struct sockaddr_storage *ss, socklen_t len, uid_t *uid)
1.1       cgd       560: {
1.20      christos  561:        int mib[4];
                    562:        uid_t myuid;
                    563:        size_t uidlen;
                    564:
                    565:        uidlen = sizeof(myuid);
                    566:
                    567:        mib[0] = CTL_NET;
                    568:        mib[1] = ss->ss_family;
                    569:        mib[2] = IPPROTO_TCP;
                    570:        mib[3] = TCPCTL_IDENT;
                    571:
                    572:        if (sysctl(mib, sizeof(mib)/ sizeof(int), &myuid, &uidlen, ss, len) < 0)
                    573:                return -1;
                    574:        *uid = myuid;
                    575:
                    576:        return 0;
1.1       cgd       577: }
1.9       msaitoh   578:
1.20      christos  579: /* Check if a .noident file exists in the user home directory */
                    580: static int
                    581: check_noident(const char *homedir)
                    582: {
                    583:        struct stat sb;
                    584:        char *path;
                    585:        int ret;
                    586:
                    587:        if (homedir == NULL)
                    588:                return 0;
                    589:        if (asprintf(&path, "%s/.noident", homedir) < 0)
                    590:                return 0;
                    591:        ret = stat(path, &sb);
                    592:
                    593:        free(path);
                    594:        return (ret == 0);
                    595: }
1.1       cgd       596:
                    597: /*
1.20      christos  598:  * Check if a .ident file exists in the user home directory and
                    599:  * return the contents of that file.
                    600:  */
                    601: static int
                    602: check_userident(const char *homedir, char *username, size_t len)
                    603: {
                    604:        struct stat sb;
                    605:        char *path, *p;
                    606:        int fd, n;
                    607:
                    608:        if (len == 0 || homedir == NULL)
                    609:                return 0;
                    610:        if (asprintf(&path, "%s/.ident", homedir) < 0)
                    611:                return 0;
                    612:        if ((fd = open(path, O_RDONLY|O_NONBLOCK|O_NOFOLLOW, 0)) < 0) {
                    613:                free(path);
                    614:                return 0;
                    615:        }
                    616:        if (fstat(fd, &sb) < 0 || !S_ISREG(sb.st_mode)) {
                    617:                (void)close(fd);
                    618:                free(path);
                    619:                return 0;
                    620:        }
                    621:        if ((n = read(fd, username, len - 1)) < 1) {
                    622:                (void)close(fd);
                    623:                free(path);
                    624:                return 0;
                    625:        }
                    626:        username[n] = '\0';
                    627:
                    628:        if ((p = strpbrk(username, "\r\n")))
                    629:                *p = '\0';
                    630:
                    631:        (void)close(fd);
                    632:        free(path);
                    633:        return 1;
1.1       cgd       634: }
                    635:
1.20      christos  636: /* Generate a random string */
                    637: static void
                    638: random_string(char *str, size_t len)
                    639: {
                    640:        static const char chars[] = "abcdefghijklmnopqrstuvwxyz1234567890";
                    641:        char *p;
                    642:
                    643:        if (len == 0)
                    644:                return;
                    645:        for (p = str; len > 1; len--)
                    646:                *p++ = chars[arc4random() % (sizeof(chars) - 1)];
                    647:        *p = '\0';
                    648: }
1.1       cgd       649:
1.20      christos  650: /* Change the output format */
                    651: static void
                    652: change_format(const char *format, struct passwd *pw, char *dest, size_t len)
                    653: {
                    654:        struct group *gr;
                    655:        const char *cp;
                    656:        char **gmp;
                    657:        int bp;
                    658:
                    659:        if (len == 0)
                    660:                return;
                    661:        if ((gr = getgrgid(pw->pw_gid)) == NULL)
                    662:                return;
                    663:
                    664:        for (bp = 0, cp = format; *cp != '\0' && bp < 490; cp++) {
                    665:                if (*cp != '%') {
                    666:                        dest[bp++] = *cp;
                    667:                        continue;
1.9       msaitoh   668:                }
1.20      christos  669:                if (*++cp == '\0')
                    670:                        break;
                    671:                switch (*cp) {
                    672:                case 'u':
                    673:                        (void)snprintf(&dest[bp], len - bp, "%.*s", 490 - bp,
                    674:                            pw->pw_name);
                    675:                        break;
                    676:                case 'U':
                    677:                        (void)snprintf(&dest[bp], len - bp, "%d", pw->pw_uid);
                    678:                        break;
                    679:                case 'g':
                    680:                        (void)snprintf(&dest[bp], len - bp, "%.*s", 490 - bp,
                    681:                            gr->gr_name);
                    682:                        break;
                    683:                case 'G':
                    684:                        (void)snprintf(&dest[bp], len - bp, "%d", gr->gr_gid);
                    685:                        break;
                    686:                case 'l':
                    687:                        (void)snprintf(&dest[bp], len - bp, "%.*s", 490 - bp,
                    688:                            gr->gr_name);
                    689:                        bp += strlen(&dest[bp]);
                    690:                        if (bp >= 490)
                    691:                                break;
                    692:                        setgrent();
                    693:                        while ((gr = getgrent()) != NULL) {
                    694:                                if (gr->gr_gid == pw->pw_gid)
                    695:                                        continue;
                    696:                                for (gmp = gr->gr_mem; *gmp && **gmp; gmp++) {
                    697:                                        if (strcmp(*gmp, pw->pw_name) == 0) {
                    698:                                                (void)snprintf(&dest[bp],
                    699:                                                    len - bp, ",%.*s",
                    700:                                                    490 - bp, gr->gr_name);
                    701:                                                bp += strlen(&dest[bp]);
                    702:                                                break;
                    703:                                        }
                    704:                                }
                    705:                                if (bp >= 490)
                    706:                                        break;
                    707:                        }
                    708:                        endgrent();
                    709:                        break;
                    710:                case 'L':
                    711:                        (void)snprintf(&dest[bp], len - bp, "%u", gr->gr_gid);
                    712:                        bp += strlen(&dest[bp]);
                    713:                        if (bp >= 490)
                    714:                                break;
                    715:                        setgrent();
                    716:                        while ((gr = getgrent()) != NULL) {
                    717:                                if (gr->gr_gid == pw->pw_gid)
                    718:                                        continue;
                    719:                                for (gmp = gr->gr_mem; *gmp && **gmp; gmp++) {
                    720:                                        if (strcmp(*gmp, pw->pw_name) == 0) {
                    721:                                                (void)snprintf(&dest[bp],
                    722:                                                    len - bp, ",%u",
                    723:                                                    gr->gr_gid);
                    724:                                                bp += strlen(&dest[bp]);
                    725:                                                break;
                    726:                                        }
                    727:                                }
                    728:                                if (bp >= 490)
                    729:                                        break;
                    730:                        }
                    731:                        endgrent();
                    732:                        break;
                    733:                default:
                    734:                        dest[bp] = *cp;
                    735:                        dest[bp+1] = '\0';
                    736:                        break;
1.9       msaitoh   737:                }
1.20      christos  738:                bp += strlen(&dest[bp]);
                    739:        }
                    740:        if (bp >= 490) {
                    741:                (void)snprintf(&dest[490], len - 490, "...");
                    742:                bp = 493;
                    743:        }
                    744:        dest[bp] = '\0';
                    745: }
                    746:
                    747: /* Just exit when we caught SIGALRM */
                    748: static void
                    749: timeout_handler(int s)
                    750: {
                    751:        if (lflag)
                    752:                syslog(LOG_DEBUG, "SIGALRM triggered, exiting...");
                    753:        exit(1);
                    754: }
                    755:
                    756: /* This is to clean up zombie processes when in daemon mode */
                    757: static void
                    758: waitchild(int s)
                    759: {
                    760:        while (waitpid(-1, NULL, WNOHANG) > 0)
1.19      christos  761:                continue;
1.20      christos  762: }
                    763:
                    764: /* Report errno through syslog and quit */
                    765: static void
                    766: fatal(const char *func)
                    767: {
                    768:        if (lflag)
                    769:                syslog(LOG_ERR, "%s: %m", func);
1.9       msaitoh   770:        exit(1);
1.1       cgd       771: }

CVSweb <webmaster@jp.NetBSD.org>