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

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.4     ! deraadt    21: RCSID("$Id: login.c,v 1.3 1999/09/29 21:14:16 deraadt 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:
1.3       deraadt    53:   snprintf(lastlogfile, sizeof lastlogfile, "%.200s/%.200s",
                     54:     _PATH_LASTLOG, name);
1.1       deraadt    55:
1.3       deraadt    56:   buf[0] = '\0';
1.1       deraadt    57:
                     58:   fd = open(lastlogfile, O_RDONLY);
                     59:   if (fd < 0)
                     60:     return 0;
                     61:   if (read(fd, &ll, sizeof(ll)) != sizeof(ll))
                     62:     {
                     63:       close(fd);
                     64:       return 0;
                     65:     }
                     66:   close(fd);
                     67:   if (bufsize > sizeof(ll.ll_host) + 1)
                     68:     bufsize = sizeof(ll.ll_host) + 1;
                     69:   strncpy(buf, ll.ll_host, bufsize - 1);
                     70:   buf[bufsize - 1] = 0;
                     71:   return ll.ll_time;
                     72:
                     73: #else /* HAVE_LASTLOG_H || HAVE_LASTLOG */
                     74:
                     75:   return 0;
                     76:
                     77: #endif /* HAVE_LASTLOG_H || HAVE_LASTLOG */
                     78: }
                     79:
                     80: #else /* LASTLOG_IS_DIR */
                     81:
                     82: /* Returns the time when the user last logged in (or 0 if no previous login
                     83:    is found).  The name of the host used last time is returned in buf. */
                     84:
                     85: unsigned long get_last_login_time(uid_t uid, const char *logname,
                     86:                                  char *buf, unsigned int bufsize)
                     87: {
                     88: #if defined(HAVE_LASTLOG_H) || defined(HAVE_LASTLOG)
                     89:
                     90:   struct lastlog ll;
                     91:   char *lastlog;
                     92:   int fd;
                     93:
                     94:   lastlog = _PATH_LASTLOG;
                     95:
1.3       deraadt    96:   buf[0] = '\0';
1.1       deraadt    97:
                     98:   fd = open(lastlog, O_RDONLY);
                     99:   if (fd < 0)
                    100:     return 0;
                    101:   lseek(fd, (off_t)((long)uid * sizeof(ll)), 0);
                    102:   if (read(fd, &ll, sizeof(ll)) != sizeof(ll))
                    103:     {
                    104:       close(fd);
                    105:       return 0;
                    106:     }
                    107:   close(fd);
                    108:   if (bufsize > sizeof(ll.ll_host) + 1)
                    109:     bufsize = sizeof(ll.ll_host) + 1;
                    110:   strncpy(buf, ll.ll_host, bufsize - 1);
                    111:   buf[bufsize - 1] = 0;
                    112:   return ll.ll_time;
                    113:
                    114: #else /* HAVE_LASTLOG_H || HAVE_LASTLOG */
                    115:
                    116: #ifdef HAVE_USERSEC_H
                    117:
                    118:   char *lasthost;
                    119:   int lasttime;
                    120:   if (setuserdb(S_READ) < 0)
                    121:     return 0;
                    122:   if (getuserattr((char *)logname, S_LASTTIME, &lasttime, SEC_INT) < 0)
                    123:     {
                    124:       enduserdb();
                    125:       return 0;
                    126:     }
                    127:   if (getuserattr((char *)logname, S_LASTHOST, &lasthost, SEC_CHAR) < 0)
                    128:     {
                    129:       enduserdb();
                    130:       return 0;
                    131:     }
                    132:   strncpy(buf, lasthost, bufsize);
                    133:   buf[bufsize - 1] = 0;
                    134:   if (enduserdb() < 0)
                    135:     return 0;
                    136:   return lasttime;
                    137:
                    138: #else /* HAVE_USERSEC_H */
                    139:
                    140:   return 0;
                    141:
                    142: #endif /* HAVE_USERSEC_H */
                    143:
                    144: #endif /* HAVE_LASTLOG_H || HAVE_LASTLOG */
                    145: }
                    146: #endif /* LASTLOG_IS_DIR */
                    147:
                    148: /* Records that the user has logged in.  I these parts of operating systems
                    149:    were more standardized. */
                    150:
                    151: void record_login(int pid, const char *ttyname, const char *user, uid_t uid,
                    152:                  const char *host, struct sockaddr_in *addr)
                    153: {
                    154:   int fd;
                    155:
                    156: #if defined(HAVE_LASTLOG_H) || defined(HAVE_LASTLOG)
                    157:   struct lastlog ll;
                    158:   char *lastlog;
                    159: #ifdef LASTLOG_IS_DIR
                    160:   char lastlogfile[100];
                    161: #endif /* LASTLOG_IS_DIR */
                    162: #endif /* HAVE_LASTLOG_H || HAVE_LASTLOG */
                    163:
                    164: #if defined(HAVE_UTMP_H) && !defined(HAVE_UTMPX_H)
1.2       dugsong   165:   struct utmp u;
1.1       deraadt   166:   const char *utmp, *wtmp;
                    167:
                    168:   /* Construct an utmp/wtmp entry. */
                    169:   memset(&u, 0, sizeof(u));
                    170: #ifdef DEAD_PROCESS
                    171:   if (strcmp(user, "") == 0)
                    172:     u.ut_type = DEAD_PROCESS; /* logout */
                    173:   else
                    174:     u.ut_type = USER_PROCESS;
                    175: #endif /* LOGIN_PROCESS */
                    176: #ifdef HAVE_PID_IN_UTMP
                    177:   u.ut_pid = pid;
                    178: #endif /* PID_IN_UTMP */
                    179: #ifdef HAVE_ID_IN_UTMP
                    180: #ifdef __sgi
                    181:     strncpy(u.ut_id, ttyname + 8, sizeof(u.ut_id)); /* /dev/ttyq99 -> q99 */
                    182: #else /* __sgi */
                    183:     if (sizeof(u.ut_id) > 4)
                    184:       strncpy(u.ut_id, ttyname + 5, sizeof(u.ut_id));
                    185:     else
                    186:       strncpy(u.ut_id, ttyname + strlen(ttyname) - 2, sizeof(u.ut_id));
                    187: #endif /* __sgi */
                    188: #endif /* HAVE_ID_IN_UTMP */
                    189:   strncpy(u.ut_line, ttyname + 5, sizeof(u.ut_line));
                    190:   u.ut_time = time(NULL);
                    191: #ifdef HAVE_NAME_IN_UTMP
                    192:   strncpy(u.ut_name, user, sizeof(u.ut_name));
                    193: #else /* HAVE_NAME_IN_UTMP */
                    194:   strncpy(u.ut_user, user, sizeof(u.ut_user));
                    195: #endif /* HAVE_NAME_IN_UTMP */
                    196: #ifdef HAVE_HOST_IN_UTMP
                    197:   strncpy(u.ut_host, host, sizeof(u.ut_host));
                    198: #endif /* HAVE_HOST_IN_UTMP */
                    199: #ifdef HAVE_ADDR_IN_UTMP
                    200:   if (addr)
                    201:     memcpy(&u.ut_addr, &addr->sin_addr, sizeof(u.ut_addr));
                    202:   else
                    203:     memset(&u.ut_addr, 0, sizeof(u.ut_addr));
                    204: #endif
                    205:
                    206:   /* Figure out the file names. */
                    207:   utmp = _PATH_UTMP;
                    208:   wtmp = _PATH_WTMP;
                    209:
                    210: #ifdef HAVE_LIBUTIL_LOGIN
                    211:   login(&u);
                    212: #else /* HAVE_LIBUTIL_LOGIN */
                    213:   /* Append an entry to wtmp. */
                    214:   fd = open(wtmp, O_WRONLY|O_APPEND);
                    215:   if (fd >= 0)
                    216:     {
                    217:       if (write(fd, &u, sizeof(u)) != sizeof(u))
                    218:        log("Could not write %.100s: %.100s", wtmp, strerror(errno));
                    219:       close(fd);
                    220:     }
                    221:
                    222:   /* Replace the proper entry in utmp, as identified by ut_line.  Append a
                    223:      new entry if the line could not be found. */
                    224:   fd = open(utmp, O_RDWR);
                    225:   if (fd >= 0)
                    226:     {
                    227:       while (1)
                    228:        {
                    229:          offset = lseek(fd, (off_t)0L, 1);
                    230:          if (read(fd, &u2, sizeof(u2)) != sizeof(u2))
                    231:            {
                    232:              lseek(fd, offset, 0);
                    233:              if (write(fd, &u, sizeof(u)) != sizeof(u))
                    234:                log("Could not append to %.100s: %.100s",
                    235:                    utmp, strerror(errno));
                    236:              break;
                    237:            }
                    238:          if (strncmp(u2.ut_line, ttyname + 5, sizeof(u2.ut_line)) == 0)
                    239:            {
                    240:              lseek(fd, offset, 0);
                    241:              if (write(fd, &u, sizeof(u)) != sizeof(u))
                    242:                log("Could not write to %.100s: %.100s",
                    243:                    utmp, strerror(errno));
                    244:              break;
                    245:            }
                    246:        }
                    247:       close(fd);
                    248:     }
                    249: #endif /* HAVE_LIBUTIL_LOGIN */
                    250: #endif /* HAVE_UTMP_H && !HAVE_UTMPX_H */
                    251:
                    252: #ifdef HAVE_UTMPX_H
                    253:   {
                    254:     struct utmpx ux, *uxp;
                    255:     memset(&ux, 0, sizeof(ux));
                    256:     strncpy(ux.ut_line, ttyname + 5, sizeof(ux.ut_line));
                    257:     uxp = getutxline(&ux);
                    258:     if (uxp)
                    259:       ux = *uxp;
                    260:     strncpy(ux.ut_user, user, sizeof(ux.ut_user));
                    261: #ifdef __sgi
                    262:     strncpy(ux.ut_id, ttyname + 8, sizeof(ux.ut_id)); /* /dev/ttyq99 -> q99 */
                    263: #else /* __sgi */
                    264:     if (sizeof(ux.ut_id) > 4)
                    265:       strncpy(ux.ut_id, ttyname + 5, sizeof(ux.ut_id));
                    266:     else
                    267:       strncpy(ux.ut_id, ttyname + strlen(ttyname) - 2, sizeof(ux.ut_id));
                    268: #endif /* __sgi */
                    269:     ux.ut_pid = pid;
                    270:     if (strcmp(user, "") == 0)
                    271:       ux.ut_type = DEAD_PROCESS;
                    272:     else
                    273:       ux.ut_type = USER_PROCESS;
                    274:     gettimeofday(&ux.ut_tv, NULL);
                    275: #if HAVE_UT_SESSION
                    276:     ux.ut_session = pid;
                    277: #endif
                    278:     strncpy(ux.ut_host, host, sizeof(ux.ut_host));
                    279:     ux.ut_host[sizeof(ux.ut_host) - 1] = 0;
                    280: #ifdef HAVE_UT_SYSLEN
                    281:     ux.ut_syslen = strlen(ux.ut_host);
                    282: #endif
                    283:     pututxline(&ux);
                    284: #ifdef WTMPX_FILE
                    285:     updwtmpx(WTMPX_FILE, &ux);
                    286: #endif
                    287:     endutxent();
                    288:   }
                    289: #endif /* HAVE_UTMPX_H */
                    290:
                    291: #if defined(HAVE_LASTLOG_H) || defined(HAVE_LASTLOG)
                    292:
                    293:   lastlog = _PATH_LASTLOG;
                    294:
                    295:   /* Update lastlog unless actually recording a logout. */
                    296:   if (strcmp(user, "") != 0)
                    297:     {
                    298:       /* It is safer to bzero the lastlog structure first because some
                    299:         systems might have some extra fields in it (e.g. SGI) */
                    300:       memset(&ll, 0, sizeof(ll));
                    301:
                    302:       /* Update lastlog. */
                    303:       ll.ll_time = time(NULL);
                    304:       strncpy(ll.ll_line, ttyname + 5, sizeof(ll.ll_line));
                    305:       strncpy(ll.ll_host, host, sizeof(ll.ll_host));
                    306: #ifdef LASTLOG_IS_DIR
1.3       deraadt   307:       snprintf(lastlogfile, sizeof lastlogfile, "%.100s/%.100s",
                    308:         lastlog, user);
1.1       deraadt   309:       fd = open(lastlogfile, O_WRONLY | O_CREAT, 0644);
                    310:       if (fd >= 0)
                    311:        {
                    312:          if (write(fd, &ll, sizeof(ll)) != sizeof(ll))
                    313:            log("Could not write %.100s: %.100s",
                    314:                lastlogfile, strerror(errno));
                    315:          close(fd);
                    316:        }
                    317:       else
                    318:        {
                    319:          log("Could not open %.100s: %.100s", lastlogfile, strerror(errno));
                    320:        }
                    321: #else /* LASTLOG_IS_DIR */
                    322:       fd = open(lastlog, O_RDWR);
                    323:       if (fd >= 0)
                    324:        {
                    325:          lseek(fd, (off_t)((long)uid * sizeof(ll)), 0);
                    326:          if (write(fd, &ll, sizeof(ll)) != sizeof(ll))
                    327:            log("Could not write %.100s: %.100s", lastlog, strerror(errno));
                    328:          close(fd);
                    329:        }
                    330: #endif /* LASTLOG_IS_DIR */
                    331:     }
                    332: #endif /* HAVE_LASTLOG_H || HAVE_LASTLOG */
                    333:
                    334: #ifdef HAVE_USERSEC_H
                    335:
                    336:   if (strcmp(user, "") != 0)
                    337:     {
                    338:       int lasttime = time(NULL);
                    339:       if (setuserdb(S_WRITE) < 0)
                    340:        log("setuserdb S_WRITE failed: %.100s", strerror(errno));
                    341:       if (putuserattr((char *)user, S_LASTTIME, (void *)lasttime, SEC_INT) < 0)
                    342:        log("putuserattr S_LASTTIME failed: %.100s", strerror(errno));
                    343:       if (putuserattr((char *)user, S_LASTTTY, (void *)(ttyname + 5),
                    344:                      SEC_CHAR) < 0)
                    345:        log("putuserattr S_LASTTTY %.900s failed: %.100s",
                    346:            ttyname, strerror(errno));
                    347:       if (putuserattr((char *)user, S_LASTHOST, (void *)host, SEC_CHAR) < 0)
                    348:        log("putuserattr S_LASTHOST %.900s failed: %.100s",
                    349:            host, strerror(errno));
                    350:       if (putuserattr((char *)user, 0, NULL, SEC_COMMIT) < 0)
                    351:        log("putuserattr SEC_COMMIT failed: %.100s", strerror(errno));
                    352:       if (enduserdb() < 0)
                    353:        log("enduserdb failed: %.100s", strerror(errno));
                    354:     }
                    355: #endif
                    356: }
                    357:
                    358: /* Records that the user has logged out. */
                    359:
                    360: void record_logout(int pid, const char *ttyname)
                    361: {
                    362: #ifdef HAVE_LIBUTIL_LOGIN
                    363:   const char *line = ttyname + 5; /* /dev/ttyq8 -> ttyq8 */
                    364:   if (logout(line))
                    365:     logwtmp(line, "", "");
                    366: #else /* HAVE_LIBUTIL_LOGIN */
                    367:   record_login(pid, ttyname, "", -1, "", NULL);
                    368: #endif /* HAVE_LIBUTIL_LOGIN */
                    369: }