Annotation of src/usr.bin/ssh/login.c, Revision 1.5
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.5 ! deraadt 21: RCSID("$Id: login.c,v 1.4 1999/09/30 04:10:28 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: if (sizeof(u.ut_id) > 4)
181: strncpy(u.ut_id, ttyname + 5, sizeof(u.ut_id));
182: else
183: strncpy(u.ut_id, ttyname + strlen(ttyname) - 2, sizeof(u.ut_id));
184: #endif /* HAVE_ID_IN_UTMP */
185: strncpy(u.ut_line, ttyname + 5, sizeof(u.ut_line));
186: u.ut_time = time(NULL);
187: #ifdef HAVE_NAME_IN_UTMP
188: strncpy(u.ut_name, user, sizeof(u.ut_name));
189: #else /* HAVE_NAME_IN_UTMP */
190: strncpy(u.ut_user, user, sizeof(u.ut_user));
191: #endif /* HAVE_NAME_IN_UTMP */
192: #ifdef HAVE_HOST_IN_UTMP
193: strncpy(u.ut_host, host, sizeof(u.ut_host));
194: #endif /* HAVE_HOST_IN_UTMP */
195: #ifdef HAVE_ADDR_IN_UTMP
196: if (addr)
197: memcpy(&u.ut_addr, &addr->sin_addr, sizeof(u.ut_addr));
198: else
199: memset(&u.ut_addr, 0, sizeof(u.ut_addr));
200: #endif
201:
202: /* Figure out the file names. */
203: utmp = _PATH_UTMP;
204: wtmp = _PATH_WTMP;
205:
206: #ifdef HAVE_LIBUTIL_LOGIN
207: login(&u);
208: #else /* HAVE_LIBUTIL_LOGIN */
209: /* Append an entry to wtmp. */
210: fd = open(wtmp, O_WRONLY|O_APPEND);
211: if (fd >= 0)
212: {
213: if (write(fd, &u, sizeof(u)) != sizeof(u))
214: log("Could not write %.100s: %.100s", wtmp, strerror(errno));
215: close(fd);
216: }
217:
218: /* Replace the proper entry in utmp, as identified by ut_line. Append a
219: new entry if the line could not be found. */
220: fd = open(utmp, O_RDWR);
221: if (fd >= 0)
222: {
223: while (1)
224: {
225: offset = lseek(fd, (off_t)0L, 1);
226: if (read(fd, &u2, sizeof(u2)) != sizeof(u2))
227: {
228: lseek(fd, offset, 0);
229: if (write(fd, &u, sizeof(u)) != sizeof(u))
230: log("Could not append to %.100s: %.100s",
231: utmp, strerror(errno));
232: break;
233: }
234: if (strncmp(u2.ut_line, ttyname + 5, sizeof(u2.ut_line)) == 0)
235: {
236: lseek(fd, offset, 0);
237: if (write(fd, &u, sizeof(u)) != sizeof(u))
238: log("Could not write to %.100s: %.100s",
239: utmp, strerror(errno));
240: break;
241: }
242: }
243: close(fd);
244: }
245: #endif /* HAVE_LIBUTIL_LOGIN */
246: #endif /* HAVE_UTMP_H && !HAVE_UTMPX_H */
247:
248: #ifdef HAVE_UTMPX_H
249: {
250: struct utmpx ux, *uxp;
251: memset(&ux, 0, sizeof(ux));
252: strncpy(ux.ut_line, ttyname + 5, sizeof(ux.ut_line));
253: uxp = getutxline(&ux);
254: if (uxp)
255: ux = *uxp;
256: strncpy(ux.ut_user, user, sizeof(ux.ut_user));
257: if (sizeof(ux.ut_id) > 4)
258: strncpy(ux.ut_id, ttyname + 5, sizeof(ux.ut_id));
259: else
260: strncpy(ux.ut_id, ttyname + strlen(ttyname) - 2, sizeof(ux.ut_id));
261: ux.ut_pid = pid;
262: if (strcmp(user, "") == 0)
263: ux.ut_type = DEAD_PROCESS;
264: else
265: ux.ut_type = USER_PROCESS;
266: gettimeofday(&ux.ut_tv, NULL);
267: #if HAVE_UT_SESSION
268: ux.ut_session = pid;
269: #endif
270: strncpy(ux.ut_host, host, sizeof(ux.ut_host));
271: ux.ut_host[sizeof(ux.ut_host) - 1] = 0;
272: #ifdef HAVE_UT_SYSLEN
273: ux.ut_syslen = strlen(ux.ut_host);
274: #endif
275: pututxline(&ux);
276: #ifdef WTMPX_FILE
277: updwtmpx(WTMPX_FILE, &ux);
278: #endif
279: endutxent();
280: }
281: #endif /* HAVE_UTMPX_H */
282:
283: #if defined(HAVE_LASTLOG_H) || defined(HAVE_LASTLOG)
284:
285: lastlog = _PATH_LASTLOG;
286:
287: /* Update lastlog unless actually recording a logout. */
288: if (strcmp(user, "") != 0)
289: {
290: /* It is safer to bzero the lastlog structure first because some
291: systems might have some extra fields in it (e.g. SGI) */
292: memset(&ll, 0, sizeof(ll));
293:
294: /* Update lastlog. */
295: ll.ll_time = time(NULL);
296: strncpy(ll.ll_line, ttyname + 5, sizeof(ll.ll_line));
297: strncpy(ll.ll_host, host, sizeof(ll.ll_host));
298: #ifdef LASTLOG_IS_DIR
1.3 deraadt 299: snprintf(lastlogfile, sizeof lastlogfile, "%.100s/%.100s",
300: lastlog, user);
1.1 deraadt 301: fd = open(lastlogfile, O_WRONLY | O_CREAT, 0644);
302: if (fd >= 0)
303: {
304: if (write(fd, &ll, sizeof(ll)) != sizeof(ll))
305: log("Could not write %.100s: %.100s",
306: lastlogfile, strerror(errno));
307: close(fd);
308: }
309: else
310: {
311: log("Could not open %.100s: %.100s", lastlogfile, strerror(errno));
312: }
313: #else /* LASTLOG_IS_DIR */
314: fd = open(lastlog, O_RDWR);
315: if (fd >= 0)
316: {
317: lseek(fd, (off_t)((long)uid * sizeof(ll)), 0);
318: if (write(fd, &ll, sizeof(ll)) != sizeof(ll))
319: log("Could not write %.100s: %.100s", lastlog, strerror(errno));
320: close(fd);
321: }
322: #endif /* LASTLOG_IS_DIR */
323: }
324: #endif /* HAVE_LASTLOG_H || HAVE_LASTLOG */
325:
326: #ifdef HAVE_USERSEC_H
327:
328: if (strcmp(user, "") != 0)
329: {
330: int lasttime = time(NULL);
331: if (setuserdb(S_WRITE) < 0)
332: log("setuserdb S_WRITE failed: %.100s", strerror(errno));
333: if (putuserattr((char *)user, S_LASTTIME, (void *)lasttime, SEC_INT) < 0)
334: log("putuserattr S_LASTTIME failed: %.100s", strerror(errno));
335: if (putuserattr((char *)user, S_LASTTTY, (void *)(ttyname + 5),
336: SEC_CHAR) < 0)
337: log("putuserattr S_LASTTTY %.900s failed: %.100s",
338: ttyname, strerror(errno));
339: if (putuserattr((char *)user, S_LASTHOST, (void *)host, SEC_CHAR) < 0)
340: log("putuserattr S_LASTHOST %.900s failed: %.100s",
341: host, strerror(errno));
342: if (putuserattr((char *)user, 0, NULL, SEC_COMMIT) < 0)
343: log("putuserattr SEC_COMMIT failed: %.100s", strerror(errno));
344: if (enduserdb() < 0)
345: log("enduserdb failed: %.100s", strerror(errno));
346: }
347: #endif
348: }
349:
350: /* Records that the user has logged out. */
351:
352: void record_logout(int pid, const char *ttyname)
353: {
354: #ifdef HAVE_LIBUTIL_LOGIN
355: const char *line = ttyname + 5; /* /dev/ttyq8 -> ttyq8 */
356: if (logout(line))
357: logwtmp(line, "", "");
358: #else /* HAVE_LIBUTIL_LOGIN */
359: record_login(pid, ttyname, "", -1, "", NULL);
360: #endif /* HAVE_LIBUTIL_LOGIN */
361: }