Annotation of embedaddon/sudo/src/utmp.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (c) 2011 Todd C. Miller <Todd.Miller@courtesan.com>
        !             3:  *
        !             4:  * Permission to use, copy, modify, and distribute this software for any
        !             5:  * purpose with or without fee is hereby granted, provided that the above
        !             6:  * copyright notice and this permission notice appear in all copies.
        !             7:  *
        !             8:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !             9:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            10:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            11:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            12:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            13:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            14:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            15:  */
        !            16: 
        !            17: #include <config.h>
        !            18: 
        !            19: #include <sys/types.h>
        !            20: #include <sys/param.h>
        !            21: #include <sys/time.h>
        !            22: #include <sys/wait.h>
        !            23: #include <stdio.h>
        !            24: #ifdef STDC_HEADERS
        !            25: # include <stdlib.h>
        !            26: # include <stddef.h>
        !            27: #else
        !            28: # ifdef HAVE_STDLIB_H
        !            29: #  include <stdlib.h>
        !            30: # endif
        !            31: #endif /* STDC_HEADERS */
        !            32: #ifdef HAVE_STRING_H
        !            33: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
        !            34: #  include <memory.h>
        !            35: # endif
        !            36: # include <string.h>
        !            37: #endif /* HAVE_STRING_H */
        !            38: #ifdef HAVE_STRINGS_H
        !            39: # include <strings.h>
        !            40: #endif /* HAVE_STRINGS_H */
        !            41: #ifdef HAVE_UNISTD_H
        !            42: # include <unistd.h>
        !            43: #endif /* HAVE_UNISTD_H */
        !            44: #if TIME_WITH_SYS_TIME
        !            45: # include <time.h>
        !            46: #endif
        !            47: #ifdef HAVE_UTMPX_H
        !            48: # include <utmpx.h>
        !            49: #else
        !            50: # include <utmp.h>
        !            51: #endif /* HAVE_UTMPX_H */
        !            52: #ifdef HAVE_GETTTYENT
        !            53: # include <ttyent.h>
        !            54: #endif
        !            55: #include <fcntl.h>
        !            56: 
        !            57: #include "sudo.h"
        !            58: #include "sudo_exec.h"
        !            59: 
        !            60: /*
        !            61:  * Simplify handling of utmp vs. utmpx
        !            62:  */
        !            63: #if !defined(HAVE_GETUTXID) && defined(HAVE_GETUTID)
        !            64: # define getutxline(u) getutline(u)
        !            65: # define pututxline(u) pututline(u)
        !            66: # define setutxent     setutent(u)
        !            67: # define endutxent     endutent(u)
        !            68: #endif /* !HAVE_GETUTXID && HAVE_GETUTID */
        !            69: 
        !            70: #ifdef HAVE_GETUTXID
        !            71: typedef struct utmpx sudo_utmp_t;
        !            72: #else
        !            73: typedef struct utmp sudo_utmp_t;
        !            74: /* Older systems have ut_name, not us_user */
        !            75: # if !defined(HAVE_STRUCT_UTMP_UT_USER) && !defined(ut_user)
        !            76: #  define ut_user ut_name
        !            77: # endif
        !            78: #endif
        !            79: 
        !            80: /* HP-UX has __e_termination and __e_exit, others lack the __ */
        !            81: #if defined(HAVE_STRUCT_UTMPX_UT_EXIT_E_TERMINATION) || defined(HAVE_STRUCT_UTMP_UT_EXIT_E_TERMINATION)
        !            82: # undef  __e_termination
        !            83: # define __e_termination       e_termination
        !            84: # undef  __e_exit
        !            85: # define __e_exit              e_exit
        !            86: #endif
        !            87: 
        !            88: #if defined(HAVE_GETUTXID) || defined(HAVE_GETUTID)
        !            89: /*
        !            90:  * Create ut_id from the new ut_line and the old ut_id.
        !            91:  */
        !            92: static void
        !            93: utmp_setid(sudo_utmp_t *old, sudo_utmp_t *new)
        !            94: {
        !            95:     const char *line = new->ut_line;
        !            96:     size_t idlen;
        !            97: 
        !            98:     /* Skip over "tty" in the id if old entry did too. */
        !            99:     if (old != NULL) {
        !           100:        if (strncmp(line, "tty", 3) == 0) {
        !           101:            idlen = MIN(sizeof(old->ut_id), 3);
        !           102:            if (strncmp(old->ut_id, "tty", idlen) != 0)
        !           103:                line += 3;
        !           104:        }
        !           105:     }
        !           106:     
        !           107:     /* Store as much as will fit, skipping parts of the beginning as needed. */
        !           108:     idlen = strlen(line);
        !           109:     if (idlen > sizeof(new->ut_id)) {
        !           110:        line += idlen - sizeof(new->ut_id);
        !           111:        idlen = sizeof(new->ut_id);
        !           112:     }
        !           113:     strncpy(new->ut_id, line, idlen);
        !           114: }
        !           115: #endif /* HAVE_GETUTXID || HAVE_GETUTID */
        !           116: 
        !           117: /*
        !           118:  * Store time in utmp structure.
        !           119:  */
        !           120: static void
        !           121: utmp_settime(sudo_utmp_t *ut)
        !           122: {
        !           123:     struct timeval tv;
        !           124: 
        !           125:     gettimeofday(&tv, NULL);
        !           126: 
        !           127: #if defined(HAVE_STRUCT_UTMP_UT_TV) || defined(HAVE_STRUCT_UTMPX_UT_TV)
        !           128:     ut->ut_tv.tv_sec = tv.tv_sec;
        !           129:     ut->ut_tv.tv_usec = tv.tv_usec;
        !           130: #else
        !           131:     ut->ut_time = tv.tv_sec;
        !           132: #endif
        !           133: }
        !           134: 
        !           135: /*
        !           136:  * Fill in a utmp entry, using an old entry as a template if there is one.
        !           137:  */
        !           138: static void
        !           139: utmp_fill(const char *line, const char *user, sudo_utmp_t *ut_old,
        !           140:     sudo_utmp_t *ut_new)
        !           141: {
        !           142:     if (ut_old == NULL) {
        !           143:        memset(ut_new, 0, sizeof(*ut_new));
        !           144:        if (user == NULL) {
        !           145:            strncpy(ut_new->ut_user, user_details.username,
        !           146:                sizeof(ut_new->ut_user));
        !           147:        }
        !           148:     } else if (ut_old != ut_new) {
        !           149:        memcpy(ut_new, ut_old, sizeof(*ut_new));
        !           150:     }
        !           151:     if (user != NULL)
        !           152:        strncpy(ut_new->ut_user, user, sizeof(ut_new->ut_user));
        !           153:     strncpy(ut_new->ut_line, line, sizeof(ut_new->ut_line));
        !           154: #if defined(HAVE_STRUCT_UTMPX_UT_ID) || defined(HAVE_STRUCT_UTMP_UT_ID)
        !           155:     utmp_setid(ut_old, ut_new);
        !           156: #endif
        !           157: #if defined(HAVE_STRUCT_UTMPX_UT_PID) || defined(HAVE_STRUCT_UTMP_UT_PID)
        !           158:     ut_new->ut_pid = getpid();
        !           159: #endif
        !           160:     utmp_settime(ut_new);
        !           161: #if defined(HAVE_STRUCT_UTMPX_UT_TYPE) || defined(HAVE_STRUCT_UTMP_UT_TYPE)
        !           162:     ut_new->ut_type = USER_PROCESS;
        !           163: #endif
        !           164: }
        !           165: 
        !           166: /*
        !           167:  * There are two basic utmp file types:
        !           168:  *
        !           169:  *  POSIX:  sequential access with new entries appended to the end.
        !           170:  *         Manipulated via {get,put}utent()/{get,put}getutxent().
        !           171:  *
        !           172:  *  Legacy: sparse file indexed by ttyslot() * sizeof(struct utmp)
        !           173:  */
        !           174: #if defined(HAVE_GETUTXID) || defined(HAVE_GETUTID)
        !           175: int
        !           176: utmp_login(const char *from_line, const char *to_line, int ttyfd,
        !           177:     const char *user)
        !           178: {
        !           179:     sudo_utmp_t utbuf, *ut_old = NULL;
        !           180:     int rval = FALSE;
        !           181: 
        !           182:     /* Strip off /dev/ prefix from line as needed. */
        !           183:     if (strncmp(to_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
        !           184:        to_line += sizeof(_PATH_DEV) - 1;
        !           185:     setutxent();
        !           186:     if (from_line != NULL) {
        !           187:        if (strncmp(from_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
        !           188:            from_line += sizeof(_PATH_DEV) - 1;
        !           189: 
        !           190:        /* Lookup old line. */
        !           191:        memset(&utbuf, 0, sizeof(utbuf));
        !           192:        strncpy(utbuf.ut_line, from_line, sizeof(utbuf.ut_line));
        !           193:        ut_old = getutxline(&utbuf);
        !           194:     }
        !           195:     utmp_fill(to_line, user, ut_old, &utbuf);
        !           196:     if (pututxline(&utbuf) != NULL)
        !           197:        rval = TRUE;
        !           198:     endutxent();
        !           199: 
        !           200:     return rval;
        !           201: }
        !           202: 
        !           203: int
        !           204: utmp_logout(const char *line, int status)
        !           205: {
        !           206:     int rval = FALSE;
        !           207:     sudo_utmp_t *ut, utbuf;
        !           208: 
        !           209:     /* Strip off /dev/ prefix from line as needed. */
        !           210:     if (strncmp(line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
        !           211:        line += sizeof(_PATH_DEV) - 1;
        !           212:    
        !           213:     memset(&utbuf, 0, sizeof(utbuf));
        !           214:     strncpy(utbuf.ut_line, line, sizeof(utbuf.ut_line));
        !           215:     if ((ut = getutxline(&utbuf)) != NULL) {
        !           216:        memset(ut->ut_user, 0, sizeof(ut->ut_user));
        !           217: # if defined(HAVE_STRUCT_UTMPX_UT_TYPE) || defined(HAVE_STRUCT_UTMP_UT_TYPE)
        !           218:        ut->ut_type = DEAD_PROCESS;
        !           219: # endif
        !           220: # if defined(HAVE_STRUCT_UTMPX_UT_EXIT) || defined(HAVE_STRUCT_UTMP_UT_EXIT)
        !           221:        ut->ut_exit.__e_exit = WEXITSTATUS(status);
        !           222:        ut->ut_exit.__e_termination = WIFEXITED(status) ? WEXITSTATUS(status) : 0;
        !           223: # endif
        !           224:        utmp_settime(ut);
        !           225:        if (pututxline(ut) != NULL)
        !           226:            rval = TRUE;
        !           227:     }
        !           228:     return rval;
        !           229: }
        !           230: 
        !           231: #else /* !HAVE_GETUTXID && !HAVE_GETUTID */
        !           232: 
        !           233: /*
        !           234:  * Find the slot for the specified line (tty name and file descriptor).
        !           235:  * Returns a slot suitable for seeking into utmp on success or <= 0 on error.
        !           236:  * If getttyent() is available we can use that to compute the slot.
        !           237:  */
        !           238: # ifdef HAVE_GETTTYENT
        !           239: static int
        !           240: utmp_slot(const char *line, int ttyfd)
        !           241: {
        !           242:     int slot = 1;
        !           243:     struct ttyent *tty;
        !           244: 
        !           245:     setttyent();
        !           246:     while ((tty = getttyent()) != NULL) {
        !           247:        if (strcmp(line, tty->ty_name) == 0)
        !           248:            break;
        !           249:        slot++;
        !           250:     }
        !           251:     endttyent();
        !           252:     return tty ? slot : 0;
        !           253: }
        !           254: # else
        !           255: static int
        !           256: utmp_slot(const char *line, int ttyfd)
        !           257: {
        !           258:     int sfd, slot;
        !           259: 
        !           260:     /*
        !           261:      * Temporarily point stdin to the tty since ttyslot()
        !           262:      * doesn't take an argument.
        !           263:      */
        !           264:     if ((sfd = dup(STDIN_FILENO)) == -1)
        !           265:        error(1, _("unable to save stdin"));
        !           266:     if (dup2(ttyfd, STDIN_FILENO) == -1)
        !           267:        error(1, _("unable to dup2 stdin"));
        !           268:     slot = ttyslot();
        !           269:     if (dup2(sfd, STDIN_FILENO) == -1)
        !           270:        error(1, _("unable to restore stdin"));
        !           271:     close(sfd);
        !           272: 
        !           273:     return slot;
        !           274: }
        !           275: # endif /* HAVE_GETTTYENT */
        !           276: 
        !           277: int
        !           278: utmp_login(const char *from_line, const char *to_line, int ttyfd,
        !           279:     const char *user)
        !           280: {
        !           281:     sudo_utmp_t utbuf, *ut_old = NULL;
        !           282:     int slot, rval = FALSE;
        !           283:     FILE *fp;
        !           284: 
        !           285:     /* Strip off /dev/ prefix from line as needed. */
        !           286:     if (strncmp(to_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
        !           287:        to_line += sizeof(_PATH_DEV) - 1;
        !           288: 
        !           289:     /* Find slot for new entry. */
        !           290:     slot = utmp_slot(to_line, ttyfd);
        !           291:     if (slot <= 0)
        !           292:        goto done;
        !           293: 
        !           294:     if ((fp = fopen(_PATH_UTMP, "r+")) == NULL)
        !           295:        goto done;
        !           296: 
        !           297:     if (from_line != NULL) {
        !           298:        if (strncmp(from_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
        !           299:            from_line += sizeof(_PATH_DEV) - 1;
        !           300: 
        !           301:        /* Lookup old line. */
        !           302:        while (fread(&utbuf, sizeof(utbuf), 1, fp) == 1) {
        !           303: # ifdef HAVE_STRUCT_UTMP_UT_ID
        !           304:            if (utbuf.ut_type != LOGIN_PROCESS && utbuf.ut_type != USER_PROCESS)
        !           305:                continue;
        !           306: # endif
        !           307:            if (utbuf.ut_user[0] &&
        !           308:                !strncmp(utbuf.ut_line, from_line, sizeof(utbuf.ut_line))) {
        !           309:                ut_old = &utbuf;
        !           310:                break;
        !           311:            }
        !           312:        }
        !           313:     }
        !           314:     utmp_fill(to_line, user, ut_old, &utbuf);
        !           315:     if (fseek(fp, slot * (long)sizeof(utbuf), SEEK_SET) == 0) {
        !           316:        if (fwrite(&utbuf, sizeof(utbuf), 1, fp) == 1)
        !           317:            rval = TRUE;
        !           318:     }
        !           319:     fclose(fp);
        !           320: 
        !           321: done:
        !           322:     return rval;
        !           323: }
        !           324: 
        !           325: int
        !           326: utmp_logout(const char *line, int status)
        !           327: {
        !           328:     sudo_utmp_t utbuf;
        !           329:     int rval = FALSE;
        !           330:     FILE *fp;
        !           331: 
        !           332:     if ((fp = fopen(_PATH_UTMP, "r+")) == NULL)
        !           333:        return rval;
        !           334: 
        !           335:     /* Strip off /dev/ prefix from line as needed. */
        !           336:     if (strncmp(line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
        !           337:        line += sizeof(_PATH_DEV) - 1;
        !           338:    
        !           339:     while (fread(&utbuf, sizeof(utbuf), 1, fp) == 1) {
        !           340:        if (!strncmp(utbuf.ut_line, line, sizeof(utbuf.ut_line))) {
        !           341:            memset(utbuf.ut_user, 0, sizeof(utbuf.ut_user));
        !           342: # if defined(HAVE_STRUCT_UTMP_UT_TYPE)
        !           343:            utbuf.ut_type = DEAD_PROCESS;
        !           344: # endif
        !           345:            utmp_settime(&utbuf);
        !           346:            /* Back up and overwrite record. */
        !           347:            if (fseek(fp, 0L - (long)sizeof(utbuf), SEEK_CUR) == 0) {
        !           348:                if (fwrite(&utbuf, sizeof(utbuf), 1, fp) == 1)
        !           349:                    rval = TRUE;
        !           350:            }
        !           351:            break;
        !           352:        }
        !           353:     }
        !           354:     fclose(fp);
        !           355: 
        !           356:     return rval;
        !           357: }
        !           358: #endif /* HAVE_GETUTXID || HAVE_GETUTID */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>