Line | Count | Source |
1 | | /* $OpenBSD: sshlogin.c,v 1.37 2026/02/16 23:47:06 jsg Exp $ */ |
2 | | /* |
3 | | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
5 | | * All rights reserved |
6 | | * This file performs some of the things login(1) normally does. We cannot |
7 | | * easily use something like login -p -h host -f user, because there are |
8 | | * several different logins around, and it is hard to determined what kind of |
9 | | * login the current system has. Also, we want to be able to execute commands |
10 | | * on a tty. |
11 | | * |
12 | | * As far as I am concerned, the code I have written for this software |
13 | | * can be used freely for any purpose. Any derived versions of this |
14 | | * software must be clearly marked as such, and if the derived work is |
15 | | * incompatible with the protocol description in the RFC file, it must be |
16 | | * called by a name other than "ssh" or "Secure Shell". |
17 | | * |
18 | | * Copyright (c) 1999 Theo de Raadt. All rights reserved. |
19 | | * Copyright (c) 1999 Markus Friedl. All rights reserved. |
20 | | * |
21 | | * Redistribution and use in source and binary forms, with or without |
22 | | * modification, are permitted provided that the following conditions |
23 | | * are met: |
24 | | * 1. Redistributions of source code must retain the above copyright |
25 | | * notice, this list of conditions and the following disclaimer. |
26 | | * 2. Redistributions in binary form must reproduce the above copyright |
27 | | * notice, this list of conditions and the following disclaimer in the |
28 | | * documentation and/or other materials provided with the distribution. |
29 | | * |
30 | | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
31 | | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
32 | | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
33 | | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
34 | | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
35 | | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
36 | | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
37 | | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
38 | | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
39 | | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
40 | | */ |
41 | | |
42 | | #include "includes.h" |
43 | | |
44 | | #include <sys/types.h> |
45 | | #include <sys/socket.h> |
46 | | |
47 | | #include <netinet/in.h> |
48 | | |
49 | | #include <errno.h> |
50 | | #include <fcntl.h> |
51 | | #include <stdio.h> |
52 | | #include <stdlib.h> |
53 | | #include <string.h> |
54 | | #include <time.h> |
55 | | #include <unistd.h> |
56 | | #include <limits.h> |
57 | | |
58 | | #include "sshlogin.h" |
59 | | #include "ssherr.h" |
60 | | #include "loginrec.h" |
61 | | #include "log.h" |
62 | | #include "sshbuf.h" |
63 | | #include "misc.h" |
64 | | #include "servconf.h" |
65 | | |
66 | | extern struct sshbuf *loginmsg; |
67 | | extern ServerOptions options; |
68 | | |
69 | | /* |
70 | | * Returns the time when the user last logged in. Returns 0 if the |
71 | | * information is not available. This must be called before record_login. |
72 | | * The host the user logged in from will be returned in buf. |
73 | | */ |
74 | | time_t |
75 | | get_last_login_time(uid_t uid, const char *logname, |
76 | | char *buf, size_t bufsize) |
77 | 0 | { |
78 | 0 | struct logininfo li; |
79 | |
|
80 | 0 | login_get_lastlog(&li, uid); |
81 | 0 | strlcpy(buf, li.hostname, bufsize); |
82 | 0 | return (time_t)li.tv_sec; |
83 | 0 | } |
84 | | |
85 | | /* |
86 | | * Generate and store last login message. This must be done before |
87 | | * login_login() is called and lastlog is updated. |
88 | | */ |
89 | | static void |
90 | | store_lastlog_message(const char *user, uid_t uid) |
91 | 0 | { |
92 | 0 | #ifndef NO_SSH_LASTLOG |
93 | 0 | # ifndef CUSTOM_SYS_AUTH_GET_LASTLOGIN_MSG |
94 | 0 | char hostname[HOST_NAME_MAX+1] = ""; |
95 | 0 | time_t last_login_time; |
96 | 0 | # endif |
97 | 0 | char *time_string; |
98 | 0 | int r; |
99 | |
|
100 | 0 | if (!options.print_lastlog) |
101 | 0 | return; |
102 | | |
103 | | # ifdef CUSTOM_SYS_AUTH_GET_LASTLOGIN_MSG |
104 | | time_string = sys_auth_get_lastlogin_msg(user, uid); |
105 | | if (time_string != NULL) { |
106 | | if ((r = sshbuf_put(loginmsg, |
107 | | time_string, strlen(time_string))) != 0) |
108 | | fatal_fr(r, "buffer error"); |
109 | | free(time_string); |
110 | | } |
111 | | # else |
112 | 0 | last_login_time = get_last_login_time(uid, user, hostname, |
113 | 0 | sizeof(hostname)); |
114 | |
|
115 | 0 | if (last_login_time != 0) { |
116 | 0 | time_string = ctime(&last_login_time); |
117 | 0 | time_string[strcspn(time_string, "\n")] = '\0'; |
118 | 0 | if (strcmp(hostname, "") == 0) |
119 | 0 | r = sshbuf_putf(loginmsg, "Last login: %s\r\n", |
120 | 0 | time_string); |
121 | 0 | else |
122 | 0 | r = sshbuf_putf(loginmsg, "Last login: %s from %s\r\n", |
123 | 0 | time_string, hostname); |
124 | 0 | if (r != 0) |
125 | 0 | fatal_fr(r, "sshbuf_putf"); |
126 | 0 | } |
127 | 0 | # endif /* CUSTOM_SYS_AUTH_GET_LASTLOGIN_MSG */ |
128 | 0 | #endif /* NO_SSH_LASTLOG */ |
129 | 0 | } |
130 | | |
131 | | /* |
132 | | * Records that the user has logged in. I wish these parts of operating |
133 | | * systems were more standardized. |
134 | | */ |
135 | | void |
136 | | record_login(pid_t pid, const char *tty, const char *user, uid_t uid, |
137 | | const char *host, struct sockaddr *addr, socklen_t addrlen) |
138 | 0 | { |
139 | 0 | struct logininfo *li; |
140 | | |
141 | | /* save previous login details before writing new */ |
142 | 0 | store_lastlog_message(user, uid); |
143 | |
|
144 | 0 | li = login_alloc_entry(pid, user, host, tty); |
145 | 0 | login_set_addr(li, addr, addrlen); |
146 | 0 | login_login(li); |
147 | 0 | login_free_entry(li); |
148 | 0 | } |
149 | | |
150 | | #ifdef LOGIN_NEEDS_UTMPX |
151 | | void |
152 | | record_utmp_only(pid_t pid, const char *ttyname, const char *user, |
153 | | const char *host, struct sockaddr *addr, socklen_t addrlen) |
154 | | { |
155 | | struct logininfo *li; |
156 | | |
157 | | li = login_alloc_entry(pid, user, host, ttyname); |
158 | | login_set_addr(li, addr, addrlen); |
159 | | login_utmp_only(li); |
160 | | login_free_entry(li); |
161 | | } |
162 | | #endif |
163 | | |
164 | | /* Records that the user has logged out. */ |
165 | | void |
166 | | record_logout(pid_t pid, const char *tty, const char *user) |
167 | 0 | { |
168 | 0 | struct logininfo *li; |
169 | |
|
170 | | li = login_alloc_entry(pid, user, NULL, tty); |
171 | 0 | login_logout(li); |
172 | 0 | login_free_entry(li); |
173 | 0 | } |