blob: 6fdc71e68809dd136421b4d4b11aa439b49d4b69 [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 Miller2f6a0ad2000-05-31 11:20:11 +100021RCSID("$Id: login.c,v 1.29 2000/05/31 01:20:12 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 Miller2f6a0ad2000-05-31 11:20:11 +100041#ifdef WITH_AIXAUTHENTICATE
42/* This is done in do_authentication */
43# define DISABLE_LASTLOG
44#endif /* WITH_AIXAUTHENTICATE */
45
Damien Miller5428f641999-11-25 11:54:57 +110046/*
47 * Returns the time when the user last logged in. Returns 0 if the
48 * information is not available. This must be called before record_login.
49 * The host the user logged in from will be returned in buf.
50 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100051
Damien Miller5428f641999-11-25 11:54:57 +110052/*
53 * Returns the time when the user last logged in (or 0 if no previous login
54 * is found). The name of the host used last time is returned in buf.
55 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100056
Damien Miller4af51302000-04-16 11:18:38 +100057unsigned long
Damien Miller95def091999-11-25 00:26:21 +110058get_last_login_time(uid_t uid, const char *logname,
59 char *buf, unsigned int bufsize)
Damien Millerd4a8b7e1999-10-27 13:42:43 +100060{
Damien Miller1b0c2281999-12-22 16:09:48 +110061#if defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG)
Damien Miller95def091999-11-25 00:26:21 +110062 struct lastlog ll;
Damien Miller95def091999-11-25 00:26:21 +110063 int fd;
Damien Miller2f6a0ad2000-05-31 11:20:11 +100064# ifdef LASTLOG_IS_DIR
Damien Millerdef0dc92000-01-23 20:18:35 +110065 char lbuf[1024];
Damien Millerd4a8b7e1999-10-27 13:42:43 +100066
Damien Miller2f6a0ad2000-05-31 11:20:11 +100067 snprintf(lbuf, sizeof(buf), "%s/%s", _PATH_LASTLOG, logname);
68 if ((fd = open(lbuf, O_RDONLY)) < 0)
69 return 0;
70# else /* LASTLOG_IS_DIR */
Damien Miller95def091999-11-25 00:26:21 +110071 buf[0] = '\0';
Damien Millerd4a8b7e1999-10-27 13:42:43 +100072
Damien Miller2f6a0ad2000-05-31 11:20:11 +100073 if ((fd = open(_PATH_LASTLOG, O_RDONLY)) < 0)
Damien Miller95def091999-11-25 00:26:21 +110074 return 0;
Damien Miller2f6a0ad2000-05-31 11:20:11 +100075
Damien Miller95def091999-11-25 00:26:21 +110076 lseek(fd, (off_t) ((long) uid * sizeof(ll)), SEEK_SET);
Damien Miller2f6a0ad2000-05-31 11:20:11 +100077# endif /* LASTLOG_IS_DIR */
Damien Miller95def091999-11-25 00:26:21 +110078 if (read(fd, &ll, sizeof(ll)) != sizeof(ll)) {
79 close(fd);
80 return 0;
81 }
Damien Miller2f6a0ad2000-05-31 11:20:11 +100082
Damien Miller95def091999-11-25 00:26:21 +110083 close(fd);
Damien Miller2f6a0ad2000-05-31 11:20:11 +100084
Damien Miller95def091999-11-25 00:26:21 +110085 if (bufsize > sizeof(ll.ll_host) + 1)
86 bufsize = sizeof(ll.ll_host) + 1;
87 strncpy(buf, ll.ll_host, bufsize - 1);
88 buf[bufsize - 1] = 0;
Damien Miller76112de1999-12-21 11:18:08 +110089
Damien Miller2f6a0ad2000-05-31 11:20:11 +100090 return ll.ll_time;
Damien Miller1b0c2281999-12-22 16:09:48 +110091#else /* defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG) */
Damien Miller8d1fd572000-05-17 21:34:07 +100092# ifdef HAVE_TYPE_IN_UTMP
Damien Miller76112de1999-12-21 11:18:08 +110093 /* Look in wtmp for the last login */
94 struct utmp wt;
Damien Miller2f6a0ad2000-05-31 11:20:11 +100095 int fd1;
Damien Miller76112de1999-12-21 11:18:08 +110096 unsigned long t = 0;
97
Damien Miller2f6a0ad2000-05-31 11:20:11 +100098 if ((fd1 = open(_PATH_WTMP, O_RDONLY)) < 0) {
99 error("Couldn't open %.100s to find last login time.", _PATH_WTMP);
Damien Miller76112de1999-12-21 11:18:08 +1100100 return 0;
101 }
102
103 /* seek to last record of file */
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000104 lseek(fd1, (off_t)(0 - sizeof(struct utmp)), SEEK_END);
Damien Miller76112de1999-12-21 11:18:08 +1100105
106 /* loop through wtmp for our last user login record */
107 do {
108 if (read(fd1, &wt, sizeof(wt)) != sizeof(wt)) {
109 close(fd1);
110 return 0;
111 }
112
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000113 if (wt.ut_type == USER_PROCESS) {
114 if (!strncmp(logname, wt.ut_user, 8)) {
115 t = (unsigned long)wt.ut_time;
116# ifdef HAVE_HOST_IN_UTMP
Damien Miller76112de1999-12-21 11:18:08 +1100117 if (bufsize > sizeof(wt.ut_host) + 1)
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000118 bufsize = sizeof(wt.ut_host) + 1;
Damien Miller76112de1999-12-21 11:18:08 +1100119 strncpy(buf, wt.ut_host, bufsize - 1);
120 buf[bufsize - 1] = 0;
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000121# else /* HAVE_HOST_IN_UTMP */
Damien Miller1b0c2281999-12-22 16:09:48 +1100122 buf[0] = 0;
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000123# endif /* HAVE_HOST_IN_UTMP */
Damien Miller76112de1999-12-21 11:18:08 +1100124 }
125 }
126
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000127 if (lseek(fd1, (off_t)(0 - (2 * sizeof(struct utmp))), SEEK_CUR) < 0)
Damien Miller76112de1999-12-21 11:18:08 +1100128 break;
129 } while (t == 0);
130
131 return t;
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000132# else /* HAVE_TYPE_IN_UTMP */
Damien Miller8d1fd572000-05-17 21:34:07 +1000133 return 0;
134# endif /* HAVE_TYPE_IN_UTMP */
Damien Miller1b0c2281999-12-22 16:09:48 +1100135#endif /* defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG) */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000136}
137
Damien Miller5428f641999-11-25 11:54:57 +1100138/*
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000139 * Records that the user has logged in. I wish these parts of operating
140 * systems were more standardized.
Damien Miller5428f641999-11-25 11:54:57 +1100141 */
Damien Miller4af51302000-04-16 11:18:38 +1000142void
Damien Miller166fca82000-04-20 07:42:21 +1000143record_login(pid_t pid, const char *ttyname, const char *user, uid_t uid,
Damien Miller34132e52000-01-14 15:45:46 +1100144 const char *host, struct sockaddr * addr)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000145{
Damien Miller1b0c2281999-12-22 16:09:48 +1100146#if defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG)
Damien Miller95def091999-11-25 00:26:21 +1100147 struct lastlog ll;
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000148# ifdef LASTLOG_IS_DIR
Damien Miller6b85a7f2000-01-02 11:45:33 +1100149 char buf[1024];
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000150# endif /* LASTLOG_IS_DIR */
Damien Miller1b0c2281999-12-22 16:09:48 +1100151#endif /* defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG) */
Damien Miller2e1b0821999-12-25 10:11:29 +1100152 struct utmp u;
153#if defined(HAVE_UTMPX_H) && defined(USE_UTMPX)
154 struct utmpx utx;
155#endif
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000156
Damien Miller95def091999-11-25 00:26:21 +1100157 /* Construct an utmp/wtmp entry. */
158 memset(&u, 0, sizeof(u));
159 strncpy(u.ut_line, ttyname + 5, sizeof(u.ut_line));
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000160
Damien Miller9550a761999-12-29 02:32:22 +1100161#if defined(HAVE_ID_IN_UTMP)
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000162# ifdef _AIX
Damien Miller0e489dc2000-05-01 22:53:53 +1000163 strncpy(u.ut_id, ttyname + 5, sizeof(u.ut_id));
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000164# else /* !AIX */
Damien Millere1276241999-12-27 11:33:56 +1100165 strncpy(u.ut_id, ttyname + 8, sizeof(u.ut_id));
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000166# endif
Damien Miller9550a761999-12-29 02:32:22 +1100167#endif /* defined(HAVE_ID_IN_UTMP) */
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000168
Damien Miller95def091999-11-25 00:26:21 +1100169 strncpy(u.ut_name, user, sizeof(u.ut_name));
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000170
Damien Miller4ff2b9b1999-12-28 10:41:12 +1100171#if defined(HAVE_TV_IN_UTMP)
172 (void)gettimeofday(&u.ut_tv, NULL);
173#else /* defined(HAVE_TV_IN_UTMP) */
174 u.ut_time = time(NULL);
175#endif /* defined(HAVE_TV_IN_UTMP) */
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000176
Damien Miller4ff2b9b1999-12-28 10:41:12 +1100177#if defined(HAVE_PID_IN_UTMP)
178 u.ut_pid = (pid_t)pid;
179#endif /* HAVE_PID_IN_UTMP */
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000180
Damien Miller4ff2b9b1999-12-28 10:41:12 +1100181#if defined(HAVE_TYPE_IN_UTMP)
Damien Miller2e1b0821999-12-25 10:11:29 +1100182 u.ut_type = (uid == -1)?DEAD_PROCESS:USER_PROCESS;
Damien Miller4ff2b9b1999-12-28 10:41:12 +1100183#endif /* HAVE_TYPE_IN_UTMP */
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000184
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 Miller2f6a0ad2000-05-31 11:20:11 +1000188
Damien Miller3131d8b1999-12-31 09:42:24 +1100189#if defined(HAVE_ADDR_IN_UTMP)
Damien Millerd89c24b2000-01-26 11:04:48 +1100190 if (addr) {
191 switch (addr->sa_family) {
192 case AF_INET: {
193 struct sockaddr_in *in = (struct sockaddr_in*)addr;
194 memcpy(&(u.ut_addr), &(in->sin_addr), sizeof(&(in->sin_addr)));
195 break;
196 }
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000197# if defined(HAVE_ADDR_V6_IN_UTMP)
Damien Millerd89c24b2000-01-26 11:04:48 +1100198 case AF_INET6: {
199 struct sockaddr_in6 *in6 = (struct sockaddr_in6*)addr;
200 memcpy(u.ut_addr_v6, &(in6->sin6_addr), sizeof(&(in6->sin6_addr)));
201 break;
202 }
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000203# endif /* defined(HAVE_ADDR_V6_IN_UTMP) */
Damien Millerd89c24b2000-01-26 11:04:48 +1100204 default:
205 break;
206 }
Damien Miller34132e52000-01-14 15:45:46 +1100207 }
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000208#endif /* defined(HAVE_ADDR_IN_UTMP) */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000209
Damien Miller2e1b0821999-12-25 10:11:29 +1100210#if defined(HAVE_UTMPX_H) && defined(USE_UTMPX)
211 memset(&utx, 0, sizeof(utx));
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000212
Damien Miller2e1b0821999-12-25 10:11:29 +1100213 strncpy(utx.ut_user, user, sizeof(utx.ut_name));
214 strncpy(utx.ut_line, ttyname + 5, sizeof(utx.ut_line));
Damien Millere1276241999-12-27 11:33:56 +1100215 strncpy(utx.ut_id, ttyname + 8, sizeof(utx.ut_id));
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000216
Damien Miller2e1b0821999-12-25 10:11:29 +1100217 utx.ut_pid = (pid_t)pid;
Damien Miller4ff2b9b1999-12-28 10:41:12 +1100218 (void)gettimeofday(&utx.ut_tv, NULL);
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000219
Damien Miller32b3cf21999-12-26 10:21:48 +1100220 utx.ut_type = (uid == -1)?DEAD_PROCESS:USER_PROCESS;
221# ifdef HAVE_HOST_IN_UTMPX
222# ifdef HAVE_SYSLEN_IN_UTMPX
Damien Miller2e1b0821999-12-25 10:11:29 +1100223 utx.ut_syslen = strlen(host);
Damien Millerc252e2e2000-05-30 13:12:46 +1000224 if (utx.ut_syslen + 1 > sizeof(utx.ut_host))
225 utx.ut_syslen = sizeof(utx.ut_host);
Damien Miller32b3cf21999-12-26 10:21:48 +1100226 strncpy(utx.ut_host, host, utx.ut_syslen);
227# else
Damien Miller2e1b0821999-12-25 10:11:29 +1100228 strncpy(utx.ut_host, host, sizeof(utx.ut_host));
Damien Miller32b3cf21999-12-26 10:21:48 +1100229# endif /* HAVE_SYSLEN_IN_UTMPX */
Damien Millerc252e2e2000-05-30 13:12:46 +1000230 utx.ut_host[sizeof(utx.ut_host)-1] = '\0';
Damien Miller32b3cf21999-12-26 10:21:48 +1100231# endif
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000232
233# if defined(HAVE_ADDR_IN_UTMPX)
Damien Miller6034fdf2000-01-29 20:55:09 +1100234 if (addr) {
Damien Millerd89c24b2000-01-26 11:04:48 +1100235 switch (addr->sa_family) {
236 case AF_INET: {
237 struct sockaddr_in *in = (struct sockaddr_in*)addr;
238 memcpy(&(utx.ut_addr), &(in->sin_addr), sizeof(&(in->sin_addr)));
239 break;
240 }
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000241# if defined(HAVE_ADDR_V6_IN_UTMPX)
Damien Millerd89c24b2000-01-26 11:04:48 +1100242 case AF_INET6: {
243 struct sockaddr_in6 *in6 = (struct sockaddr_in6*)addr;
244 memcpy(utx.ut_addr_v6, &(in6->sin6_addr), sizeof(&(in6->sin6_addr)));
245 break;
246 }
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000247# endif /* defined(HAVE_ADDR_V6_IN_UTMPX) */
Damien Millerd89c24b2000-01-26 11:04:48 +1100248 default:
249 break;
250 }
Damien Miller34132e52000-01-14 15:45:46 +1100251 }
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000252# endif /* defined(HAVE_ADDR_IN_UTMPX) */
Damien Miller2e1b0821999-12-25 10:11:29 +1100253#endif /* defined(HAVE_UTMPX_H) && defined(USE_UTMPX) */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000254
Damien Miller32b3cf21999-12-26 10:21:48 +1100255#if defined(HAVE_UTMPX_H) && defined(USE_UTMPX)
Damien Miller2e1b0821999-12-25 10:11:29 +1100256 login(&u, &utx);
257#else /* defined(HAVE_UTMPX_H) && defined(USE_UTMPX) */
Damien Miller95def091999-11-25 00:26:21 +1100258 login(&u);
Damien Miller2e1b0821999-12-25 10:11:29 +1100259#endif /* defined(HAVE_UTMPX_H) && defined(USE_UTMPX) */
Damien Miller76112de1999-12-21 11:18:08 +1100260
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000261#if defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG)
Damien Miller95def091999-11-25 00:26:21 +1100262 /* Update lastlog unless actually recording a logout. */
263 if (strcmp(user, "") != 0) {
Damien Miller76112de1999-12-21 11:18:08 +1100264 int fd;
Damien Miller5428f641999-11-25 11:54:57 +1100265 /*
266 * It is safer to bzero the lastlog structure first because
267 * some systems might have some extra fields in it (e.g. SGI)
268 */
Damien Miller95def091999-11-25 00:26:21 +1100269 memset(&ll, 0, sizeof(ll));
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000270
Damien Miller95def091999-11-25 00:26:21 +1100271 /* Update lastlog. */
272 ll.ll_time = time(NULL);
273 strncpy(ll.ll_line, ttyname + 5, sizeof(ll.ll_line));
274 strncpy(ll.ll_host, host, sizeof(ll.ll_host));
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000275# ifdef LASTLOG_IS_DIR
276 snprintf(buf, sizeof(buf), "%s/%s", _PATH_LASTLOG, user);
277 if ((fd = open(buf, O_RDWR)) >= 0) {
Damien Miller95def091999-11-25 00:26:21 +1100278 if (write(fd, &ll, sizeof(ll)) != sizeof(ll))
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000279 log("Could not write %.100s: %.100s", buf, strerror(errno));
Damien Miller95def091999-11-25 00:26:21 +1100280 close(fd);
281 }
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000282# else /* LASTLOG_IS_DIR */
283 if ((fd = open(_PATH_LASTLOG, O_RDWR)) >= 0) {
284 lseek(fd, (off_t) ((long) uid * sizeof(ll)), SEEK_SET);
285 if (write(fd, &ll, sizeof(ll)) != sizeof(ll)) {
286 log("Could not write %.100s: %.100s", _PATH_LASTLOG,
287 strerror(errno));
288 }
289 close(fd);
290 }
291# endif /* LASTLOG_IS_DIR */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000292 }
Damien Miller2f6a0ad2000-05-31 11:20:11 +1000293#endif /* defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG) */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000294}
Damien Miller95def091999-11-25 00:26:21 +1100295
296/* Records that the user has logged out. */
297
Damien Miller4af51302000-04-16 11:18:38 +1000298void
Damien Miller166fca82000-04-20 07:42:21 +1000299record_logout(pid_t pid, const char *ttyname)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000300{
Damien Millerab18c411999-11-11 10:40:23 +1100301#ifdef HAVE_LIBUTIL_LOGIN
Damien Miller95def091999-11-25 00:26:21 +1100302 const char *line = ttyname + 5; /* /dev/ttyq8 -> ttyq8 */
303 if (logout(line))
304 logwtmp(line, "", "");
Damien Millerab18c411999-11-11 10:40:23 +1100305#else /* HAVE_LIBUTIL_LOGIN */
Damien Miller95def091999-11-25 00:26:21 +1100306 record_login(pid, ttyname, "", -1, "", NULL);
Damien Millerab18c411999-11-11 10:40:23 +1100307#endif /* HAVE_LIBUTIL_LOGIN */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000308}