1 /* $OpenBSD: sshlogin.c,v 1.26 2007/09/11 15:47:17 gilles Exp $ */
2 /*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright © 2013
5 * Thorsten “mirabilos” Glaser <tg@mirbsd.org>
6 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
7 * All rights reserved
8 * This file performs some of the things login(1) normally does. We cannot
9 * easily use something like login -p -h host -f user, because there are
10 * several different logins around, and it is hard to determined what kind of
11 * login the current system has. Also, we want to be able to execute commands
12 * on a tty.
13 *
14 * As far as I am concerned, the code I have written for this software
15 * can be used freely for any purpose. Any derived versions of this
16 * software must be clearly marked as such, and if the derived work is
17 * incompatible with the protocol description in the RFC file, it must be
18 * called by a name other than "ssh" or "Secure Shell".
19 *
20 * Copyright (c) 1999 Theo de Raadt. All rights reserved.
21 * Copyright (c) 1999 Markus Friedl. All rights reserved.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the above copyright
27 * notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 * notice, this list of conditions and the following disclaimer in the
30 * documentation and/or other materials provided with the distribution.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
33 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
34 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
35 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
36 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
37 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
38 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
39 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
41 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 */
43
44 #include <sys/param.h>
45 #include <sys/socket.h>
46
47 #include <errno.h>
48 #include <fcntl.h>
49 #include <stdio.h>
50 #include <string.h>
51 #include <time.h>
52 #include <unistd.h>
53 #include <util.h>
54 #include <utmp.h>
55 #include <stdarg.h>
56
57 #include "sshlogin.h"
58 #include "log.h"
59 #include "buffer.h"
60 #include "servconf.h"
61
62 __RCSID("$MirOS: src/usr.bin/ssh/sshlogin.c,v 1.7 2013/10/31 20:07:15 tg Exp $");
63
64 extern Buffer loginmsg;
65 extern ServerOptions options;
66
67 #ifdef SMALL
68 #define usmall __attribute__((__unused__))
69 #else
70 #define usmall /* nothing */
71 static time_t get_last_login_time(uid_t, const char *, char *, size_t);
72
73 /*
74 * Returns the time when the user last logged in. Returns 0 if the
75 * information is not available. This must be called before record_login.
76 * The host the user logged in from will be returned in buf.
77 */
78 static time_t
get_last_login_time(uid_t uid,const char * logname,char * buf,size_t bufsize)79 get_last_login_time(uid_t uid, const char *logname __attribute__((__unused__)),
80 char *buf, size_t bufsize)
81 {
82 struct lastlog ll;
83 const char *lastlog;
84 int fd;
85 off_t pos, r;
86
87 lastlog = _PATH_LASTLOG;
88 buf[0] = '\0';
89
90 fd = open(lastlog, O_RDONLY);
91 if (fd < 0)
92 return 0;
93
94 pos = (long) uid * sizeof(ll);
95 r = lseek(fd, pos, SEEK_SET);
96 if (r == -1) {
97 error("%s: lseek: %s", __func__, strerror(errno));
98 return (0);
99 }
100 if (r != pos) {
101 debug("%s: truncated lastlog", __func__);
102 return (0);
103 }
104 if (read(fd, &ll, sizeof(ll)) != sizeof(ll)) {
105 close(fd);
106 return 0;
107 }
108 close(fd);
109 if (bufsize > sizeof(ll.ll_host) + 1)
110 bufsize = sizeof(ll.ll_host) + 1;
111 strncpy(buf, ll.ll_host, bufsize - 1);
112 buf[bufsize - 1] = '\0';
113 return (time_t)ll.ll_time;
114 }
115
116 /*
117 * Generate and store last login message. This must be done before
118 * login_login() is called and lastlog is updated.
119 */
120 static void
store_lastlog_message(const char * user,uid_t uid)121 store_lastlog_message(const char *user, uid_t uid)
122 {
123 char *time_string, hostname[MAXHOSTNAMELEN] = "", buf[512];
124 time_t last_login_time;
125
126 if (!options.print_lastlog)
127 return;
128
129 last_login_time = get_last_login_time(uid, user, hostname,
130 sizeof(hostname));
131
132 if (last_login_time != 0) {
133 time_string = ctime(&last_login_time);
134 time_string[strcspn(time_string, "\n")] = '\0';
135 if (strcmp(hostname, "") == 0)
136 snprintf(buf, sizeof(buf), "Last login: %s\r\n",
137 time_string);
138 else
139 snprintf(buf, sizeof(buf), "Last login: %s from %s\r\n",
140 time_string, hostname);
141 buffer_append(&loginmsg, buf, strlen(buf));
142 }
143 }
144 #endif
145
146 /*
147 * Records that the user has logged in. I wish these parts of operating
148 * systems were more standardized.
149 */
150 void
record_login(pid_t pid,const char * tty usmall,const char * user usmall,uid_t uid usmall,const char * host usmall,struct sockaddr * addr,socklen_t addrlen)151 record_login(pid_t pid __attribute__((__unused__)), const char *tty usmall,
152 const char *user usmall, uid_t uid usmall, const char *host usmall,
153 struct sockaddr *addr __attribute__((__unused__)),
154 socklen_t addrlen __attribute__((__unused__)))
155 {
156 #ifndef SMALL
157 int fd;
158 struct lastlog ll;
159 const char *lastlog;
160 struct utmp u;
161
162 /* save previous login details before writing new */
163 store_lastlog_message(user, uid);
164
165 /* Construct an utmp/wtmp entry. */
166 memset(&u, 0, sizeof(u));
167 strncpy(u.ut_line, tty + 5, sizeof(u.ut_line));
168 u.ut_time = time(NULL);
169 strncpy(u.ut_name, user, sizeof(u.ut_name));
170 strncpy(u.ut_host, host, sizeof(u.ut_host));
171
172 login(&u);
173 lastlog = _PATH_LASTLOG;
174
175 /* Update lastlog unless actually recording a logout. */
176 if (strcmp(user, "") != 0) {
177 /*
178 * It is safer to bzero the lastlog structure first because
179 * some systems might have some extra fields in it (e.g. SGI)
180 */
181 memset(&ll, 0, sizeof(ll));
182
183 /* Update lastlog. */
184 ll.ll_time = time(NULL);
185 strncpy(ll.ll_line, tty + 5, sizeof(ll.ll_line));
186 strncpy(ll.ll_host, host, sizeof(ll.ll_host));
187 fd = open(lastlog, O_RDWR);
188 if (fd >= 0) {
189 lseek(fd, (off_t) ((long) uid * sizeof(ll)), SEEK_SET);
190 if (write(fd, &ll, sizeof(ll)) != sizeof(ll))
191 logit("Could not write %.100s: %.100s", lastlog, strerror(errno));
192 close(fd);
193 }
194 }
195 #endif
196 }
197
198 /* Records that the user has logged out. */
199 void
record_logout(pid_t pid,const char * tty usmall)200 record_logout(pid_t pid __attribute__((__unused__)), const char *tty usmall)
201 {
202 #ifndef SMALL
203 const char *line = tty + 5; /* /dev/ttyq8 -> ttyq8 */
204 if (logout(line))
205 logwtmp(line, "", "");
206 #endif
207 }
208