]> andersk Git - openssh.git/blob - login.c
a1a336140c96249e26bf01b1e25b993e4d04d341
[openssh.git] / login.c
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$");
22
23 #if defined(HAVE_UTMPX_H) && defined(USE_UTMPX)
24 # include <utmpx.h>
25 #endif
26 #ifdef HAVE_UTMP_H
27 # include <utmp.h>
28 #endif
29 #include "ssh.h"
30
31 #ifdef HAVE_UTIL_H
32 # include <util.h>
33 #endif
34 #ifdef HAVE_LASTLOG_H
35 # include <lastlog.h>
36 #endif
37 #ifdef HAVE_LOGIN_H
38 # include <login.h>
39 #endif
40
41 #ifdef WITH_AIXAUTHENTICATE
42 /* This is done in do_authentication */
43 # define DISABLE_LASTLOG
44 #endif /* WITH_AIXAUTHENTICATE */
45
46 /*
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  */
51
52 /*
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  */
56
57 unsigned long
58 get_last_login_time(uid_t uid, const char *logname,
59                     char *buf, unsigned int bufsize)
60 {
61 #if defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG)
62         struct lastlog ll;
63         int fd;
64 # ifdef LASTLOG_IS_DIR
65         char lbuf[1024];
66
67         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 */
71         buf[0] = '\0';
72
73         if ((fd = open(_PATH_LASTLOG, O_RDONLY)) < 0)
74                 return 0;
75
76         lseek(fd, (off_t) ((long) uid * sizeof(ll)), SEEK_SET);
77 # endif /* LASTLOG_IS_DIR */
78         if (read(fd, &ll, sizeof(ll)) != sizeof(ll)) {
79                 close(fd);
80                 return 0;
81         }
82
83         close(fd);
84
85         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;
89
90         return ll.ll_time;
91 #else /* defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG) */
92 # ifdef HAVE_TYPE_IN_UTMP
93         /* Look in wtmp for the last login */
94         struct utmp  wt;
95         int fd1;
96         unsigned long t = 0;
97
98         if ((fd1 = open(_PATH_WTMP, O_RDONLY)) < 0) {
99                 error("Couldn't open %.100s to find last login time.", _PATH_WTMP);
100                 return 0;
101         }
102
103         /* seek to last record of file */
104         lseek(fd1, (off_t)(0 - sizeof(struct utmp)), SEEK_END);
105
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
113                 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
117                                 if (bufsize > sizeof(wt.ut_host) + 1)
118                                         bufsize = sizeof(wt.ut_host) + 1;
119                                 strncpy(buf, wt.ut_host, bufsize - 1);
120                                 buf[bufsize - 1] = 0;
121 #  else /* HAVE_HOST_IN_UTMP */
122                                 buf[0] = 0;
123 #  endif /* HAVE_HOST_IN_UTMP */
124                         }
125                 }
126
127                 if (lseek(fd1, (off_t)(0 - (2 * sizeof(struct utmp))), SEEK_CUR) < 0)
128                         break;
129         } while (t == 0);
130
131         return t;
132 # else /* HAVE_TYPE_IN_UTMP */
133         return 0;
134 # endif /* HAVE_TYPE_IN_UTMP */
135 #endif /* defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG) */
136 }
137
138 /*
139  * Records that the user has logged in.  I wish these parts of operating 
140  * systems were more standardized.
141  */
142 void
143 record_login(pid_t pid, const char *ttyname, const char *user, uid_t uid,
144              const char *host, struct sockaddr * addr)
145 {
146 #if defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG)
147         struct lastlog ll;
148 # ifdef LASTLOG_IS_DIR
149         char buf[1024];
150 # endif /* LASTLOG_IS_DIR */
151 #endif /* defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG) */
152         struct utmp u;
153 #if defined(HAVE_UTMPX_H) && defined(USE_UTMPX)
154         struct utmpx utx;
155 #endif
156
157         /* Construct an utmp/wtmp entry. */
158         memset(&u, 0, sizeof(u));
159         strncpy(u.ut_line, ttyname + 5, sizeof(u.ut_line));
160         
161 #if defined(HAVE_ID_IN_UTMP)
162 # ifdef _AIX
163         strncpy(u.ut_id, ttyname + 5, sizeof(u.ut_id));
164 # else /* !AIX */
165         strncpy(u.ut_id, ttyname + 8, sizeof(u.ut_id));
166 # endif
167 #endif /* defined(HAVE_ID_IN_UTMP) */ 
168
169         strncpy(u.ut_name, user, sizeof(u.ut_name));
170         
171 #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) */
176
177 #if defined(HAVE_PID_IN_UTMP)
178         u.ut_pid = (pid_t)pid;
179 #endif /* HAVE_PID_IN_UTMP */
180
181 #if defined(HAVE_TYPE_IN_UTMP)
182         u.ut_type = (uid == -1)?DEAD_PROCESS:USER_PROCESS;
183 #endif /* HAVE_TYPE_IN_UTMP */
184
185 #if defined(HAVE_HOST_IN_UTMP)
186         strncpy(u.ut_host, host, sizeof(u.ut_host));
187 #endif
188
189 #if defined(HAVE_ADDR_IN_UTMP)
190         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                         }
197 # if defined(HAVE_ADDR_V6_IN_UTMP)
198                         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                         }
203 # endif /* defined(HAVE_ADDR_V6_IN_UTMP) */
204                         default:
205                                 break;
206                 }
207         }
208 #endif /* defined(HAVE_ADDR_IN_UTMP) */
209
210 #if defined(HAVE_UTMPX_H) && defined(USE_UTMPX)
211         memset(&utx, 0, sizeof(utx));
212
213         strncpy(utx.ut_user, user, sizeof(utx.ut_name));
214         strncpy(utx.ut_line, ttyname + 5, sizeof(utx.ut_line));
215         strncpy(utx.ut_id, ttyname + 8, sizeof(utx.ut_id));
216
217         utx.ut_pid = (pid_t)pid;
218         (void)gettimeofday(&utx.ut_tv, NULL);
219         
220         utx.ut_type = (uid == -1)?DEAD_PROCESS:USER_PROCESS;
221 # ifdef HAVE_HOST_IN_UTMPX
222 #  ifdef HAVE_SYSLEN_IN_UTMPX
223         utx.ut_syslen = strlen(host);
224         if (utx.ut_syslen + 1 > sizeof(utx.ut_host))
225                 utx.ut_syslen = sizeof(utx.ut_host);
226         strncpy(utx.ut_host, host, utx.ut_syslen);
227 #  else
228         strncpy(utx.ut_host, host, sizeof(utx.ut_host));
229 #  endif /* HAVE_SYSLEN_IN_UTMPX */
230         utx.ut_host[sizeof(utx.ut_host)-1] = '\0';
231 # endif
232
233 # if defined(HAVE_ADDR_IN_UTMPX)
234         if (addr) {
235                 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                         }
241 #  if defined(HAVE_ADDR_V6_IN_UTMPX)
242                         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                         }
247 #  endif /* defined(HAVE_ADDR_V6_IN_UTMPX) */
248                         default:
249                                 break;
250                 }
251         }
252 # endif /* defined(HAVE_ADDR_IN_UTMPX) */
253 #endif /* defined(HAVE_UTMPX_H) && defined(USE_UTMPX) */
254
255 #if defined(HAVE_UTMPX_H) && defined(USE_UTMPX)
256         login(&utx);
257 #else /* defined(HAVE_UTMPX_H) && defined(USE_UTMPX) */
258         login(&u);
259 #endif /* defined(HAVE_UTMPX_H) && defined(USE_UTMPX) */
260
261 #if defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG)
262         /* Update lastlog unless actually recording a logout. */
263         if (strcmp(user, "") != 0) {
264                 int fd;
265                 /*
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                  */
269                 memset(&ll, 0, sizeof(ll));
270
271                 /* 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));
275 # ifdef LASTLOG_IS_DIR
276                 snprintf(buf, sizeof(buf), "%s/%s", _PATH_LASTLOG, user);
277                 if ((fd = open(buf, O_RDWR)) >= 0) {
278                         if (write(fd, &ll, sizeof(ll)) != sizeof(ll))
279                                 log("Could not write %.100s: %.100s", buf, strerror(errno));
280                         close(fd);
281                 }
282 # 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 */
292         }
293 #endif /* defined(_PATH_LASTLOG) && !defined(DISABLE_LASTLOG) */
294 }
295
296 /* Records that the user has logged out. */
297
298 void
299 record_logout(pid_t pid, const char *ttyname)
300 {
301 #ifdef HAVE_LIBUTIL_LOGIN
302         const char *line = ttyname + 5; /* /dev/ttyq8 -> ttyq8 */
303         if (logout(line))
304                 logwtmp(line, "", "");
305 #else /* HAVE_LIBUTIL_LOGIN */
306         record_login(pid, ttyname, "", -1, "", NULL);
307 #endif /* HAVE_LIBUTIL_LOGIN */
308 }
This page took 0.048597 seconds and 3 git commands to generate.