No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / external / bsd / openssh / dist / sshlogin.c
blobe3563c2fc1ea9011b7c42b63fe3e7e5ec435159a
1 /* $NetBSD$ */
2 /* $OpenBSD: sshlogin.c,v 1.26 2007/09/11 15:47:17 gilles Exp $ */
3 /*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
5 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
6 * All rights reserved
7 * This file performs some of the things login(1) normally does. We cannot
8 * easily use something like login -p -h host -f user, because there are
9 * several different logins around, and it is hard to determined what kind of
10 * login the current system has. Also, we want to be able to execute commands
11 * on a tty.
13 * As far as I am concerned, the code I have written for this software
14 * can be used freely for any purpose. Any derived versions of this
15 * software must be clearly marked as such, and if the derived work is
16 * incompatible with the protocol description in the RFC file, it must be
17 * called by a name other than "ssh" or "Secure Shell".
19 * Copyright (c) 1999 Theo de Raadt. All rights reserved.
20 * Copyright (c) 1999 Markus Friedl. All rights reserved.
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the above copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
31 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
32 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
33 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
34 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
35 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
40 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 #include "includes.h"
44 __RCSID("$NetBSD: sshlogin.c,v 1.18 2008/04/06 23:38:20 christos Exp $");
45 #include <sys/types.h>
46 #include <sys/param.h>
47 #include <sys/socket.h>
49 #include <errno.h>
50 #include <fcntl.h>
51 #include <stdio.h>
52 #include <string.h>
53 #include <time.h>
54 #include <unistd.h>
55 #include <util.h>
56 #ifdef SUPPORT_UTMP
57 #include <utmp.h>
58 #endif
59 #ifdef SUPPORT_UTMPX
60 #include <utmpx.h>
61 #endif
62 #include <stdarg.h>
64 #include "sshlogin.h"
65 #include "log.h"
66 #include "buffer.h"
67 #include "servconf.h"
69 extern Buffer loginmsg;
70 extern ServerOptions options;
73 * Returns the time when the user last logged in. Returns 0 if the
74 * information is not available. This must be called before record_login.
75 * The host the user logged in from will be returned in buf.
77 time_t
78 get_last_login_time(uid_t uid, const char *logname,
79 char *buf, size_t bufsize)
81 #ifdef SUPPORT_UTMPX
82 struct lastlogx llx, *llxp;
83 #endif
84 #ifdef SUPPORT_UTMP
85 struct lastlog ll;
86 int fd;
87 #endif
88 off_t pos, r;
90 buf[0] = '\0';
91 #ifdef SUPPORT_UTMPX
92 if ((llxp = getlastlogx(_PATH_LASTLOGX, uid, &llx)) != NULL) {
93 if (bufsize > sizeof(llxp->ll_host) + 1)
94 bufsize = sizeof(llxp->ll_host) + 1;
95 strncpy(buf, llxp->ll_host, bufsize - 1);
96 buf[bufsize - 1] = 0;
97 return llxp->ll_tv.tv_sec;
99 #endif
100 #ifdef SUPPORT_UTMP
101 fd = open(_PATH_LASTLOG, O_RDONLY);
102 if (fd < 0)
103 return 0;
105 pos = (long) uid * sizeof(ll);
106 r = lseek(fd, pos, SEEK_SET);
107 if (r == -1) {
108 error("%s: lseek: %s", __func__, strerror(errno));
109 return (0);
111 if (r != pos) {
112 debug("%s: truncated lastlog", __func__);
113 return (0);
115 if (read(fd, &ll, sizeof(ll)) != sizeof(ll)) {
116 close(fd);
117 return 0;
119 close(fd);
120 if (bufsize > sizeof(ll.ll_host) + 1)
121 bufsize = sizeof(ll.ll_host) + 1;
122 strncpy(buf, ll.ll_host, bufsize - 1);
123 buf[bufsize - 1] = '\0';
124 return (time_t)ll.ll_time;
125 #else
126 return 0;
127 #endif
131 * Generate and store last login message. This must be done before
132 * login_login() is called and lastlog is updated.
134 static void
135 store_lastlog_message(const char *user, uid_t uid)
137 char *time_string, hostname[MAXHOSTNAMELEN] = "", buf[512];
138 time_t last_login_time;
140 if (!options.print_lastlog)
141 return;
143 last_login_time = get_last_login_time(uid, user, hostname,
144 sizeof(hostname));
146 if (last_login_time != 0) {
147 time_string = ctime(&last_login_time);
148 time_string[strcspn(time_string, "\n")] = '\0';
149 if (strcmp(hostname, "") == 0)
150 snprintf(buf, sizeof(buf), "Last login: %s\r\n",
151 time_string);
152 else
153 snprintf(buf, sizeof(buf), "Last login: %s from %s\r\n",
154 time_string, hostname);
155 buffer_append(&loginmsg, buf, strlen(buf));
160 * Records that the user has logged in. I wish these parts of operating
161 * systems were more standardized.
163 void
164 record_login(pid_t pid, const char *tty, const char *user, uid_t uid,
165 const char *host, struct sockaddr *addr, socklen_t addrlen)
167 #if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
168 int fd;
169 #endif
170 struct timeval tv;
171 #ifdef SUPPORT_UTMP
172 struct utmp u;
173 struct lastlog ll;
174 #endif
175 #ifdef SUPPORT_UTMPX
176 struct utmpx ux, *uxp = &ux;
177 struct lastlogx llx;
178 #endif
179 (void)gettimeofday(&tv, NULL);
181 * XXX: why do we need to handle logout cases here?
182 * Isn't the function below taking care of this?
184 /* save previous login details before writing new */
185 store_lastlog_message(user, uid);
187 #ifdef SUPPORT_UTMP
188 /* Construct an utmp/wtmp entry. */
189 memset(&u, 0, sizeof(u));
190 strncpy(u.ut_line, tty + 5, sizeof(u.ut_line));
191 u.ut_time = (time_t)tv.tv_sec;
192 strncpy(u.ut_name, user, sizeof(u.ut_name));
193 strncpy(u.ut_host, host, sizeof(u.ut_host));
195 login(&u);
197 /* Update lastlog unless actually recording a logout. */
198 if (*user != '\0') {
200 * It is safer to bzero the lastlog structure first because
201 * some systems might have some extra fields in it (e.g. SGI)
203 memset(&ll, 0, sizeof(ll));
205 /* Update lastlog. */
206 ll.ll_time = time(NULL);
207 strncpy(ll.ll_line, tty + 5, sizeof(ll.ll_line));
208 strncpy(ll.ll_host, host, sizeof(ll.ll_host));
209 fd = open(_PATH_LASTLOG, O_RDWR);
210 if (fd >= 0) {
211 lseek(fd, (off_t) ((long) uid * sizeof(ll)), SEEK_SET);
212 if (write(fd, &ll, sizeof(ll)) != sizeof(ll))
213 logit("Could not write %.100s: %.100s", _PATH_LASTLOG, strerror(errno));
214 close(fd);
217 #endif
218 #ifdef SUPPORT_UTMPX
219 /* Construct an utmpx/wtmpx entry. */
220 memset(&ux, 0, sizeof(ux));
221 strncpy(ux.ut_line, tty + 5, sizeof(ux.ut_line));
222 if (*user) {
223 ux.ut_pid = pid;
224 ux.ut_type = USER_PROCESS;
225 ux.ut_tv = tv;
226 strncpy(ux.ut_name, user, sizeof(ux.ut_name));
227 strncpy(ux.ut_host, host, sizeof(ux.ut_host));
228 /* XXX: need ut_id, use last 4 char of tty */
229 if (strlen(tty) > sizeof(ux.ut_id)) {
230 strncpy(ux.ut_id,
231 tty + strlen(tty) - sizeof(ux.ut_id),
232 sizeof(ux.ut_id));
233 } else
234 strncpy(ux.ut_id, tty, sizeof(ux.ut_id));
235 /* XXX: It would be better if we had sockaddr_storage here */
236 if (addrlen > sizeof(ux.ut_ss))
237 addrlen = sizeof(ux.ut_ss);
238 (void)memcpy(&ux.ut_ss, addr, addrlen);
239 if (pututxline(&ux) == NULL)
240 logit("could not add utmpx line: %.100s",
241 strerror(errno));
242 /* Update lastlog. */
243 (void)gettimeofday(&llx.ll_tv, NULL);
244 strncpy(llx.ll_line, tty + 5, sizeof(llx.ll_line));
245 strncpy(llx.ll_host, host, sizeof(llx.ll_host));
246 (void)memcpy(&llx.ll_ss, addr, addrlen);
247 if (updlastlogx(_PATH_LASTLOGX, uid, &llx) == -1)
248 logit("Could not update %.100s: %.100s",
249 _PATH_LASTLOGX, strerror(errno));
250 } else {
251 if ((uxp = getutxline(&ux)) == NULL)
252 logit("could not find utmpx line for %.100s", tty);
253 else {
254 uxp->ut_type = DEAD_PROCESS;
255 uxp->ut_tv = tv;
256 /* XXX: we don't record exit info yet */
257 if (pututxline(&ux) == NULL)
258 logit("could not replace utmpx line: %.100s",
259 strerror(errno));
262 endutxent();
263 updwtmpx(_PATH_WTMPX, uxp);
264 #endif
267 /* Records that the user has logged out. */
268 void
269 record_logout(pid_t pid, const char *tty)
271 #if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
272 const char *line = tty + 5; /* /dev/ttyq8 -> ttyq8 */
273 #endif
274 #ifdef SUPPORT_UTMP
275 if (logout(line))
276 logwtmp(line, "", "");
277 #endif
278 #ifdef SUPPORT_UTMPX
279 /* XXX: no exit info yet */
280 if (logoutx(line, 0, DEAD_PROCESS))
281 logwtmpx(line, "", "", 0, DEAD_PROCESS);
282 #endif