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