blob: 49853bdc29870b4cd342476819d932e175a6dab1 [file] [log] [blame]
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001/*
Damien Miller4af51302000-04-16 11:18:38 +10002 *
Damien Miller95def091999-11-25 00:26:21 +11003 * login.c
Damien Miller4af51302000-04-16 11:18:38 +10004 *
Damien Miller95def091999-11-25 00:26:21 +11005 * Author: Tatu Ylonen <ylo@cs.hut.fi>
Damien Miller4af51302000-04-16 11:18:38 +10006 *
Damien Miller95def091999-11-25 00:26:21 +11007 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 * All rights reserved
Damien Miller4af51302000-04-16 11:18:38 +10009 *
Damien Miller95def091999-11-25 00:26:21 +110010 * Created: Fri Mar 24 14:51:08 1995 ylo
Damien Miller4af51302000-04-16 11:18:38 +100011 *
Damien Miller95def091999-11-25 00:26:21 +110012 * 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.
Damien Miller4af51302000-04-16 11:18:38 +100017 *
Damien Miller95def091999-11-25 00:26:21 +110018 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100019
20#include "includes.h"
Damien Millerd2c208a2000-05-17 22:00:02 +100021RCSID("$Id: login.c,v 1.27 2000/05/17 12:00:03 damien Exp $");
Damien Millerd4a8b7e1999-10-27 13:42:43 +100022
Damien Miller368cf641999-12-21 09:51:36 +110023#if defined(HAVE_UTMPX_H) && defined(USE_UTMPX)
Damien Millerbf1c9b21999-12-09 10:16:54 +110024# include <utmpx.h>
25#endif
26#ifdef HAVE_UTMP_H
27# include <utmp.h>
28#endif
Damien Miller95def091999-11-25 00:26:21 +110029#include "ssh.h"
Damien Millerab18c411999-11-11 10:40:23 +110030
Damien Miller95def091999-11-25 00:26:21 +110031#ifdef HAVE_UTIL_H
32# include <util.h>
33#endif
Damien Millerab18c411999-11-11 10:40:23 +110034#ifdef HAVE_LASTLOG_H
35# include <lastlog.h>
36#endif
Damien Miller063fdf81999-11-25 13:08:31 +110037#ifdef HAVE_LOGIN_H
38# include <login.h>
39#endif
Damien Millerab18c411999-11-11 10:40:23 +110040
Damien Miller5428f641999-11-25 11:54:57 +110041/*
42 * Returns the time when the user last logged in. Returns 0 if the
43 * information is not available. This must be called before record_login.
44 * The host the user logged in from will be returned in buf.
45 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100046
Damien Miller5428f641999-11-25 11:54:57 +110047/*
48 * Returns the time when the user last logged in (or 0 if no previous login
49 * is found). The name of the host used last time is returned in buf.
50 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100051
Damien Miller4af51302000-04-16 11:18:38 +100052unsigned long
Damien Miller95def091999-11-25 00:26:21 +110053get_last_login_time(uid_t uid, const char *logname,
54 char *buf, unsigned int bufsize)
Damien Millerd4a8b7e1999-10-27 13:42:43 +100055{
Damien Millerd2c208a2000-05-17 22:00:02 +100056#if defined(WITH_AIXAUTHENTICATE)
57 /* This is done in do_authentication */
58 return (unsigned long) 0;
59#else
Damien Miller1b0c2281999-12-22 16:09:48 +110060#if defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG)
Damien Miller95def091999-11-25 00:26:21 +110061 struct lastlog ll;
62 char *lastlog;
63 int fd;
Damien Miller6b85a7f2000-01-02 11:45:33 +110064#ifdef LASTLOG_IS_DIR
Damien Millerdef0dc92000-01-23 20:18:35 +110065 char lbuf[1024];
Damien Miller6b85a7f2000-01-02 11:45:33 +110066#endif /* LASTLOG_IS_DIR */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100067
Damien Miller95def091999-11-25 00:26:21 +110068 lastlog = _PATH_LASTLOG;
69 buf[0] = '\0';
Damien Millerd4a8b7e1999-10-27 13:42:43 +100070
Damien Millerdef0dc92000-01-23 20:18:35 +110071#ifndef LASTLOG_IS_DIR
Damien Miller95def091999-11-25 00:26:21 +110072 fd = open(lastlog, O_RDONLY);
73 if (fd < 0)
74 return 0;
75 lseek(fd, (off_t) ((long) uid * sizeof(ll)), SEEK_SET);
Damien Miller6b85a7f2000-01-02 11:45:33 +110076#else /* LASTLOG_IS_DIR */
Damien Millerdef0dc92000-01-23 20:18:35 +110077 snprintf(lbuf, sizeof(buf), "%s/%s", lastlog, logname);
78 fd = open(lbuf, O_RDONLY);
Damien Miller6b85a7f2000-01-02 11:45:33 +110079 if (fd < 0)
80 return 0;
81#endif /* LASTLOG_IS_DIR */
Damien Miller95def091999-11-25 00:26:21 +110082 if (read(fd, &ll, sizeof(ll)) != sizeof(ll)) {
83 close(fd);
84 return 0;
85 }
86 close(fd);
87 if (bufsize > sizeof(ll.ll_host) + 1)
88 bufsize = sizeof(ll.ll_host) + 1;
89 strncpy(buf, ll.ll_host, bufsize - 1);
90 buf[bufsize - 1] = 0;
91 return ll.ll_time;
Damien Miller76112de1999-12-21 11:18:08 +110092
Damien Miller1b0c2281999-12-22 16:09:48 +110093#else /* defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG) */
Damien Miller8d1fd572000-05-17 21:34:07 +100094# ifdef HAVE_TYPE_IN_UTMP
Damien Miller76112de1999-12-21 11:18:08 +110095 /* Look in wtmp for the last login */
96 struct utmp wt;
97 char *wt_file = _PATH_WTMP;
98 int fd1;
99 unsigned long t = 0;
100
101 if ( (fd1 = open(wt_file, O_RDONLY)) < 0 ) {
102 error("Couldn't open %.100s to find last login time.", wt_file);
103 return 0;
104 }
105
106 /* seek to last record of file */
107 lseek(fd1, (off_t)(0-sizeof(struct utmp)), SEEK_END);
108
109 /* loop through wtmp for our last user login record */
110 do {
111 if (read(fd1, &wt, sizeof(wt)) != sizeof(wt)) {
112 close(fd1);
113 return 0;
114 }
115
116 if ( wt.ut_type == USER_PROCESS) {
117 if ( !strncmp(logname, wt.ut_user, 8) ) {
118 t = (unsigned long) wt.ut_time;
Damien Miller8d1fd572000-05-17 21:34:07 +1000119# ifdef HAVE_HOST_IN_UTMP
Damien Miller76112de1999-12-21 11:18:08 +1100120 if (bufsize > sizeof(wt.ut_host) + 1)
121 bufsize = sizeof(wt.ut_host) + 1;
122 strncpy(buf, wt.ut_host, bufsize - 1);
123 buf[bufsize - 1] = 0;
Damien Miller8d1fd572000-05-17 21:34:07 +1000124# else /* HAVE_HOST_IN_UTMP */
Damien Miller1b0c2281999-12-22 16:09:48 +1100125 buf[0] = 0;
Damien Miller8d1fd572000-05-17 21:34:07 +1000126# endif /* HAVE_HOST_IN_UTMP */
Damien Miller76112de1999-12-21 11:18:08 +1100127 }
128 }
129
130 if (lseek(fd1, (off_t)(0-2*sizeof(struct utmp)), SEEK_CUR) == -1)
131 break;
132 } while (t == 0);
133
134 return t;
Damien Miller8d1fd572000-05-17 21:34:07 +1000135# else
136 return 0;
137# endif /* HAVE_TYPE_IN_UTMP */
Damien Miller1b0c2281999-12-22 16:09:48 +1100138#endif /* defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG) */
Damien Millerd2c208a2000-05-17 22:00:02 +1000139#endif /* defined(WITH_AIXAUTHENTICATE) */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000140}
141
Damien Miller5428f641999-11-25 11:54:57 +1100142/*
143 * Records that the user has logged in. I these parts of operating systems
144 * were more standardized.
145 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000146
Damien Miller4af51302000-04-16 11:18:38 +1000147void
Damien Miller166fca82000-04-20 07:42:21 +1000148record_login(pid_t pid, const char *ttyname, const char *user, uid_t uid,
Damien Miller34132e52000-01-14 15:45:46 +1100149 const char *host, struct sockaddr * addr)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000150{
Damien Miller1b0c2281999-12-22 16:09:48 +1100151#if defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG)
Damien Miller95def091999-11-25 00:26:21 +1100152 struct lastlog ll;
153 char *lastlog;
Damien Miller6b85a7f2000-01-02 11:45:33 +1100154#ifdef LASTLOG_IS_DIR
155 char buf[1024];
156#endif /* LASTLOG_IS_DIR */
Damien Miller1b0c2281999-12-22 16:09:48 +1100157#endif /* defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG) */
Damien Miller2e1b0821999-12-25 10:11:29 +1100158 struct utmp u;
159#if defined(HAVE_UTMPX_H) && defined(USE_UTMPX)
160 struct utmpx utx;
161#endif
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000162
Damien Miller95def091999-11-25 00:26:21 +1100163 /* Construct an utmp/wtmp entry. */
164 memset(&u, 0, sizeof(u));
165 strncpy(u.ut_line, ttyname + 5, sizeof(u.ut_line));
Damien Miller9550a761999-12-29 02:32:22 +1100166#if defined(HAVE_ID_IN_UTMP)
Damien Miller0e489dc2000-05-01 22:53:53 +1000167#ifdef _AIX
168 strncpy(u.ut_id, ttyname + 5, sizeof(u.ut_id));
169#else /* !AIX */
Damien Millere1276241999-12-27 11:33:56 +1100170 strncpy(u.ut_id, ttyname + 8, sizeof(u.ut_id));
Damien Miller0e489dc2000-05-01 22:53:53 +1000171#endif
Damien Miller9550a761999-12-29 02:32:22 +1100172#endif /* defined(HAVE_ID_IN_UTMP) */
Damien Miller95def091999-11-25 00:26:21 +1100173 strncpy(u.ut_name, user, sizeof(u.ut_name));
Damien Miller4ff2b9b1999-12-28 10:41:12 +1100174#if defined(HAVE_TV_IN_UTMP)
175 (void)gettimeofday(&u.ut_tv, NULL);
176#else /* defined(HAVE_TV_IN_UTMP) */
177 u.ut_time = time(NULL);
178#endif /* defined(HAVE_TV_IN_UTMP) */
179#if defined(HAVE_PID_IN_UTMP)
180 u.ut_pid = (pid_t)pid;
181#endif /* HAVE_PID_IN_UTMP */
182#if defined(HAVE_TYPE_IN_UTMP)
Damien Miller2e1b0821999-12-25 10:11:29 +1100183 u.ut_type = (uid == -1)?DEAD_PROCESS:USER_PROCESS;
Damien Miller4ff2b9b1999-12-28 10:41:12 +1100184#endif /* HAVE_TYPE_IN_UTMP */
Damien Miller2e1b0821999-12-25 10:11:29 +1100185#if defined(HAVE_HOST_IN_UTMP)
Damien Miller95def091999-11-25 00:26:21 +1100186 strncpy(u.ut_host, host, sizeof(u.ut_host));
Damien Millerab18c411999-11-11 10:40:23 +1100187#endif
Damien Miller3131d8b1999-12-31 09:42:24 +1100188#if defined(HAVE_ADDR_IN_UTMP)
Damien Millerd89c24b2000-01-26 11:04:48 +1100189 if (addr) {
190 switch (addr->sa_family) {
191 case AF_INET: {
192 struct sockaddr_in *in = (struct sockaddr_in*)addr;
193 memcpy(&(u.ut_addr), &(in->sin_addr), sizeof(&(in->sin_addr)));
194 break;
195 }
Damien Miller34132e52000-01-14 15:45:46 +1100196#if defined(HAVE_ADDR_V6_IN_UTMP)
Damien Millerd89c24b2000-01-26 11:04:48 +1100197 case AF_INET6: {
198 struct sockaddr_in6 *in6 = (struct sockaddr_in6*)addr;
199 memcpy(u.ut_addr_v6, &(in6->sin6_addr), sizeof(&(in6->sin6_addr)));
200 break;
201 }
Damien Miller34132e52000-01-14 15:45:46 +1100202#endif
Damien Millerd89c24b2000-01-26 11:04:48 +1100203 default:
204 break;
205 }
Damien Miller34132e52000-01-14 15:45:46 +1100206 }
Damien Miller3131d8b1999-12-31 09:42:24 +1100207#endif
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000208
Damien Miller2e1b0821999-12-25 10:11:29 +1100209#if defined(HAVE_UTMPX_H) && defined(USE_UTMPX)
210 memset(&utx, 0, sizeof(utx));
211 strncpy(utx.ut_user, user, sizeof(utx.ut_name));
212 strncpy(utx.ut_line, ttyname + 5, sizeof(utx.ut_line));
Damien Millere1276241999-12-27 11:33:56 +1100213 strncpy(utx.ut_id, ttyname + 8, sizeof(utx.ut_id));
Damien Miller2e1b0821999-12-25 10:11:29 +1100214 utx.ut_pid = (pid_t)pid;
Damien Miller4ff2b9b1999-12-28 10:41:12 +1100215 (void)gettimeofday(&utx.ut_tv, NULL);
Damien Miller32b3cf21999-12-26 10:21:48 +1100216 utx.ut_type = (uid == -1)?DEAD_PROCESS:USER_PROCESS;
217# ifdef HAVE_HOST_IN_UTMPX
218# ifdef HAVE_SYSLEN_IN_UTMPX
Damien Miller2e1b0821999-12-25 10:11:29 +1100219 utx.ut_syslen = strlen(host);
Damien Miller32b3cf21999-12-26 10:21:48 +1100220 strncpy(utx.ut_host, host, utx.ut_syslen);
221# else
Damien Miller2e1b0821999-12-25 10:11:29 +1100222 strncpy(utx.ut_host, host, sizeof(utx.ut_host));
Damien Miller32b3cf21999-12-26 10:21:48 +1100223# endif /* HAVE_SYSLEN_IN_UTMPX */
224# endif
Damien Miller34132e52000-01-14 15:45:46 +1100225#if defined(HAVE_ADDR_IN_UTMPX)
Damien Miller6034fdf2000-01-29 20:55:09 +1100226 if (addr) {
Damien Millerd89c24b2000-01-26 11:04:48 +1100227 switch (addr->sa_family) {
228 case AF_INET: {
229 struct sockaddr_in *in = (struct sockaddr_in*)addr;
230 memcpy(&(utx.ut_addr), &(in->sin_addr), sizeof(&(in->sin_addr)));
231 break;
232 }
Damien Miller34132e52000-01-14 15:45:46 +1100233#if defined(HAVE_ADDR_V6_IN_UTMPX)
Damien Millerd89c24b2000-01-26 11:04:48 +1100234 case AF_INET6: {
235 struct sockaddr_in6 *in6 = (struct sockaddr_in6*)addr;
236 memcpy(utx.ut_addr_v6, &(in6->sin6_addr), sizeof(&(in6->sin6_addr)));
237 break;
238 }
Damien Miller34132e52000-01-14 15:45:46 +1100239#endif
Damien Millerd89c24b2000-01-26 11:04:48 +1100240 default:
241 break;
242 }
Damien Miller34132e52000-01-14 15:45:46 +1100243 }
244#endif
Damien Miller2e1b0821999-12-25 10:11:29 +1100245#endif /* defined(HAVE_UTMPX_H) && defined(USE_UTMPX) */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000246
Damien Miller32b3cf21999-12-26 10:21:48 +1100247/*#if defined(HAVE_UTMPX_H) && defined(USE_UTMPX) && !defined(HAVE_LOGIN)*/
248#if defined(HAVE_UTMPX_H) && defined(USE_UTMPX)
Damien Miller2e1b0821999-12-25 10:11:29 +1100249 login(&u, &utx);
250#else /* defined(HAVE_UTMPX_H) && defined(USE_UTMPX) */
Damien Miller95def091999-11-25 00:26:21 +1100251 login(&u);
Damien Miller2e1b0821999-12-25 10:11:29 +1100252#endif /* defined(HAVE_UTMPX_H) && defined(USE_UTMPX) */
Damien Miller76112de1999-12-21 11:18:08 +1100253
Damien Millerd2c208a2000-05-17 22:00:02 +1000254#if defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG) && !defined(WITH_AIXAUTHENTICATE)
255 /* AIX does this in do_authentication */
Damien Miller95def091999-11-25 00:26:21 +1100256 lastlog = _PATH_LASTLOG;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000257
Damien Miller95def091999-11-25 00:26:21 +1100258 /* Update lastlog unless actually recording a logout. */
259 if (strcmp(user, "") != 0) {
Damien Miller76112de1999-12-21 11:18:08 +1100260 int fd;
Damien Miller5428f641999-11-25 11:54:57 +1100261 /*
262 * It is safer to bzero the lastlog structure first because
263 * some systems might have some extra fields in it (e.g. SGI)
264 */
Damien Miller95def091999-11-25 00:26:21 +1100265 memset(&ll, 0, sizeof(ll));
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000266
Damien Miller95def091999-11-25 00:26:21 +1100267 /* Update lastlog. */
268 ll.ll_time = time(NULL);
269 strncpy(ll.ll_line, ttyname + 5, sizeof(ll.ll_line));
270 strncpy(ll.ll_host, host, sizeof(ll.ll_host));
Damien Miller6b85a7f2000-01-02 11:45:33 +1100271#ifdef LASTLOG_IS_DIR
Damien Miller65527582000-02-02 19:17:40 +1100272 snprintf(buf, sizeof(buf), "%s/%s", lastlog, user);
Damien Miller6b85a7f2000-01-02 11:45:33 +1100273 fd = open(buf, O_RDWR);
274 if (fd >= 0) {
275#else /* LASTLOG_IS_DIR */
Damien Miller95def091999-11-25 00:26:21 +1100276 fd = open(lastlog, O_RDWR);
277 if (fd >= 0) {
278 lseek(fd, (off_t) ((long) uid * sizeof(ll)), SEEK_SET);
Damien Miller6b85a7f2000-01-02 11:45:33 +1100279#endif /* LASTLOG_IS_DIR */
Damien Miller95def091999-11-25 00:26:21 +1100280 if (write(fd, &ll, sizeof(ll)) != sizeof(ll))
281 log("Could not write %.100s: %.100s", lastlog, strerror(errno));
282 close(fd);
283 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000284 }
Damien Millerd2c208a2000-05-17 22:00:02 +1000285#endif /* defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG) && !defined(WITH_AIXAUTHENTICATE) */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000286}
Damien Miller95def091999-11-25 00:26:21 +1100287
288/* Records that the user has logged out. */
289
Damien Miller4af51302000-04-16 11:18:38 +1000290void
Damien Miller166fca82000-04-20 07:42:21 +1000291record_logout(pid_t pid, const char *ttyname)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000292{
Damien Millerab18c411999-11-11 10:40:23 +1100293#ifdef HAVE_LIBUTIL_LOGIN
Damien Miller95def091999-11-25 00:26:21 +1100294 const char *line = ttyname + 5; /* /dev/ttyq8 -> ttyq8 */
295 if (logout(line))
296 logwtmp(line, "", "");
Damien Millerab18c411999-11-11 10:40:23 +1100297#else /* HAVE_LIBUTIL_LOGIN */
Damien Miller95def091999-11-25 00:26:21 +1100298 record_login(pid, ttyname, "", -1, "", NULL);
Damien Millerab18c411999-11-11 10:40:23 +1100299#endif /* HAVE_LIBUTIL_LOGIN */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000300}