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