[BACK]Return to login.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/login.c, Revision 1.3

1.1       deraadt     1: /*
                      2:
                      3: login.c
                      4:
                      5: Author: Tatu Ylonen <ylo@cs.hut.fi>
                      6:
                      7: Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
                      8:                    All rights reserved
                      9:
                     10: Created: Fri Mar 24 14:51:08 1995 ylo
                     11:
                     12: This file performs some of the things login(1) normally does.  We cannot
                     13: easily use something like login -p -h host -f user, because there are
                     14: several different logins around, and it is hard to determined what kind of
                     15: login the current system has.  Also, we want to be able to execute commands
                     16: on a tty.
                     17:
                     18: */
                     19:
                     20: #include "includes.h"
1.3     ! deraadt    21: RCSID("$Id: login.c,v 1.2 1999/09/29 18:16:19 dugsong Exp $");
1.1       deraadt    22:
1.2       dugsong    23: #ifdef HAVE_LIBUTIL_LOGIN
                     24: #include <util.h>
                     25: #endif /* HAVE_LIBUTIL_LOGIN */
1.1       deraadt    26: #ifdef HAVE_UTMP_H
                     27: #include <utmp.h>
                     28: #ifdef HAVE_LASTLOG_H
                     29: #include <lastlog.h> /* Some have the definitions in utmp.h. */
                     30: #endif /* HAVE_LASTLOG_H */
                     31: #endif /* HAVE_UTMP_H */
                     32: #ifdef HAVE_UTMPX_H
                     33: #include <utmpx.h>
                     34: #endif /* HAVE_UTMPX_H */
                     35: #ifdef HAVE_USERSEC_H
                     36: #include <usersec.h>
                     37: #endif /* HAVE_USERSEC_H */
                     38: #include "ssh.h"
                     39:
                     40: /* Returns the time when the user last logged in.  Returns 0 if the
                     41:    information is not available.  This must be called before record_login.
                     42:    The host the user logged in from will be returned in buf. */
                     43:
                     44: #ifdef LASTLOG_IS_DIR
                     45: unsigned long get_last_login_time(uid_t uid, const char *name,
                     46:                                  char *buf, unsigned int bufsize)
                     47: {
                     48: #if defined(HAVE_LASTLOG_H) || defined(HAVE_LASTLOG)
                     49:   struct lastlog ll;
                     50:   char lastlogfile[500];
                     51:   int fd;
                     52:
                     53: #ifdef _PATH_LASTLOG
1.3     ! deraadt    54:   snprintf(lastlogfile, sizeof lastlogfile, "%.200s/%.200s",
        !            55:     _PATH_LASTLOG, name);
1.1       deraadt    56: #else
                     57: #ifdef LASTLOG_FILE
1.3     ! deraadt    58:   snprintf(lastlogfile, sizeof lastlogfile, "%.200s/%.200s",
        !            59:     LASTLOG_FILE, name);
1.1       deraadt    60: #else
1.3     ! deraadt    61:   snprintf(lastlogfile, sizeof lastlogfile, "%.200s/%.200s",
        !            62:     SSH_LASTLOG, name);
1.1       deraadt    63: #endif
                     64: #endif
                     65:
1.3     ! deraadt    66:   buf[0] = '\0';
1.1       deraadt    67:
                     68:   fd = open(lastlogfile, O_RDONLY);
                     69:   if (fd < 0)
                     70:     return 0;
                     71:   if (read(fd, &ll, sizeof(ll)) != sizeof(ll))
                     72:     {
                     73:       close(fd);
                     74:       return 0;
                     75:     }
                     76:   close(fd);
                     77:   if (bufsize > sizeof(ll.ll_host) + 1)
                     78:     bufsize = sizeof(ll.ll_host) + 1;
                     79:   strncpy(buf, ll.ll_host, bufsize - 1);
                     80:   buf[bufsize - 1] = 0;
                     81:   return ll.ll_time;
                     82:
                     83: #else /* HAVE_LASTLOG_H || HAVE_LASTLOG */
                     84:
                     85:   return 0;
                     86:
                     87: #endif /* HAVE_LASTLOG_H || HAVE_LASTLOG */
                     88: }
                     89:
                     90: #else /* LASTLOG_IS_DIR */
                     91:
                     92: /* Returns the time when the user last logged in (or 0 if no previous login
                     93:    is found).  The name of the host used last time is returned in buf. */
                     94:
                     95: unsigned long get_last_login_time(uid_t uid, const char *logname,
                     96:                                  char *buf, unsigned int bufsize)
                     97: {
                     98: #if defined(HAVE_LASTLOG_H) || defined(HAVE_LASTLOG)
                     99:
                    100:   struct lastlog ll;
                    101:   char *lastlog;
                    102:   int fd;
                    103:
                    104: #ifdef _PATH_LASTLOG
                    105:   lastlog = _PATH_LASTLOG;
                    106: #else
                    107: #ifdef LASTLOG_FILE
                    108:   lastlog = LASTLOG_FILE;
                    109: #else
                    110:   lastlog = SSH_LASTLOG;
                    111: #endif
                    112: #endif
                    113:
1.3     ! deraadt   114:   buf[0] = '\0';
1.1       deraadt   115:
                    116:   fd = open(lastlog, O_RDONLY);
                    117:   if (fd < 0)
                    118:     return 0;
                    119:   lseek(fd, (off_t)((long)uid * sizeof(ll)), 0);
                    120:   if (read(fd, &ll, sizeof(ll)) != sizeof(ll))
                    121:     {
                    122:       close(fd);
                    123:       return 0;
                    124:     }
                    125:   close(fd);
                    126:   if (bufsize > sizeof(ll.ll_host) + 1)
                    127:     bufsize = sizeof(ll.ll_host) + 1;
                    128:   strncpy(buf, ll.ll_host, bufsize - 1);
                    129:   buf[bufsize - 1] = 0;
                    130:   return ll.ll_time;
                    131:
                    132: #else /* HAVE_LASTLOG_H || HAVE_LASTLOG */
                    133:
                    134: #ifdef HAVE_USERSEC_H
                    135:
                    136:   char *lasthost;
                    137:   int lasttime;
                    138:   if (setuserdb(S_READ) < 0)
                    139:     return 0;
                    140:   if (getuserattr((char *)logname, S_LASTTIME, &lasttime, SEC_INT) < 0)
                    141:     {
                    142:       enduserdb();
                    143:       return 0;
                    144:     }
                    145:   if (getuserattr((char *)logname, S_LASTHOST, &lasthost, SEC_CHAR) < 0)
                    146:     {
                    147:       enduserdb();
                    148:       return 0;
                    149:     }
                    150:   strncpy(buf, lasthost, bufsize);
                    151:   buf[bufsize - 1] = 0;
                    152:   if (enduserdb() < 0)
                    153:     return 0;
                    154:   return lasttime;
                    155:
                    156: #else /* HAVE_USERSEC_H */
                    157:
                    158:   return 0;
                    159:
                    160: #endif /* HAVE_USERSEC_H */
                    161:
                    162: #endif /* HAVE_LASTLOG_H || HAVE_LASTLOG */
                    163: }
                    164: #endif /* LASTLOG_IS_DIR */
                    165:
                    166: /* Records that the user has logged in.  I these parts of operating systems
                    167:    were more standardized. */
                    168:
                    169: void record_login(int pid, const char *ttyname, const char *user, uid_t uid,
                    170:                  const char *host, struct sockaddr_in *addr)
                    171: {
                    172:   int fd;
                    173:
                    174: #if defined(HAVE_LASTLOG_H) || defined(HAVE_LASTLOG)
                    175:   struct lastlog ll;
                    176:   char *lastlog;
                    177: #ifdef LASTLOG_IS_DIR
                    178:   char lastlogfile[100];
                    179: #endif /* LASTLOG_IS_DIR */
                    180: #endif /* HAVE_LASTLOG_H || HAVE_LASTLOG */
                    181:
                    182: #if defined(HAVE_UTMP_H) && !defined(HAVE_UTMPX_H)
1.2       dugsong   183:   struct utmp u;
1.1       deraadt   184:   const char *utmp, *wtmp;
                    185:
                    186:   /* Construct an utmp/wtmp entry. */
                    187:   memset(&u, 0, sizeof(u));
                    188: #ifdef DEAD_PROCESS
                    189:   if (strcmp(user, "") == 0)
                    190:     u.ut_type = DEAD_PROCESS; /* logout */
                    191:   else
                    192:     u.ut_type = USER_PROCESS;
                    193: #endif /* LOGIN_PROCESS */
                    194: #ifdef HAVE_PID_IN_UTMP
                    195:   u.ut_pid = pid;
                    196: #endif /* PID_IN_UTMP */
                    197: #ifdef HAVE_ID_IN_UTMP
                    198: #ifdef __sgi
                    199:     strncpy(u.ut_id, ttyname + 8, sizeof(u.ut_id)); /* /dev/ttyq99 -> q99 */
                    200: #else /* __sgi */
                    201:     if (sizeof(u.ut_id) > 4)
                    202:       strncpy(u.ut_id, ttyname + 5, sizeof(u.ut_id));
                    203:     else
                    204:       strncpy(u.ut_id, ttyname + strlen(ttyname) - 2, sizeof(u.ut_id));
                    205: #endif /* __sgi */
                    206: #endif /* HAVE_ID_IN_UTMP */
                    207:   strncpy(u.ut_line, ttyname + 5, sizeof(u.ut_line));
                    208:   u.ut_time = time(NULL);
                    209: #ifdef HAVE_NAME_IN_UTMP
                    210:   strncpy(u.ut_name, user, sizeof(u.ut_name));
                    211: #else /* HAVE_NAME_IN_UTMP */
                    212:   strncpy(u.ut_user, user, sizeof(u.ut_user));
                    213: #endif /* HAVE_NAME_IN_UTMP */
                    214: #ifdef HAVE_HOST_IN_UTMP
                    215:   strncpy(u.ut_host, host, sizeof(u.ut_host));
                    216: #endif /* HAVE_HOST_IN_UTMP */
                    217: #ifdef HAVE_ADDR_IN_UTMP
                    218:   if (addr)
                    219:     memcpy(&u.ut_addr, &addr->sin_addr, sizeof(u.ut_addr));
                    220:   else
                    221:     memset(&u.ut_addr, 0, sizeof(u.ut_addr));
                    222: #endif
                    223:
                    224:   /* Figure out the file names. */
                    225: #ifdef _PATH_UTMP
                    226:   utmp = _PATH_UTMP;
                    227:   wtmp = _PATH_WTMP;
                    228: #else
                    229: #ifdef UTMP_FILE
                    230:   utmp = UTMP_FILE;
                    231:   wtmp = WTMP_FILE;
                    232: #else
                    233:   utmp = SSH_UTMP;
                    234:   wtmp = SSH_WTMP;
                    235: #endif
                    236: #endif
                    237:
                    238: #ifdef HAVE_LIBUTIL_LOGIN
                    239:   login(&u);
                    240: #else /* HAVE_LIBUTIL_LOGIN */
                    241:   /* Append an entry to wtmp. */
                    242:   fd = open(wtmp, O_WRONLY|O_APPEND);
                    243:   if (fd >= 0)
                    244:     {
                    245:       if (write(fd, &u, sizeof(u)) != sizeof(u))
                    246:        log("Could not write %.100s: %.100s", wtmp, strerror(errno));
                    247:       close(fd);
                    248:     }
                    249:
                    250:   /* Replace the proper entry in utmp, as identified by ut_line.  Append a
                    251:      new entry if the line could not be found. */
                    252:   fd = open(utmp, O_RDWR);
                    253:   if (fd >= 0)
                    254:     {
                    255:       while (1)
                    256:        {
                    257:          offset = lseek(fd, (off_t)0L, 1);
                    258:          if (read(fd, &u2, sizeof(u2)) != sizeof(u2))
                    259:            {
                    260:              lseek(fd, offset, 0);
                    261:              if (write(fd, &u, sizeof(u)) != sizeof(u))
                    262:                log("Could not append to %.100s: %.100s",
                    263:                    utmp, strerror(errno));
                    264:              break;
                    265:            }
                    266:          if (strncmp(u2.ut_line, ttyname + 5, sizeof(u2.ut_line)) == 0)
                    267:            {
                    268:              lseek(fd, offset, 0);
                    269:              if (write(fd, &u, sizeof(u)) != sizeof(u))
                    270:                log("Could not write to %.100s: %.100s",
                    271:                    utmp, strerror(errno));
                    272:              break;
                    273:            }
                    274:        }
                    275:       close(fd);
                    276:     }
                    277: #endif /* HAVE_LIBUTIL_LOGIN */
                    278: #endif /* HAVE_UTMP_H && !HAVE_UTMPX_H */
                    279:
                    280: #ifdef HAVE_UTMPX_H
                    281:   {
                    282:     struct utmpx ux, *uxp;
                    283:     memset(&ux, 0, sizeof(ux));
                    284:     strncpy(ux.ut_line, ttyname + 5, sizeof(ux.ut_line));
                    285:     uxp = getutxline(&ux);
                    286:     if (uxp)
                    287:       ux = *uxp;
                    288:     strncpy(ux.ut_user, user, sizeof(ux.ut_user));
                    289: #ifdef __sgi
                    290:     strncpy(ux.ut_id, ttyname + 8, sizeof(ux.ut_id)); /* /dev/ttyq99 -> q99 */
                    291: #else /* __sgi */
                    292:     if (sizeof(ux.ut_id) > 4)
                    293:       strncpy(ux.ut_id, ttyname + 5, sizeof(ux.ut_id));
                    294:     else
                    295:       strncpy(ux.ut_id, ttyname + strlen(ttyname) - 2, sizeof(ux.ut_id));
                    296: #endif /* __sgi */
                    297:     ux.ut_pid = pid;
                    298:     if (strcmp(user, "") == 0)
                    299:       ux.ut_type = DEAD_PROCESS;
                    300:     else
                    301:       ux.ut_type = USER_PROCESS;
                    302:     gettimeofday(&ux.ut_tv, NULL);
                    303: #if HAVE_UT_SESSION
                    304:     ux.ut_session = pid;
                    305: #endif
                    306:     strncpy(ux.ut_host, host, sizeof(ux.ut_host));
                    307:     ux.ut_host[sizeof(ux.ut_host) - 1] = 0;
                    308: #ifdef HAVE_UT_SYSLEN
                    309:     ux.ut_syslen = strlen(ux.ut_host);
                    310: #endif
                    311:     pututxline(&ux);
                    312: #ifdef WTMPX_FILE
                    313:     updwtmpx(WTMPX_FILE, &ux);
                    314: #endif
                    315:     endutxent();
                    316:   }
                    317: #endif /* HAVE_UTMPX_H */
                    318:
                    319: #if defined(HAVE_LASTLOG_H) || defined(HAVE_LASTLOG)
                    320:
                    321: #ifdef _PATH_LASTLOG
                    322:   lastlog = _PATH_LASTLOG;
                    323: #else
                    324: #ifdef LASTLOG_FILE
                    325:   lastlog = LASTLOG_FILE;
                    326: #else
                    327:   lastlog = SSH_LASTLOG;
                    328: #endif
                    329: #endif
                    330:
                    331:   /* Update lastlog unless actually recording a logout. */
                    332:   if (strcmp(user, "") != 0)
                    333:     {
                    334:       /* It is safer to bzero the lastlog structure first because some
                    335:         systems might have some extra fields in it (e.g. SGI) */
                    336:       memset(&ll, 0, sizeof(ll));
                    337:
                    338:       /* Update lastlog. */
                    339:       ll.ll_time = time(NULL);
                    340:       strncpy(ll.ll_line, ttyname + 5, sizeof(ll.ll_line));
                    341:       strncpy(ll.ll_host, host, sizeof(ll.ll_host));
                    342: #ifdef LASTLOG_IS_DIR
1.3     ! deraadt   343:       snprintf(lastlogfile, sizeof lastlogfile, "%.100s/%.100s",
        !           344:         lastlog, user);
1.1       deraadt   345:       fd = open(lastlogfile, O_WRONLY | O_CREAT, 0644);
                    346:       if (fd >= 0)
                    347:        {
                    348:          if (write(fd, &ll, sizeof(ll)) != sizeof(ll))
                    349:            log("Could not write %.100s: %.100s",
                    350:                lastlogfile, strerror(errno));
                    351:          close(fd);
                    352:        }
                    353:       else
                    354:        {
                    355:          log("Could not open %.100s: %.100s", lastlogfile, strerror(errno));
                    356:        }
                    357: #else /* LASTLOG_IS_DIR */
                    358:       fd = open(lastlog, O_RDWR);
                    359:       if (fd >= 0)
                    360:        {
                    361:          lseek(fd, (off_t)((long)uid * sizeof(ll)), 0);
                    362:          if (write(fd, &ll, sizeof(ll)) != sizeof(ll))
                    363:            log("Could not write %.100s: %.100s", lastlog, strerror(errno));
                    364:          close(fd);
                    365:        }
                    366: #endif /* LASTLOG_IS_DIR */
                    367:     }
                    368: #endif /* HAVE_LASTLOG_H || HAVE_LASTLOG */
                    369:
                    370: #ifdef HAVE_USERSEC_H
                    371:
                    372:   if (strcmp(user, "") != 0)
                    373:     {
                    374:       int lasttime = time(NULL);
                    375:       if (setuserdb(S_WRITE) < 0)
                    376:        log("setuserdb S_WRITE failed: %.100s", strerror(errno));
                    377:       if (putuserattr((char *)user, S_LASTTIME, (void *)lasttime, SEC_INT) < 0)
                    378:        log("putuserattr S_LASTTIME failed: %.100s", strerror(errno));
                    379:       if (putuserattr((char *)user, S_LASTTTY, (void *)(ttyname + 5),
                    380:                      SEC_CHAR) < 0)
                    381:        log("putuserattr S_LASTTTY %.900s failed: %.100s",
                    382:            ttyname, strerror(errno));
                    383:       if (putuserattr((char *)user, S_LASTHOST, (void *)host, SEC_CHAR) < 0)
                    384:        log("putuserattr S_LASTHOST %.900s failed: %.100s",
                    385:            host, strerror(errno));
                    386:       if (putuserattr((char *)user, 0, NULL, SEC_COMMIT) < 0)
                    387:        log("putuserattr SEC_COMMIT failed: %.100s", strerror(errno));
                    388:       if (enduserdb() < 0)
                    389:        log("enduserdb failed: %.100s", strerror(errno));
                    390:     }
                    391: #endif
                    392: }
                    393:
                    394: /* Records that the user has logged out. */
                    395:
                    396: void record_logout(int pid, const char *ttyname)
                    397: {
                    398: #ifdef HAVE_LIBUTIL_LOGIN
                    399:   const char *line = ttyname + 5; /* /dev/ttyq8 -> ttyq8 */
                    400:   if (logout(line))
                    401:     logwtmp(line, "", "");
                    402: #else /* HAVE_LIBUTIL_LOGIN */
                    403:   record_login(pid, ttyname, "", -1, "", NULL);
                    404: #endif /* HAVE_LIBUTIL_LOGIN */
                    405: }