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