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