diff options
Diffstat (limited to 'loginrec.c')
-rw-r--r-- | loginrec.c | 825 |
1 files changed, 462 insertions, 363 deletions
diff --git a/loginrec.c b/loginrec.c index f07f65fce..361ac4cb7 100644 --- a/loginrec.c +++ b/loginrec.c | |||
@@ -25,130 +25,125 @@ | |||
25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | /* | ||
29 | * The btmp logging code is derived from login.c from util-linux and is under | ||
30 | * the the following license: | ||
31 | * | ||
32 | * Copyright (c) 1980, 1987, 1988 The Regents of the University of California. | ||
33 | * All rights reserved. | ||
34 | * | ||
35 | * Redistribution and use in source and binary forms are permitted | ||
36 | * provided that the above copyright notice and this paragraph are | ||
37 | * duplicated in all such forms and that any documentation, | ||
38 | * advertising materials, and other materials related to such | ||
39 | * distribution and use acknowledge that the software was developed | ||
40 | * by the University of California, Berkeley. The name of the | ||
41 | * University may not be used to endorse or promote products derived | ||
42 | * from this software without specific prior written permission. | ||
43 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
44 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
45 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
46 | */ | ||
47 | |||
48 | |||
28 | /** | 49 | /** |
29 | ** loginrec.c: platform-independent login recording and lastlog retrieval | 50 | ** loginrec.c: platform-independent login recording and lastlog retrieval |
30 | **/ | 51 | **/ |
31 | 52 | ||
32 | /* | 53 | /* |
33 | The new login code explained | 54 | * The new login code explained |
34 | ============================ | 55 | * ============================ |
35 | 56 | * | |
36 | This code attempts to provide a common interface to login recording | 57 | * This code attempts to provide a common interface to login recording |
37 | (utmp and friends) and last login time retrieval. | 58 | * (utmp and friends) and last login time retrieval. |
38 | 59 | * | |
39 | Its primary means of achieving this is to use 'struct logininfo', a | 60 | * Its primary means of achieving this is to use 'struct logininfo', a |
40 | union of all the useful fields in the various different types of | 61 | * union of all the useful fields in the various different types of |
41 | system login record structures one finds on UNIX variants. | 62 | * system login record structures one finds on UNIX variants. |
42 | 63 | * | |
43 | We depend on autoconf to define which recording methods are to be | 64 | * We depend on autoconf to define which recording methods are to be |
44 | used, and which fields are contained in the relevant data structures | 65 | * used, and which fields are contained in the relevant data structures |
45 | on the local system. Many C preprocessor symbols affect which code | 66 | * on the local system. Many C preprocessor symbols affect which code |
46 | gets compiled here. | 67 | * gets compiled here. |
47 | 68 | * | |
48 | The code is designed to make it easy to modify a particular | 69 | * The code is designed to make it easy to modify a particular |
49 | recording method, without affecting other methods nor requiring so | 70 | * recording method, without affecting other methods nor requiring so |
50 | many nested conditional compilation blocks as were commonplace in | 71 | * many nested conditional compilation blocks as were commonplace in |
51 | the old code. | 72 | * the old code. |
52 | 73 | * | |
53 | For login recording, we try to use the local system's libraries as | 74 | * For login recording, we try to use the local system's libraries as |
54 | these are clearly most likely to work correctly. For utmp systems | 75 | * these are clearly most likely to work correctly. For utmp systems |
55 | this usually means login() and logout() or setutent() etc., probably | 76 | * this usually means login() and logout() or setutent() etc., probably |
56 | in libutil, along with logwtmp() etc. On these systems, we fall back | 77 | * in libutil, along with logwtmp() etc. On these systems, we fall back |
57 | to writing the files directly if we have to, though this method | 78 | * to writing the files directly if we have to, though this method |
58 | requires very thorough testing so we do not corrupt local auditing | 79 | * requires very thorough testing so we do not corrupt local auditing |
59 | information. These files and their access methods are very system | 80 | * information. These files and their access methods are very system |
60 | specific indeed. | 81 | * specific indeed. |
61 | 82 | * | |
62 | For utmpx systems, the corresponding library functions are | 83 | * For utmpx systems, the corresponding library functions are |
63 | setutxent() etc. To the author's knowledge, all utmpx systems have | 84 | * setutxent() etc. To the author's knowledge, all utmpx systems have |
64 | these library functions and so no direct write is attempted. If such | 85 | * these library functions and so no direct write is attempted. If such |
65 | a system exists and needs support, direct analogues of the [uw]tmp | 86 | * a system exists and needs support, direct analogues of the [uw]tmp |
66 | code should suffice. | 87 | * code should suffice. |
67 | 88 | * | |
68 | Retrieving the time of last login ('lastlog') is in some ways even | 89 | * Retrieving the time of last login ('lastlog') is in some ways even |
69 | more problemmatic than login recording. Some systems provide a | 90 | * more problemmatic than login recording. Some systems provide a |
70 | simple table of all users which we seek based on uid and retrieve a | 91 | * simple table of all users which we seek based on uid and retrieve a |
71 | relatively standard structure. Others record the same information in | 92 | * relatively standard structure. Others record the same information in |
72 | a directory with a separate file, and others don't record the | 93 | * a directory with a separate file, and others don't record the |
73 | information separately at all. For systems in the latter category, | 94 | * information separately at all. For systems in the latter category, |
74 | we look backwards in the wtmp or wtmpx file for the last login entry | 95 | * we look backwards in the wtmp or wtmpx file for the last login entry |
75 | for our user. Naturally this is slower and on busy systems could | 96 | * for our user. Naturally this is slower and on busy systems could |
76 | incur a significant performance penalty. | 97 | * incur a significant performance penalty. |
77 | 98 | * | |
78 | Calling the new code | 99 | * Calling the new code |
79 | -------------------- | 100 | * -------------------- |
80 | 101 | * | |
81 | In OpenSSH all login recording and retrieval is performed in | 102 | * In OpenSSH all login recording and retrieval is performed in |
82 | login.c. Here you'll find working examples. Also, in the logintest.c | 103 | * login.c. Here you'll find working examples. Also, in the logintest.c |
83 | program there are more examples. | 104 | * program there are more examples. |
84 | 105 | * | |
85 | Internal handler calling method | 106 | * Internal handler calling method |
86 | ------------------------------- | 107 | * ------------------------------- |
87 | 108 | * | |
88 | When a call is made to login_login() or login_logout(), both | 109 | * When a call is made to login_login() or login_logout(), both |
89 | routines set a struct logininfo flag defining which action (log in, | 110 | * routines set a struct logininfo flag defining which action (log in, |
90 | or log out) is to be taken. They both then call login_write(), which | 111 | * or log out) is to be taken. They both then call login_write(), which |
91 | calls whichever of the many structure-specific handlers autoconf | 112 | * calls whichever of the many structure-specific handlers autoconf |
92 | selects for the local system. | 113 | * selects for the local system. |
93 | 114 | * | |
94 | The handlers themselves handle system data structure specifics. Both | 115 | * The handlers themselves handle system data structure specifics. Both |
95 | struct utmp and struct utmpx have utility functions (see | 116 | * struct utmp and struct utmpx have utility functions (see |
96 | construct_utmp*()) to try to make it simpler to add extra systems | 117 | * construct_utmp*()) to try to make it simpler to add extra systems |
97 | that introduce new features to either structure. | 118 | * that introduce new features to either structure. |
98 | 119 | * | |
99 | While it may seem terribly wasteful to replicate so much similar | 120 | * While it may seem terribly wasteful to replicate so much similar |
100 | code for each method, experience has shown that maintaining code to | 121 | * code for each method, experience has shown that maintaining code to |
101 | write both struct utmp and utmpx in one function, whilst maintaining | 122 | * write both struct utmp and utmpx in one function, whilst maintaining |
102 | support for all systems whether they have library support or not, is | 123 | * support for all systems whether they have library support or not, is |
103 | a difficult and time-consuming task. | 124 | * a difficult and time-consuming task. |
104 | 125 | * | |
105 | Lastlog support proceeds similarly. Functions login_get_lastlog() | 126 | * Lastlog support proceeds similarly. Functions login_get_lastlog() |
106 | (and its OpenSSH-tuned friend login_get_lastlog_time()) call | 127 | * (and its OpenSSH-tuned friend login_get_lastlog_time()) call |
107 | getlast_entry(), which tries one of three methods to find the last | 128 | * getlast_entry(), which tries one of three methods to find the last |
108 | login time. It uses local system lastlog support if it can, | 129 | * login time. It uses local system lastlog support if it can, |
109 | otherwise it tries wtmp or wtmpx before giving up and returning 0, | 130 | * otherwise it tries wtmp or wtmpx before giving up and returning 0, |
110 | meaning "tilt". | 131 | * meaning "tilt". |
111 | 132 | * | |
112 | Maintenance | 133 | * Maintenance |
113 | ----------- | 134 | * ----------- |
114 | 135 | * | |
115 | In many cases it's possible to tweak autoconf to select the correct | 136 | * In many cases it's possible to tweak autoconf to select the correct |
116 | methods for a particular platform, either by improving the detection | 137 | * methods for a particular platform, either by improving the detection |
117 | code (best), or by presetting DISABLE_<method> or CONF_<method>_FILE | 138 | * code (best), or by presetting DISABLE_<method> or CONF_<method>_FILE |
118 | symbols for the platform. | 139 | * symbols for the platform. |
119 | 140 | * | |
120 | Use logintest to check which symbols are defined before modifying | 141 | * Use logintest to check which symbols are defined before modifying |
121 | configure.ac and loginrec.c. (You have to build logintest yourself | 142 | * configure.ac and loginrec.c. (You have to build logintest yourself |
122 | with 'make logintest' as it's not built by default.) | 143 | * with 'make logintest' as it's not built by default.) |
123 | 144 | * | |
124 | Otherwise, patches to the specific method(s) are very helpful! | 145 | * Otherwise, patches to the specific method(s) are very helpful! |
125 | 146 | */ | |
126 | */ | ||
127 | |||
128 | /** | ||
129 | ** TODO: | ||
130 | ** homegrown ttyslot() | ||
131 | ** test, test, test | ||
132 | ** | ||
133 | ** Platform status: | ||
134 | ** ---------------- | ||
135 | ** | ||
136 | ** Known good: | ||
137 | ** Linux (Redhat 6.2, Debian) | ||
138 | ** Solaris | ||
139 | ** HP-UX 10.20 (gcc only) | ||
140 | ** IRIX | ||
141 | ** NeXT - M68k/HPPA/Sparc (4.2/3.3) | ||
142 | ** | ||
143 | ** Testing required: Please send reports! | ||
144 | ** NetBSD | ||
145 | ** HP-UX 11 | ||
146 | ** AIX | ||
147 | ** | ||
148 | ** Platforms with known problems: | ||
149 | ** Some variants of Slackware Linux | ||
150 | ** | ||
151 | **/ | ||
152 | 147 | ||
153 | #include "includes.h" | 148 | #include "includes.h" |
154 | 149 | ||
@@ -157,17 +152,21 @@ | |||
157 | #include "loginrec.h" | 152 | #include "loginrec.h" |
158 | #include "log.h" | 153 | #include "log.h" |
159 | #include "atomicio.h" | 154 | #include "atomicio.h" |
160 | 155 | #include "packet.h" | |
161 | RCSID("$Id: loginrec.c,v 1.58 2004/08/15 09:12:52 djm Exp $"); | 156 | #include "canohost.h" |
157 | #include "auth.h" | ||
158 | #include "buffer.h" | ||
162 | 159 | ||
163 | #ifdef HAVE_UTIL_H | 160 | #ifdef HAVE_UTIL_H |
164 | # include <util.h> | 161 | # include <util.h> |
165 | #endif | 162 | #endif |
166 | 163 | ||
167 | #ifdef HAVE_LIBUTIL_H | 164 | #ifdef HAVE_LIBUTIL_H |
168 | # include <libutil.h> | 165 | # include <libutil.h> |
169 | #endif | 166 | #endif |
170 | 167 | ||
168 | RCSID("$Id: loginrec.c,v 1.67 2005/02/15 11:19:28 dtucker Exp $"); | ||
169 | |||
171 | /** | 170 | /** |
172 | ** prototypes for helper functions in this file | 171 | ** prototypes for helper functions in this file |
173 | **/ | 172 | **/ |
@@ -194,14 +193,17 @@ int lastlog_get_entry(struct logininfo *li); | |||
194 | int wtmp_get_entry(struct logininfo *li); | 193 | int wtmp_get_entry(struct logininfo *li); |
195 | int wtmpx_get_entry(struct logininfo *li); | 194 | int wtmpx_get_entry(struct logininfo *li); |
196 | 195 | ||
196 | extern Buffer loginmsg; | ||
197 | |||
197 | /* pick the shortest string */ | 198 | /* pick the shortest string */ |
198 | #define MIN_SIZEOF(s1,s2) ( sizeof(s1) < sizeof(s2) ? sizeof(s1) : sizeof(s2) ) | 199 | #define MIN_SIZEOF(s1,s2) (sizeof(s1) < sizeof(s2) ? sizeof(s1) : sizeof(s2)) |
199 | 200 | ||
200 | /** | 201 | /** |
201 | ** platform-independent login functions | 202 | ** platform-independent login functions |
202 | **/ | 203 | **/ |
203 | 204 | ||
204 | /* login_login(struct logininfo *) -Record a login | 205 | /* |
206 | * login_login(struct logininfo *) - Record a login | ||
205 | * | 207 | * |
206 | * Call with a pointer to a struct logininfo initialised with | 208 | * Call with a pointer to a struct logininfo initialised with |
207 | * login_init_entry() or login_alloc_entry() | 209 | * login_init_entry() or login_alloc_entry() |
@@ -211,14 +213,15 @@ int wtmpx_get_entry(struct logininfo *li); | |||
211 | * 0 on failure (will use OpenSSH's logging facilities for diagnostics) | 213 | * 0 on failure (will use OpenSSH's logging facilities for diagnostics) |
212 | */ | 214 | */ |
213 | int | 215 | int |
214 | login_login (struct logininfo *li) | 216 | login_login(struct logininfo *li) |
215 | { | 217 | { |
216 | li->type = LTYPE_LOGIN; | 218 | li->type = LTYPE_LOGIN; |
217 | return login_write(li); | 219 | return (login_write(li)); |
218 | } | 220 | } |
219 | 221 | ||
220 | 222 | ||
221 | /* login_logout(struct logininfo *) - Record a logout | 223 | /* |
224 | * login_logout(struct logininfo *) - Record a logout | ||
222 | * | 225 | * |
223 | * Call as with login_login() | 226 | * Call as with login_login() |
224 | * | 227 | * |
@@ -230,10 +233,11 @@ int | |||
230 | login_logout(struct logininfo *li) | 233 | login_logout(struct logininfo *li) |
231 | { | 234 | { |
232 | li->type = LTYPE_LOGOUT; | 235 | li->type = LTYPE_LOGOUT; |
233 | return login_write(li); | 236 | return (login_write(li)); |
234 | } | 237 | } |
235 | 238 | ||
236 | /* login_get_lastlog_time(int) - Retrieve the last login time | 239 | /* |
240 | * login_get_lastlog_time(int) - Retrieve the last login time | ||
237 | * | 241 | * |
238 | * Retrieve the last login time for the given uid. Will try to use the | 242 | * Retrieve the last login time for the given uid. Will try to use the |
239 | * system lastlog facilities if they are available, but will fall back | 243 | * system lastlog facilities if they are available, but will fall back |
@@ -256,12 +260,13 @@ login_get_lastlog_time(const int uid) | |||
256 | struct logininfo li; | 260 | struct logininfo li; |
257 | 261 | ||
258 | if (login_get_lastlog(&li, uid)) | 262 | if (login_get_lastlog(&li, uid)) |
259 | return li.tv_sec; | 263 | return (li.tv_sec); |
260 | else | 264 | else |
261 | return 0; | 265 | return (0); |
262 | } | 266 | } |
263 | 267 | ||
264 | /* login_get_lastlog(struct logininfo *, int) - Retrieve a lastlog entry | 268 | /* |
269 | * login_get_lastlog(struct logininfo *, int) - Retrieve a lastlog entry | ||
265 | * | 270 | * |
266 | * Retrieve a logininfo structure populated (only partially) with | 271 | * Retrieve a logininfo structure populated (only partially) with |
267 | * information from the system lastlog data, or from wtmp/wtmpx if no | 272 | * information from the system lastlog data, or from wtmp/wtmpx if no |
@@ -272,7 +277,6 @@ login_get_lastlog_time(const int uid) | |||
272 | * Returns: | 277 | * Returns: |
273 | * >0: A pointer to your struct logininfo if successful | 278 | * >0: A pointer to your struct logininfo if successful |
274 | * 0 on failure (will use OpenSSH's logging facilities for diagnostics) | 279 | * 0 on failure (will use OpenSSH's logging facilities for diagnostics) |
275 | * | ||
276 | */ | 280 | */ |
277 | struct logininfo * | 281 | struct logininfo * |
278 | login_get_lastlog(struct logininfo *li, const int uid) | 282 | login_get_lastlog(struct logininfo *li, const int uid) |
@@ -289,20 +293,21 @@ login_get_lastlog(struct logininfo *li, const int uid) | |||
289 | */ | 293 | */ |
290 | pw = getpwuid(uid); | 294 | pw = getpwuid(uid); |
291 | if (pw == NULL) | 295 | if (pw == NULL) |
292 | fatal("login_get_lastlog: Cannot find account for uid %i", uid); | 296 | fatal("%s: Cannot find account for uid %i", __func__, uid); |
293 | 297 | ||
294 | /* No MIN_SIZEOF here - we absolutely *must not* truncate the | 298 | /* No MIN_SIZEOF here - we absolutely *must not* truncate the |
295 | * username */ | 299 | * username (XXX - so check for trunc!) */ |
296 | strlcpy(li->username, pw->pw_name, sizeof(li->username)); | 300 | strlcpy(li->username, pw->pw_name, sizeof(li->username)); |
297 | 301 | ||
298 | if (getlast_entry(li)) | 302 | if (getlast_entry(li)) |
299 | return li; | 303 | return (li); |
300 | else | 304 | else |
301 | return NULL; | 305 | return (NULL); |
302 | } | 306 | } |
303 | 307 | ||
304 | 308 | ||
305 | /* login_alloc_entry(int, char*, char*, char*) - Allocate and initialise | 309 | /* |
310 | * login_alloc_entry(int, char*, char*, char*) - Allocate and initialise | ||
306 | * a logininfo structure | 311 | * a logininfo structure |
307 | * | 312 | * |
308 | * This function creates a new struct logininfo, a data structure | 313 | * This function creates a new struct logininfo, a data structure |
@@ -313,13 +318,13 @@ login_get_lastlog(struct logininfo *li, const int uid) | |||
313 | */ | 318 | */ |
314 | struct | 319 | struct |
315 | logininfo *login_alloc_entry(int pid, const char *username, | 320 | logininfo *login_alloc_entry(int pid, const char *username, |
316 | const char *hostname, const char *line) | 321 | const char *hostname, const char *line) |
317 | { | 322 | { |
318 | struct logininfo *newli; | 323 | struct logininfo *newli; |
319 | 324 | ||
320 | newli = (struct logininfo *) xmalloc (sizeof(*newli)); | 325 | newli = xmalloc(sizeof(*newli)); |
321 | (void)login_init_entry(newli, pid, username, hostname, line); | 326 | login_init_entry(newli, pid, username, hostname, line); |
322 | return newli; | 327 | return (newli); |
323 | } | 328 | } |
324 | 329 | ||
325 | 330 | ||
@@ -341,7 +346,7 @@ login_free_entry(struct logininfo *li) | |||
341 | */ | 346 | */ |
342 | int | 347 | int |
343 | login_init_entry(struct logininfo *li, int pid, const char *username, | 348 | login_init_entry(struct logininfo *li, int pid, const char *username, |
344 | const char *hostname, const char *line) | 349 | const char *hostname, const char *line) |
345 | { | 350 | { |
346 | struct passwd *pw; | 351 | struct passwd *pw; |
347 | 352 | ||
@@ -356,18 +361,21 @@ login_init_entry(struct logininfo *li, int pid, const char *username, | |||
356 | if (username) { | 361 | if (username) { |
357 | strlcpy(li->username, username, sizeof(li->username)); | 362 | strlcpy(li->username, username, sizeof(li->username)); |
358 | pw = getpwnam(li->username); | 363 | pw = getpwnam(li->username); |
359 | if (pw == NULL) | 364 | if (pw == NULL) { |
360 | fatal("login_init_entry: Cannot find user \"%s\"", li->username); | 365 | fatal("%s: Cannot find user \"%s\"", __func__, |
366 | li->username); | ||
367 | } | ||
361 | li->uid = pw->pw_uid; | 368 | li->uid = pw->pw_uid; |
362 | } | 369 | } |
363 | 370 | ||
364 | if (hostname) | 371 | if (hostname) |
365 | strlcpy(li->hostname, hostname, sizeof(li->hostname)); | 372 | strlcpy(li->hostname, hostname, sizeof(li->hostname)); |
366 | 373 | ||
367 | return 1; | 374 | return (1); |
368 | } | 375 | } |
369 | 376 | ||
370 | /* login_set_current_time(struct logininfo *) - set the current time | 377 | /* |
378 | * login_set_current_time(struct logininfo *) - set the current time | ||
371 | * | 379 | * |
372 | * Set the current time in a logininfo structure. This function is | 380 | * Set the current time in a logininfo structure. This function is |
373 | * meant to eliminate the need to deal with system dependencies for | 381 | * meant to eliminate the need to deal with system dependencies for |
@@ -387,7 +395,7 @@ login_set_current_time(struct logininfo *li) | |||
387 | /* copy a sockaddr_* into our logininfo */ | 395 | /* copy a sockaddr_* into our logininfo */ |
388 | void | 396 | void |
389 | login_set_addr(struct logininfo *li, const struct sockaddr *sa, | 397 | login_set_addr(struct logininfo *li, const struct sockaddr *sa, |
390 | const unsigned int sa_size) | 398 | const unsigned int sa_size) |
391 | { | 399 | { |
392 | unsigned int bufsize = sa_size; | 400 | unsigned int bufsize = sa_size; |
393 | 401 | ||
@@ -395,7 +403,7 @@ login_set_addr(struct logininfo *li, const struct sockaddr *sa, | |||
395 | if (sizeof(li->hostaddr) < sa_size) | 403 | if (sizeof(li->hostaddr) < sa_size) |
396 | bufsize = sizeof(li->hostaddr); | 404 | bufsize = sizeof(li->hostaddr); |
397 | 405 | ||
398 | memcpy((void *)&(li->hostaddr.sa), (const void *)sa, bufsize); | 406 | memcpy(&li->hostaddr.sa, sa, bufsize); |
399 | } | 407 | } |
400 | 408 | ||
401 | 409 | ||
@@ -404,12 +412,12 @@ login_set_addr(struct logininfo *li, const struct sockaddr *sa, | |||
404 | ** results | 412 | ** results |
405 | **/ | 413 | **/ |
406 | int | 414 | int |
407 | login_write (struct logininfo *li) | 415 | login_write(struct logininfo *li) |
408 | { | 416 | { |
409 | #ifndef HAVE_CYGWIN | 417 | #ifndef HAVE_CYGWIN |
410 | if ((int)geteuid() != 0) { | 418 | if (geteuid() != 0) { |
411 | logit("Attempt to write login records by non-root user (aborting)"); | 419 | logit("Attempt to write login records by non-root user (aborting)"); |
412 | return 1; | 420 | return (1); |
413 | } | 421 | } |
414 | #endif | 422 | #endif |
415 | 423 | ||
@@ -419,9 +427,8 @@ login_write (struct logininfo *li) | |||
419 | syslogin_write_entry(li); | 427 | syslogin_write_entry(li); |
420 | #endif | 428 | #endif |
421 | #ifdef USE_LASTLOG | 429 | #ifdef USE_LASTLOG |
422 | if (li->type == LTYPE_LOGIN) { | 430 | if (li->type == LTYPE_LOGIN) |
423 | lastlog_write_entry(li); | 431 | lastlog_write_entry(li); |
424 | } | ||
425 | #endif | 432 | #endif |
426 | #ifdef USE_UTMP | 433 | #ifdef USE_UTMP |
427 | utmp_write_entry(li); | 434 | utmp_write_entry(li); |
@@ -437,10 +444,16 @@ login_write (struct logininfo *li) | |||
437 | #endif | 444 | #endif |
438 | #ifdef CUSTOM_SYS_AUTH_RECORD_LOGIN | 445 | #ifdef CUSTOM_SYS_AUTH_RECORD_LOGIN |
439 | if (li->type == LTYPE_LOGIN && | 446 | if (li->type == LTYPE_LOGIN && |
440 | !sys_auth_record_login(li->username,li->hostname,li->line)) | 447 | !sys_auth_record_login(li->username,li->hostname,li->line, &loginmsg)) |
441 | logit("Writing login record failed for %s", li->username); | 448 | logit("Writing login record failed for %s", li->username); |
442 | #endif | 449 | #endif |
443 | return 0; | 450 | #ifdef SSH_AUDIT_EVENTS |
451 | if (li->type == LTYPE_LOGIN) | ||
452 | audit_session_open(li->line); | ||
453 | else if (li->type == LTYPE_LOGOUT) | ||
454 | audit_session_close(li->line); | ||
455 | #endif | ||
456 | return (0); | ||
444 | } | 457 | } |
445 | 458 | ||
446 | #ifdef LOGIN_NEEDS_UTMPX | 459 | #ifdef LOGIN_NEEDS_UTMPX |
@@ -461,7 +474,7 @@ login_utmp_only(struct logininfo *li) | |||
461 | # ifdef USE_WTMPX | 474 | # ifdef USE_WTMPX |
462 | wtmpx_write_entry(li); | 475 | wtmpx_write_entry(li); |
463 | # endif | 476 | # endif |
464 | return 0; | 477 | return (0); |
465 | } | 478 | } |
466 | #endif | 479 | #endif |
467 | 480 | ||
@@ -478,25 +491,21 @@ getlast_entry(struct logininfo *li) | |||
478 | return(lastlog_get_entry(li)); | 491 | return(lastlog_get_entry(li)); |
479 | #else /* !USE_LASTLOG */ | 492 | #else /* !USE_LASTLOG */ |
480 | 493 | ||
481 | #ifdef DISABLE_LASTLOG | 494 | #if defined(DISABLE_LASTLOG) |
482 | /* On some systems we shouldn't even try to obtain last login | 495 | /* On some systems we shouldn't even try to obtain last login |
483 | * time, e.g. AIX */ | 496 | * time, e.g. AIX */ |
484 | return 0; | 497 | return (0); |
485 | # else /* DISABLE_LASTLOG */ | 498 | # elif defined(USE_WTMP) && \ |
486 | /* Try to retrieve the last login time from wtmp */ | 499 | (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP)) |
487 | # if defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP)) | ||
488 | /* retrieve last login time from utmp */ | 500 | /* retrieve last login time from utmp */ |
489 | return (wtmp_get_entry(li)); | 501 | return (wtmp_get_entry(li)); |
490 | # else /* defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP)) */ | 502 | # elif defined(USE_WTMPX) && \ |
503 | (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX)) | ||
491 | /* If wtmp isn't available, try wtmpx */ | 504 | /* If wtmp isn't available, try wtmpx */ |
492 | # if defined(USE_WTMPX) && (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX)) | ||
493 | /* retrieve last login time from utmpx */ | ||
494 | return (wtmpx_get_entry(li)); | 505 | return (wtmpx_get_entry(li)); |
495 | # else | 506 | # else |
496 | /* Give up: No means of retrieving last login time */ | 507 | /* Give up: No means of retrieving last login time */ |
497 | return 0; | 508 | return (0); |
498 | # endif /* USE_WTMPX && (HAVE_TIME_IN_UTMPX || HAVE_TV_IN_UTMPX) */ | ||
499 | # endif /* USE_WTMP && (HAVE_TIME_IN_UTMP || HAVE_TV_IN_UTMP) */ | ||
500 | # endif /* DISABLE_LASTLOG */ | 509 | # endif /* DISABLE_LASTLOG */ |
501 | #endif /* USE_LASTLOG */ | 510 | #endif /* USE_LASTLOG */ |
502 | } | 511 | } |
@@ -520,19 +529,21 @@ getlast_entry(struct logininfo *li) | |||
520 | */ | 529 | */ |
521 | 530 | ||
522 | 531 | ||
523 | /* line_fullname(): add the leading '/dev/' if it doesn't exist make | 532 | /* |
524 | * sure dst has enough space, if not just copy src (ugh) */ | 533 | * line_fullname(): add the leading '/dev/' if it doesn't exist make |
534 | * sure dst has enough space, if not just copy src (ugh) | ||
535 | */ | ||
525 | char * | 536 | char * |
526 | line_fullname(char *dst, const char *src, int dstsize) | 537 | line_fullname(char *dst, const char *src, int dstsize) |
527 | { | 538 | { |
528 | memset(dst, '\0', dstsize); | 539 | memset(dst, '\0', dstsize); |
529 | if ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5))) { | 540 | if ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5))) |
530 | strlcpy(dst, src, dstsize); | 541 | strlcpy(dst, src, dstsize); |
531 | } else { | 542 | else { |
532 | strlcpy(dst, "/dev/", dstsize); | 543 | strlcpy(dst, "/dev/", dstsize); |
533 | strlcat(dst, src, dstsize); | 544 | strlcat(dst, src, dstsize); |
534 | } | 545 | } |
535 | return dst; | 546 | return (dst); |
536 | } | 547 | } |
537 | 548 | ||
538 | /* line_stripname(): strip the leading '/dev' if it exists, return dst */ | 549 | /* line_stripname(): strip the leading '/dev' if it exists, return dst */ |
@@ -544,15 +555,17 @@ line_stripname(char *dst, const char *src, int dstsize) | |||
544 | strlcpy(dst, src + 5, dstsize); | 555 | strlcpy(dst, src + 5, dstsize); |
545 | else | 556 | else |
546 | strlcpy(dst, src, dstsize); | 557 | strlcpy(dst, src, dstsize); |
547 | return dst; | 558 | return (dst); |
548 | } | 559 | } |
549 | 560 | ||
550 | /* line_abbrevname(): Return the abbreviated (usually four-character) | 561 | /* |
562 | * line_abbrevname(): Return the abbreviated (usually four-character) | ||
551 | * form of the line (Just use the last <dstsize> characters of the | 563 | * form of the line (Just use the last <dstsize> characters of the |
552 | * full name.) | 564 | * full name.) |
553 | * | 565 | * |
554 | * NOTE: use strncpy because we do NOT necessarily want zero | 566 | * NOTE: use strncpy because we do NOT necessarily want zero |
555 | * termination */ | 567 | * termination |
568 | */ | ||
556 | char * | 569 | char * |
557 | line_abbrevname(char *dst, const char *src, int dstsize) | 570 | line_abbrevname(char *dst, const char *src, int dstsize) |
558 | { | 571 | { |
@@ -579,7 +592,7 @@ line_abbrevname(char *dst, const char *src, int dstsize) | |||
579 | strncpy(dst, src, (size_t)dstsize); | 592 | strncpy(dst, src, (size_t)dstsize); |
580 | } | 593 | } |
581 | 594 | ||
582 | return dst; | 595 | return (dst); |
583 | } | 596 | } |
584 | 597 | ||
585 | /** | 598 | /** |
@@ -595,13 +608,11 @@ line_abbrevname(char *dst, const char *src, int dstsize) | |||
595 | void | 608 | void |
596 | set_utmp_time(struct logininfo *li, struct utmp *ut) | 609 | set_utmp_time(struct logininfo *li, struct utmp *ut) |
597 | { | 610 | { |
598 | # ifdef HAVE_TV_IN_UTMP | 611 | # if defined(HAVE_TV_IN_UTMP) |
599 | ut->ut_tv.tv_sec = li->tv_sec; | 612 | ut->ut_tv.tv_sec = li->tv_sec; |
600 | ut->ut_tv.tv_usec = li->tv_usec; | 613 | ut->ut_tv.tv_usec = li->tv_usec; |
601 | # else | 614 | # elif defined(HAVE_TIME_IN_UTMP) |
602 | # ifdef HAVE_TIME_IN_UTMP | ||
603 | ut->ut_time = li->tv_sec; | 615 | ut->ut_time = li->tv_sec; |
604 | # endif | ||
605 | # endif | 616 | # endif |
606 | } | 617 | } |
607 | 618 | ||
@@ -611,7 +622,8 @@ construct_utmp(struct logininfo *li, | |||
611 | { | 622 | { |
612 | # ifdef HAVE_ADDR_V6_IN_UTMP | 623 | # ifdef HAVE_ADDR_V6_IN_UTMP |
613 | struct sockaddr_in6 *sa6; | 624 | struct sockaddr_in6 *sa6; |
614 | # endif | 625 | # endif |
626 | |||
615 | memset(ut, '\0', sizeof(*ut)); | 627 | memset(ut, '\0', sizeof(*ut)); |
616 | 628 | ||
617 | /* First fill out fields used for both logins and logouts */ | 629 | /* First fill out fields used for both logins and logouts */ |
@@ -647,7 +659,7 @@ construct_utmp(struct logininfo *li, | |||
647 | 659 | ||
648 | /* If we're logging out, leave all other fields blank */ | 660 | /* If we're logging out, leave all other fields blank */ |
649 | if (li->type == LTYPE_LOGOUT) | 661 | if (li->type == LTYPE_LOGOUT) |
650 | return; | 662 | return; |
651 | 663 | ||
652 | /* | 664 | /* |
653 | * These fields are only used when logging in, and are blank | 665 | * These fields are only used when logging in, and are blank |
@@ -655,9 +667,11 @@ construct_utmp(struct logininfo *li, | |||
655 | */ | 667 | */ |
656 | 668 | ||
657 | /* Use strncpy because we don't necessarily want null termination */ | 669 | /* Use strncpy because we don't necessarily want null termination */ |
658 | strncpy(ut->ut_name, li->username, MIN_SIZEOF(ut->ut_name, li->username)); | 670 | strncpy(ut->ut_name, li->username, |
671 | MIN_SIZEOF(ut->ut_name, li->username)); | ||
659 | # ifdef HAVE_HOST_IN_UTMP | 672 | # ifdef HAVE_HOST_IN_UTMP |
660 | strncpy(ut->ut_host, li->hostname, MIN_SIZEOF(ut->ut_host, li->hostname)); | 673 | strncpy(ut->ut_host, li->hostname, |
674 | MIN_SIZEOF(ut->ut_host, li->hostname)); | ||
661 | # endif | 675 | # endif |
662 | # ifdef HAVE_ADDR_IN_UTMP | 676 | # ifdef HAVE_ADDR_IN_UTMP |
663 | /* this is just a 32-bit IP address */ | 677 | /* this is just a 32-bit IP address */ |
@@ -692,14 +706,12 @@ construct_utmp(struct logininfo *li, | |||
692 | void | 706 | void |
693 | set_utmpx_time(struct logininfo *li, struct utmpx *utx) | 707 | set_utmpx_time(struct logininfo *li, struct utmpx *utx) |
694 | { | 708 | { |
695 | # ifdef HAVE_TV_IN_UTMPX | 709 | # if defined(HAVE_TV_IN_UTMPX) |
696 | utx->ut_tv.tv_sec = li->tv_sec; | 710 | utx->ut_tv.tv_sec = li->tv_sec; |
697 | utx->ut_tv.tv_usec = li->tv_usec; | 711 | utx->ut_tv.tv_usec = li->tv_usec; |
698 | # else /* HAVE_TV_IN_UTMPX */ | 712 | # elif defined(HAVE_TIME_IN_UTMPX) |
699 | # ifdef HAVE_TIME_IN_UTMPX | ||
700 | utx->ut_time = li->tv_sec; | 713 | utx->ut_time = li->tv_sec; |
701 | # endif /* HAVE_TIME_IN_UTMPX */ | 714 | # endif |
702 | # endif /* HAVE_TV_IN_UTMPX */ | ||
703 | } | 715 | } |
704 | 716 | ||
705 | void | 717 | void |
@@ -709,6 +721,7 @@ construct_utmpx(struct logininfo *li, struct utmpx *utx) | |||
709 | struct sockaddr_in6 *sa6; | 721 | struct sockaddr_in6 *sa6; |
710 | # endif | 722 | # endif |
711 | memset(utx, '\0', sizeof(*utx)); | 723 | memset(utx, '\0', sizeof(*utx)); |
724 | |||
712 | # ifdef HAVE_ID_IN_UTMPX | 725 | # ifdef HAVE_ID_IN_UTMPX |
713 | line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id)); | 726 | line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id)); |
714 | # endif | 727 | # endif |
@@ -725,8 +738,10 @@ construct_utmpx(struct logininfo *li, struct utmpx *utx) | |||
725 | line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line)); | 738 | line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line)); |
726 | set_utmpx_time(li, utx); | 739 | set_utmpx_time(li, utx); |
727 | utx->ut_pid = li->pid; | 740 | utx->ut_pid = li->pid; |
741 | |||
728 | /* strncpy(): Don't necessarily want null termination */ | 742 | /* strncpy(): Don't necessarily want null termination */ |
729 | strncpy(utx->ut_name, li->username, MIN_SIZEOF(utx->ut_name, li->username)); | 743 | strncpy(utx->ut_name, li->username, |
744 | MIN_SIZEOF(utx->ut_name, li->username)); | ||
730 | 745 | ||
731 | if (li->type == LTYPE_LOGOUT) | 746 | if (li->type == LTYPE_LOGOUT) |
732 | return; | 747 | return; |
@@ -737,7 +752,8 @@ construct_utmpx(struct logininfo *li, struct utmpx *utx) | |||
737 | */ | 752 | */ |
738 | 753 | ||
739 | # ifdef HAVE_HOST_IN_UTMPX | 754 | # ifdef HAVE_HOST_IN_UTMPX |
740 | strncpy(utx->ut_host, li->hostname, MIN_SIZEOF(utx->ut_host, li->hostname)); | 755 | strncpy(utx->ut_host, li->hostname, |
756 | MIN_SIZEOF(utx->ut_host, li->hostname)); | ||
741 | # endif | 757 | # endif |
742 | # ifdef HAVE_ADDR_IN_UTMPX | 758 | # ifdef HAVE_ADDR_IN_UTMPX |
743 | /* this is just a 32-bit IP address */ | 759 | /* this is just a 32-bit IP address */ |
@@ -785,16 +801,17 @@ utmp_write_library(struct logininfo *li, struct utmp *ut) | |||
785 | { | 801 | { |
786 | setutent(); | 802 | setutent(); |
787 | pututline(ut); | 803 | pututline(ut); |
788 | |||
789 | # ifdef HAVE_ENDUTENT | 804 | # ifdef HAVE_ENDUTENT |
790 | endutent(); | 805 | endutent(); |
791 | # endif | 806 | # endif |
792 | return 1; | 807 | return (1); |
793 | } | 808 | } |
794 | # else /* UTMP_USE_LIBRARY */ | 809 | # else /* UTMP_USE_LIBRARY */ |
795 | 810 | ||
796 | /* write a utmp entry direct to the file */ | 811 | /* |
797 | /* This is a slightly modification of code in OpenBSD's login.c */ | 812 | * Write a utmp entry direct to the file |
813 | * This is a slightly modification of code in OpenBSD's login.c | ||
814 | */ | ||
798 | static int | 815 | static int |
799 | utmp_write_direct(struct logininfo *li, struct utmp *ut) | 816 | utmp_write_direct(struct logininfo *li, struct utmp *ut) |
800 | { | 817 | { |
@@ -805,19 +822,18 @@ utmp_write_direct(struct logininfo *li, struct utmp *ut) | |||
805 | /* FIXME: (ATL) ttyslot() needs local implementation */ | 822 | /* FIXME: (ATL) ttyslot() needs local implementation */ |
806 | 823 | ||
807 | #if defined(HAVE_GETTTYENT) | 824 | #if defined(HAVE_GETTTYENT) |
808 | register struct ttyent *ty; | 825 | struct ttyent *ty; |
809 | 826 | ||
810 | tty=0; | 827 | tty=0; |
811 | |||
812 | setttyent(); | 828 | setttyent(); |
813 | while ((struct ttyent *)0 != (ty = getttyent())) { | 829 | while (NULL != (ty = getttyent())) { |
814 | tty++; | 830 | tty++; |
815 | if (!strncmp(ty->ty_name, ut->ut_line, sizeof(ut->ut_line))) | 831 | if (!strncmp(ty->ty_name, ut->ut_line, sizeof(ut->ut_line))) |
816 | break; | 832 | break; |
817 | } | 833 | } |
818 | endttyent(); | 834 | endttyent(); |
819 | 835 | ||
820 | if((struct ttyent *)0 == ty) { | 836 | if (NULL == ty) { |
821 | logit("%s: tty not found", __func__); | 837 | logit("%s: tty not found", __func__); |
822 | return (0); | 838 | return (0); |
823 | } | 839 | } |
@@ -832,12 +848,12 @@ utmp_write_direct(struct logininfo *li, struct utmp *ut) | |||
832 | 848 | ||
833 | pos = (off_t)tty * sizeof(struct utmp); | 849 | pos = (off_t)tty * sizeof(struct utmp); |
834 | if ((ret = lseek(fd, pos, SEEK_SET)) == -1) { | 850 | if ((ret = lseek(fd, pos, SEEK_SET)) == -1) { |
835 | logit("%s: llseek: %s", strerror(errno)); | 851 | logit("%s: lseek: %s", __func__, strerror(errno)); |
836 | return (0); | 852 | return (0); |
837 | } | 853 | } |
838 | if (ret != pos) { | 854 | if (ret != pos) { |
839 | logit("%s: Couldn't seek to tty %s slot in %s", tty, | 855 | logit("%s: Couldn't seek to tty %d slot in %s", |
840 | UTMP_FILE); | 856 | __func__, tty, UTMP_FILE); |
841 | return (0); | 857 | return (0); |
842 | } | 858 | } |
843 | /* | 859 | /* |
@@ -846,29 +862,29 @@ utmp_write_direct(struct logininfo *li, struct utmp *ut) | |||
846 | * and ut_line and ut_name match, preserve the old ut_line. | 862 | * and ut_line and ut_name match, preserve the old ut_line. |
847 | */ | 863 | */ |
848 | if (atomicio(read, fd, &old_ut, sizeof(old_ut)) == sizeof(old_ut) && | 864 | if (atomicio(read, fd, &old_ut, sizeof(old_ut)) == sizeof(old_ut) && |
849 | (ut->ut_host[0] == '\0') && (old_ut.ut_host[0] != '\0') && | 865 | (ut->ut_host[0] == '\0') && (old_ut.ut_host[0] != '\0') && |
850 | (strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0) && | 866 | (strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0) && |
851 | (strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0)) { | 867 | (strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0)) |
852 | (void)memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host)); | 868 | memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host)); |
853 | } | ||
854 | 869 | ||
855 | if ((ret = lseek(fd, pos, SEEK_SET)) == -1) { | 870 | if ((ret = lseek(fd, pos, SEEK_SET)) == -1) { |
856 | logit("%s: llseek: %s", __func__, strerror(errno)); | 871 | logit("%s: lseek: %s", __func__, strerror(errno)); |
857 | return (0); | 872 | return (0); |
858 | } | 873 | } |
859 | if (ret != pos) { | 874 | if (ret != pos) { |
860 | logit("%s: Couldn't seek to tty %s slot in %s", | 875 | logit("%s: Couldn't seek to tty %d slot in %s", |
861 | __func__, tty, UTMP_FILE); | 876 | __func__, tty, UTMP_FILE); |
862 | return (0); | 877 | return (0); |
863 | } | 878 | } |
864 | if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) | 879 | if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) { |
865 | logit("%s: error writing %s: %s", __func__, | 880 | logit("%s: error writing %s: %s", __func__, |
866 | UTMP_FILE, strerror(errno)); | 881 | UTMP_FILE, strerror(errno)); |
882 | } | ||
867 | 883 | ||
868 | (void)close(fd); | 884 | close(fd); |
869 | return 1; | 885 | return (1); |
870 | } else { | 886 | } else { |
871 | return 0; | 887 | return (0); |
872 | } | 888 | } |
873 | } | 889 | } |
874 | # endif /* UTMP_USE_LIBRARY */ | 890 | # endif /* UTMP_USE_LIBRARY */ |
@@ -881,16 +897,16 @@ utmp_perform_login(struct logininfo *li) | |||
881 | construct_utmp(li, &ut); | 897 | construct_utmp(li, &ut); |
882 | # ifdef UTMP_USE_LIBRARY | 898 | # ifdef UTMP_USE_LIBRARY |
883 | if (!utmp_write_library(li, &ut)) { | 899 | if (!utmp_write_library(li, &ut)) { |
884 | logit("utmp_perform_login: utmp_write_library() failed"); | 900 | logit("%s: utmp_write_library() failed", __func__); |
885 | return 0; | 901 | return (0); |
886 | } | 902 | } |
887 | # else | 903 | # else |
888 | if (!utmp_write_direct(li, &ut)) { | 904 | if (!utmp_write_direct(li, &ut)) { |
889 | logit("utmp_perform_login: utmp_write_direct() failed"); | 905 | logit("%s: utmp_write_direct() failed", __func__); |
890 | return 0; | 906 | return (0); |
891 | } | 907 | } |
892 | # endif | 908 | # endif |
893 | return 1; | 909 | return (1); |
894 | } | 910 | } |
895 | 911 | ||
896 | 912 | ||
@@ -902,16 +918,16 @@ utmp_perform_logout(struct logininfo *li) | |||
902 | construct_utmp(li, &ut); | 918 | construct_utmp(li, &ut); |
903 | # ifdef UTMP_USE_LIBRARY | 919 | # ifdef UTMP_USE_LIBRARY |
904 | if (!utmp_write_library(li, &ut)) { | 920 | if (!utmp_write_library(li, &ut)) { |
905 | logit("utmp_perform_logout: utmp_write_library() failed"); | 921 | logit("%s: utmp_write_library() failed", __func__); |
906 | return 0; | 922 | return (0); |
907 | } | 923 | } |
908 | # else | 924 | # else |
909 | if (!utmp_write_direct(li, &ut)) { | 925 | if (!utmp_write_direct(li, &ut)) { |
910 | logit("utmp_perform_logout: utmp_write_direct() failed"); | 926 | logit("%s: utmp_write_direct() failed", __func__); |
911 | return 0; | 927 | return (0); |
912 | } | 928 | } |
913 | # endif | 929 | # endif |
914 | return 1; | 930 | return (1); |
915 | } | 931 | } |
916 | 932 | ||
917 | 933 | ||
@@ -920,14 +936,14 @@ utmp_write_entry(struct logininfo *li) | |||
920 | { | 936 | { |
921 | switch(li->type) { | 937 | switch(li->type) { |
922 | case LTYPE_LOGIN: | 938 | case LTYPE_LOGIN: |
923 | return utmp_perform_login(li); | 939 | return (utmp_perform_login(li)); |
924 | 940 | ||
925 | case LTYPE_LOGOUT: | 941 | case LTYPE_LOGOUT: |
926 | return utmp_perform_logout(li); | 942 | return (utmp_perform_logout(li)); |
927 | 943 | ||
928 | default: | 944 | default: |
929 | logit("utmp_write_entry: invalid type field"); | 945 | logit("%s: invalid type field", __func__); |
930 | return 0; | 946 | return (0); |
931 | } | 947 | } |
932 | } | 948 | } |
933 | #endif /* USE_UTMP */ | 949 | #endif /* USE_UTMP */ |
@@ -958,7 +974,7 @@ utmpx_write_library(struct logininfo *li, struct utmpx *utx) | |||
958 | # ifdef HAVE_ENDUTXENT | 974 | # ifdef HAVE_ENDUTXENT |
959 | endutxent(); | 975 | endutxent(); |
960 | # endif | 976 | # endif |
961 | return 1; | 977 | return (1); |
962 | } | 978 | } |
963 | 979 | ||
964 | # else /* UTMPX_USE_LIBRARY */ | 980 | # else /* UTMPX_USE_LIBRARY */ |
@@ -967,8 +983,8 @@ utmpx_write_library(struct logininfo *li, struct utmpx *utx) | |||
967 | static int | 983 | static int |
968 | utmpx_write_direct(struct logininfo *li, struct utmpx *utx) | 984 | utmpx_write_direct(struct logininfo *li, struct utmpx *utx) |
969 | { | 985 | { |
970 | logit("utmpx_write_direct: not implemented!"); | 986 | logit("%s: not implemented!", __func__); |
971 | return 0; | 987 | return (0); |
972 | } | 988 | } |
973 | # endif /* UTMPX_USE_LIBRARY */ | 989 | # endif /* UTMPX_USE_LIBRARY */ |
974 | 990 | ||
@@ -980,16 +996,16 @@ utmpx_perform_login(struct logininfo *li) | |||
980 | construct_utmpx(li, &utx); | 996 | construct_utmpx(li, &utx); |
981 | # ifdef UTMPX_USE_LIBRARY | 997 | # ifdef UTMPX_USE_LIBRARY |
982 | if (!utmpx_write_library(li, &utx)) { | 998 | if (!utmpx_write_library(li, &utx)) { |
983 | logit("utmpx_perform_login: utmp_write_library() failed"); | 999 | logit("%s: utmp_write_library() failed", __func__); |
984 | return 0; | 1000 | return (0); |
985 | } | 1001 | } |
986 | # else | 1002 | # else |
987 | if (!utmpx_write_direct(li, &ut)) { | 1003 | if (!utmpx_write_direct(li, &ut)) { |
988 | logit("utmpx_perform_login: utmp_write_direct() failed"); | 1004 | logit("%s: utmp_write_direct() failed", __func__); |
989 | return 0; | 1005 | return (0); |
990 | } | 1006 | } |
991 | # endif | 1007 | # endif |
992 | return 1; | 1008 | return (1); |
993 | } | 1009 | } |
994 | 1010 | ||
995 | 1011 | ||
@@ -1011,7 +1027,7 @@ utmpx_perform_logout(struct logininfo *li) | |||
1011 | # else | 1027 | # else |
1012 | utmpx_write_direct(li, &utx); | 1028 | utmpx_write_direct(li, &utx); |
1013 | # endif | 1029 | # endif |
1014 | return 1; | 1030 | return (1); |
1015 | } | 1031 | } |
1016 | 1032 | ||
1017 | int | 1033 | int |
@@ -1019,12 +1035,12 @@ utmpx_write_entry(struct logininfo *li) | |||
1019 | { | 1035 | { |
1020 | switch(li->type) { | 1036 | switch(li->type) { |
1021 | case LTYPE_LOGIN: | 1037 | case LTYPE_LOGIN: |
1022 | return utmpx_perform_login(li); | 1038 | return (utmpx_perform_login(li)); |
1023 | case LTYPE_LOGOUT: | 1039 | case LTYPE_LOGOUT: |
1024 | return utmpx_perform_logout(li); | 1040 | return (utmpx_perform_logout(li)); |
1025 | default: | 1041 | default: |
1026 | logit("utmpx_write_entry: invalid type field"); | 1042 | logit("%s: invalid type field", __func__); |
1027 | return 0; | 1043 | return (0); |
1028 | } | 1044 | } |
1029 | } | 1045 | } |
1030 | #endif /* USE_UTMPX */ | 1046 | #endif /* USE_UTMPX */ |
@@ -1036,8 +1052,10 @@ utmpx_write_entry(struct logininfo *li) | |||
1036 | 1052 | ||
1037 | #ifdef USE_WTMP | 1053 | #ifdef USE_WTMP |
1038 | 1054 | ||
1039 | /* write a wtmp entry direct to the end of the file */ | 1055 | /* |
1040 | /* This is a slight modification of code in OpenBSD's logwtmp.c */ | 1056 | * Write a wtmp entry direct to the end of the file |
1057 | * This is a slight modification of code in OpenBSD's logwtmp.c | ||
1058 | */ | ||
1041 | static int | 1059 | static int |
1042 | wtmp_write(struct logininfo *li, struct utmp *ut) | 1060 | wtmp_write(struct logininfo *li, struct utmp *ut) |
1043 | { | 1061 | { |
@@ -1045,19 +1063,19 @@ wtmp_write(struct logininfo *li, struct utmp *ut) | |||
1045 | int fd, ret = 1; | 1063 | int fd, ret = 1; |
1046 | 1064 | ||
1047 | if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) { | 1065 | if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) { |
1048 | logit("wtmp_write: problem writing %s: %s", | 1066 | logit("%s: problem writing %s: %s", __func__, |
1049 | WTMP_FILE, strerror(errno)); | 1067 | WTMP_FILE, strerror(errno)); |
1050 | return 0; | 1068 | return (0); |
1051 | } | 1069 | } |
1052 | if (fstat(fd, &buf) == 0) | 1070 | if (fstat(fd, &buf) == 0) |
1053 | if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) { | 1071 | if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) { |
1054 | ftruncate(fd, buf.st_size); | 1072 | ftruncate(fd, buf.st_size); |
1055 | logit("wtmp_write: problem writing %s: %s", | 1073 | logit("%s: problem writing %s: %s", __func__, |
1056 | WTMP_FILE, strerror(errno)); | 1074 | WTMP_FILE, strerror(errno)); |
1057 | ret = 0; | 1075 | ret = 0; |
1058 | } | 1076 | } |
1059 | (void)close(fd); | 1077 | close(fd); |
1060 | return ret; | 1078 | return (ret); |
1061 | } | 1079 | } |
1062 | 1080 | ||
1063 | static int | 1081 | static int |
@@ -1066,7 +1084,7 @@ wtmp_perform_login(struct logininfo *li) | |||
1066 | struct utmp ut; | 1084 | struct utmp ut; |
1067 | 1085 | ||
1068 | construct_utmp(li, &ut); | 1086 | construct_utmp(li, &ut); |
1069 | return wtmp_write(li, &ut); | 1087 | return (wtmp_write(li, &ut)); |
1070 | } | 1088 | } |
1071 | 1089 | ||
1072 | 1090 | ||
@@ -1076,7 +1094,7 @@ wtmp_perform_logout(struct logininfo *li) | |||
1076 | struct utmp ut; | 1094 | struct utmp ut; |
1077 | 1095 | ||
1078 | construct_utmp(li, &ut); | 1096 | construct_utmp(li, &ut); |
1079 | return wtmp_write(li, &ut); | 1097 | return (wtmp_write(li, &ut)); |
1080 | } | 1098 | } |
1081 | 1099 | ||
1082 | 1100 | ||
@@ -1085,17 +1103,18 @@ wtmp_write_entry(struct logininfo *li) | |||
1085 | { | 1103 | { |
1086 | switch(li->type) { | 1104 | switch(li->type) { |
1087 | case LTYPE_LOGIN: | 1105 | case LTYPE_LOGIN: |
1088 | return wtmp_perform_login(li); | 1106 | return (wtmp_perform_login(li)); |
1089 | case LTYPE_LOGOUT: | 1107 | case LTYPE_LOGOUT: |
1090 | return wtmp_perform_logout(li); | 1108 | return (wtmp_perform_logout(li)); |
1091 | default: | 1109 | default: |
1092 | logit("wtmp_write_entry: invalid type field"); | 1110 | logit("%s: invalid type field", __func__); |
1093 | return 0; | 1111 | return (0); |
1094 | } | 1112 | } |
1095 | } | 1113 | } |
1096 | 1114 | ||
1097 | 1115 | ||
1098 | /* Notes on fetching login data from wtmp/wtmpx | 1116 | /* |
1117 | * Notes on fetching login data from wtmp/wtmpx | ||
1099 | * | 1118 | * |
1100 | * Logouts are usually recorded with (amongst other things) a blank | 1119 | * Logouts are usually recorded with (amongst other things) a blank |
1101 | * username on a given tty line. However, some systems (HP-UX is one) | 1120 | * username on a given tty line. However, some systems (HP-UX is one) |
@@ -1116,15 +1135,15 @@ static int | |||
1116 | wtmp_islogin(struct logininfo *li, struct utmp *ut) | 1135 | wtmp_islogin(struct logininfo *li, struct utmp *ut) |
1117 | { | 1136 | { |
1118 | if (strncmp(li->username, ut->ut_name, | 1137 | if (strncmp(li->username, ut->ut_name, |
1119 | MIN_SIZEOF(li->username, ut->ut_name)) == 0) { | 1138 | MIN_SIZEOF(li->username, ut->ut_name)) == 0) { |
1120 | # ifdef HAVE_TYPE_IN_UTMP | 1139 | # ifdef HAVE_TYPE_IN_UTMP |
1121 | if (ut->ut_type & USER_PROCESS) | 1140 | if (ut->ut_type & USER_PROCESS) |
1122 | return 1; | 1141 | return (1); |
1123 | # else | 1142 | # else |
1124 | return 1; | 1143 | return (1); |
1125 | # endif | 1144 | # endif |
1126 | } | 1145 | } |
1127 | return 0; | 1146 | return (0); |
1128 | } | 1147 | } |
1129 | 1148 | ||
1130 | int | 1149 | int |
@@ -1132,41 +1151,43 @@ wtmp_get_entry(struct logininfo *li) | |||
1132 | { | 1151 | { |
1133 | struct stat st; | 1152 | struct stat st; |
1134 | struct utmp ut; | 1153 | struct utmp ut; |
1135 | int fd, found=0; | 1154 | int fd, found = 0; |
1136 | 1155 | ||
1137 | /* Clear the time entries in our logininfo */ | 1156 | /* Clear the time entries in our logininfo */ |
1138 | li->tv_sec = li->tv_usec = 0; | 1157 | li->tv_sec = li->tv_usec = 0; |
1139 | 1158 | ||
1140 | if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) { | 1159 | if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) { |
1141 | logit("wtmp_get_entry: problem opening %s: %s", | 1160 | logit("%s: problem opening %s: %s", __func__, |
1142 | WTMP_FILE, strerror(errno)); | 1161 | WTMP_FILE, strerror(errno)); |
1143 | return 0; | 1162 | return (0); |
1144 | } | 1163 | } |
1145 | if (fstat(fd, &st) != 0) { | 1164 | if (fstat(fd, &st) != 0) { |
1146 | logit("wtmp_get_entry: couldn't stat %s: %s", | 1165 | logit("%s: couldn't stat %s: %s", __func__, |
1147 | WTMP_FILE, strerror(errno)); | 1166 | WTMP_FILE, strerror(errno)); |
1148 | close(fd); | 1167 | close(fd); |
1149 | return 0; | 1168 | return (0); |
1150 | } | 1169 | } |
1151 | 1170 | ||
1152 | /* Seek to the start of the last struct utmp */ | 1171 | /* Seek to the start of the last struct utmp */ |
1153 | if (lseek(fd, -(off_t)sizeof(struct utmp), SEEK_END) == -1) { | 1172 | if (lseek(fd, -(off_t)sizeof(struct utmp), SEEK_END) == -1) { |
1154 | /* Looks like we've got a fresh wtmp file */ | 1173 | /* Looks like we've got a fresh wtmp file */ |
1155 | close(fd); | 1174 | close(fd); |
1156 | return 0; | 1175 | return (0); |
1157 | } | 1176 | } |
1158 | 1177 | ||
1159 | while (!found) { | 1178 | while (!found) { |
1160 | if (atomicio(read, fd, &ut, sizeof(ut)) != sizeof(ut)) { | 1179 | if (atomicio(read, fd, &ut, sizeof(ut)) != sizeof(ut)) { |
1161 | logit("wtmp_get_entry: read of %s failed: %s", | 1180 | logit("%s: read of %s failed: %s", __func__, |
1162 | WTMP_FILE, strerror(errno)); | 1181 | WTMP_FILE, strerror(errno)); |
1163 | close (fd); | 1182 | close (fd); |
1164 | return 0; | 1183 | return (0); |
1165 | } | 1184 | } |
1166 | if ( wtmp_islogin(li, &ut) ) { | 1185 | if ( wtmp_islogin(li, &ut) ) { |
1167 | found = 1; | 1186 | found = 1; |
1168 | /* We've already checked for a time in struct | 1187 | /* |
1169 | * utmp, in login_getlast(). */ | 1188 | * We've already checked for a time in struct |
1189 | * utmp, in login_getlast() | ||
1190 | */ | ||
1170 | # ifdef HAVE_TIME_IN_UTMP | 1191 | # ifdef HAVE_TIME_IN_UTMP |
1171 | li->tv_sec = ut.ut_time; | 1192 | li->tv_sec = ut.ut_time; |
1172 | # else | 1193 | # else |
@@ -1175,24 +1196,24 @@ wtmp_get_entry(struct logininfo *li) | |||
1175 | # endif | 1196 | # endif |
1176 | # endif | 1197 | # endif |
1177 | line_fullname(li->line, ut.ut_line, | 1198 | line_fullname(li->line, ut.ut_line, |
1178 | MIN_SIZEOF(li->line, ut.ut_line)); | 1199 | MIN_SIZEOF(li->line, ut.ut_line)); |
1179 | # ifdef HAVE_HOST_IN_UTMP | 1200 | # ifdef HAVE_HOST_IN_UTMP |
1180 | strlcpy(li->hostname, ut.ut_host, | 1201 | strlcpy(li->hostname, ut.ut_host, |
1181 | MIN_SIZEOF(li->hostname, ut.ut_host)); | 1202 | MIN_SIZEOF(li->hostname, ut.ut_host)); |
1182 | # endif | 1203 | # endif |
1183 | continue; | 1204 | continue; |
1184 | } | 1205 | } |
1185 | /* Seek back 2 x struct utmp */ | 1206 | /* Seek back 2 x struct utmp */ |
1186 | if (lseek(fd, -(off_t)(2 * sizeof(struct utmp)), SEEK_CUR) == -1) { | 1207 | if (lseek(fd, -(off_t)(2 * sizeof(struct utmp)), SEEK_CUR) == -1) { |
1187 | /* We've found the start of the file, so quit */ | 1208 | /* We've found the start of the file, so quit */ |
1188 | close (fd); | 1209 | close(fd); |
1189 | return 0; | 1210 | return (0); |
1190 | } | 1211 | } |
1191 | } | 1212 | } |
1192 | 1213 | ||
1193 | /* We found an entry. Tidy up and return */ | 1214 | /* We found an entry. Tidy up and return */ |
1194 | close(fd); | 1215 | close(fd); |
1195 | return 1; | 1216 | return (1); |
1196 | } | 1217 | } |
1197 | # endif /* USE_WTMP */ | 1218 | # endif /* USE_WTMP */ |
1198 | 1219 | ||
@@ -1202,8 +1223,10 @@ wtmp_get_entry(struct logininfo *li) | |||
1202 | **/ | 1223 | **/ |
1203 | 1224 | ||
1204 | #ifdef USE_WTMPX | 1225 | #ifdef USE_WTMPX |
1205 | /* write a wtmpx entry direct to the end of the file */ | 1226 | /* |
1206 | /* This is a slight modification of code in OpenBSD's logwtmp.c */ | 1227 | * Write a wtmpx entry direct to the end of the file |
1228 | * This is a slight modification of code in OpenBSD's logwtmp.c | ||
1229 | */ | ||
1207 | static int | 1230 | static int |
1208 | wtmpx_write(struct logininfo *li, struct utmpx *utx) | 1231 | wtmpx_write(struct logininfo *li, struct utmpx *utx) |
1209 | { | 1232 | { |
@@ -1212,24 +1235,24 @@ wtmpx_write(struct logininfo *li, struct utmpx *utx) | |||
1212 | int fd, ret = 1; | 1235 | int fd, ret = 1; |
1213 | 1236 | ||
1214 | if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) { | 1237 | if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) { |
1215 | logit("wtmpx_write: problem opening %s: %s", | 1238 | logit("%s: problem opening %s: %s", __func__, |
1216 | WTMPX_FILE, strerror(errno)); | 1239 | WTMPX_FILE, strerror(errno)); |
1217 | return 0; | 1240 | return (0); |
1218 | } | 1241 | } |
1219 | 1242 | ||
1220 | if (fstat(fd, &buf) == 0) | 1243 | if (fstat(fd, &buf) == 0) |
1221 | if (atomicio(vwrite, fd, utx, sizeof(*utx)) != sizeof(*utx)) { | 1244 | if (atomicio(vwrite, fd, utx, sizeof(*utx)) != sizeof(*utx)) { |
1222 | ftruncate(fd, buf.st_size); | 1245 | ftruncate(fd, buf.st_size); |
1223 | logit("wtmpx_write: problem writing %s: %s", | 1246 | logit("%s: problem writing %s: %s", __func__, |
1224 | WTMPX_FILE, strerror(errno)); | 1247 | WTMPX_FILE, strerror(errno)); |
1225 | ret = 0; | 1248 | ret = 0; |
1226 | } | 1249 | } |
1227 | (void)close(fd); | 1250 | close(fd); |
1228 | 1251 | ||
1229 | return ret; | 1252 | return (ret); |
1230 | #else | 1253 | #else |
1231 | updwtmpx(WTMPX_FILE, utx); | 1254 | updwtmpx(WTMPX_FILE, utx); |
1232 | return 1; | 1255 | return (1); |
1233 | #endif | 1256 | #endif |
1234 | } | 1257 | } |
1235 | 1258 | ||
@@ -1240,7 +1263,7 @@ wtmpx_perform_login(struct logininfo *li) | |||
1240 | struct utmpx utx; | 1263 | struct utmpx utx; |
1241 | 1264 | ||
1242 | construct_utmpx(li, &utx); | 1265 | construct_utmpx(li, &utx); |
1243 | return wtmpx_write(li, &utx); | 1266 | return (wtmpx_write(li, &utx)); |
1244 | } | 1267 | } |
1245 | 1268 | ||
1246 | 1269 | ||
@@ -1250,7 +1273,7 @@ wtmpx_perform_logout(struct logininfo *li) | |||
1250 | struct utmpx utx; | 1273 | struct utmpx utx; |
1251 | 1274 | ||
1252 | construct_utmpx(li, &utx); | 1275 | construct_utmpx(li, &utx); |
1253 | return wtmpx_write(li, &utx); | 1276 | return (wtmpx_write(li, &utx)); |
1254 | } | 1277 | } |
1255 | 1278 | ||
1256 | 1279 | ||
@@ -1259,12 +1282,12 @@ wtmpx_write_entry(struct logininfo *li) | |||
1259 | { | 1282 | { |
1260 | switch(li->type) { | 1283 | switch(li->type) { |
1261 | case LTYPE_LOGIN: | 1284 | case LTYPE_LOGIN: |
1262 | return wtmpx_perform_login(li); | 1285 | return (wtmpx_perform_login(li)); |
1263 | case LTYPE_LOGOUT: | 1286 | case LTYPE_LOGOUT: |
1264 | return wtmpx_perform_logout(li); | 1287 | return (wtmpx_perform_logout(li)); |
1265 | default: | 1288 | default: |
1266 | logit("wtmpx_write_entry: invalid type field"); | 1289 | logit("%s: invalid type field", __func__); |
1267 | return 0; | 1290 | return (0); |
1268 | } | 1291 | } |
1269 | } | 1292 | } |
1270 | 1293 | ||
@@ -1275,16 +1298,16 @@ wtmpx_write_entry(struct logininfo *li) | |||
1275 | static int | 1298 | static int |
1276 | wtmpx_islogin(struct logininfo *li, struct utmpx *utx) | 1299 | wtmpx_islogin(struct logininfo *li, struct utmpx *utx) |
1277 | { | 1300 | { |
1278 | if ( strncmp(li->username, utx->ut_name, | 1301 | if (strncmp(li->username, utx->ut_name, |
1279 | MIN_SIZEOF(li->username, utx->ut_name)) == 0 ) { | 1302 | MIN_SIZEOF(li->username, utx->ut_name)) == 0 ) { |
1280 | # ifdef HAVE_TYPE_IN_UTMPX | 1303 | # ifdef HAVE_TYPE_IN_UTMPX |
1281 | if (utx->ut_type == USER_PROCESS) | 1304 | if (utx->ut_type == USER_PROCESS) |
1282 | return 1; | 1305 | return (1); |
1283 | # else | 1306 | # else |
1284 | return 1; | 1307 | return (1); |
1285 | # endif | 1308 | # endif |
1286 | } | 1309 | } |
1287 | return 0; | 1310 | return (0); |
1288 | } | 1311 | } |
1289 | 1312 | ||
1290 | 1313 | ||
@@ -1299,57 +1322,57 @@ wtmpx_get_entry(struct logininfo *li) | |||
1299 | li->tv_sec = li->tv_usec = 0; | 1322 | li->tv_sec = li->tv_usec = 0; |
1300 | 1323 | ||
1301 | if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) { | 1324 | if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) { |
1302 | logit("wtmpx_get_entry: problem opening %s: %s", | 1325 | logit("%s: problem opening %s: %s", __func__, |
1303 | WTMPX_FILE, strerror(errno)); | 1326 | WTMPX_FILE, strerror(errno)); |
1304 | return 0; | 1327 | return (0); |
1305 | } | 1328 | } |
1306 | if (fstat(fd, &st) != 0) { | 1329 | if (fstat(fd, &st) != 0) { |
1307 | logit("wtmpx_get_entry: couldn't stat %s: %s", | 1330 | logit("%s: couldn't stat %s: %s", __func__, |
1308 | WTMPX_FILE, strerror(errno)); | 1331 | WTMPX_FILE, strerror(errno)); |
1309 | close(fd); | 1332 | close(fd); |
1310 | return 0; | 1333 | return (0); |
1311 | } | 1334 | } |
1312 | 1335 | ||
1313 | /* Seek to the start of the last struct utmpx */ | 1336 | /* Seek to the start of the last struct utmpx */ |
1314 | if (lseek(fd, -(off_t)sizeof(struct utmpx), SEEK_END) == -1 ) { | 1337 | if (lseek(fd, -(off_t)sizeof(struct utmpx), SEEK_END) == -1 ) { |
1315 | /* probably a newly rotated wtmpx file */ | 1338 | /* probably a newly rotated wtmpx file */ |
1316 | close(fd); | 1339 | close(fd); |
1317 | return 0; | 1340 | return (0); |
1318 | } | 1341 | } |
1319 | 1342 | ||
1320 | while (!found) { | 1343 | while (!found) { |
1321 | if (atomicio(read, fd, &utx, sizeof(utx)) != sizeof(utx)) { | 1344 | if (atomicio(read, fd, &utx, sizeof(utx)) != sizeof(utx)) { |
1322 | logit("wtmpx_get_entry: read of %s failed: %s", | 1345 | logit("%s: read of %s failed: %s", __func__, |
1323 | WTMPX_FILE, strerror(errno)); | 1346 | WTMPX_FILE, strerror(errno)); |
1324 | close (fd); | 1347 | close (fd); |
1325 | return 0; | 1348 | return (0); |
1326 | } | 1349 | } |
1327 | /* Logouts are recorded as a blank username on a particular line. | 1350 | /* |
1328 | * So, we just need to find the username in struct utmpx */ | 1351 | * Logouts are recorded as a blank username on a particular |
1329 | if ( wtmpx_islogin(li, &utx) ) { | 1352 | * line. So, we just need to find the username in struct utmpx |
1353 | */ | ||
1354 | if (wtmpx_islogin(li, &utx)) { | ||
1330 | found = 1; | 1355 | found = 1; |
1331 | # ifdef HAVE_TV_IN_UTMPX | 1356 | # if defined(HAVE_TV_IN_UTMPX) |
1332 | li->tv_sec = utx.ut_tv.tv_sec; | 1357 | li->tv_sec = utx.ut_tv.tv_sec; |
1333 | # else | 1358 | # elif defined(HAVE_TIME_IN_UTMPX) |
1334 | # ifdef HAVE_TIME_IN_UTMPX | ||
1335 | li->tv_sec = utx.ut_time; | 1359 | li->tv_sec = utx.ut_time; |
1336 | # endif | ||
1337 | # endif | 1360 | # endif |
1338 | line_fullname(li->line, utx.ut_line, sizeof(li->line)); | 1361 | line_fullname(li->line, utx.ut_line, sizeof(li->line)); |
1339 | # ifdef HAVE_HOST_IN_UTMPX | 1362 | # if defined(HAVE_HOST_IN_UTMPX) |
1340 | strlcpy(li->hostname, utx.ut_host, | 1363 | strlcpy(li->hostname, utx.ut_host, |
1341 | MIN_SIZEOF(li->hostname, utx.ut_host)); | 1364 | MIN_SIZEOF(li->hostname, utx.ut_host)); |
1342 | # endif | 1365 | # endif |
1343 | continue; | 1366 | continue; |
1344 | } | 1367 | } |
1345 | if (lseek(fd, -(off_t)(2 * sizeof(struct utmpx)), SEEK_CUR) == -1) { | 1368 | if (lseek(fd, -(off_t)(2 * sizeof(struct utmpx)), SEEK_CUR) == -1) { |
1346 | close (fd); | 1369 | close(fd); |
1347 | return 0; | 1370 | return (0); |
1348 | } | 1371 | } |
1349 | } | 1372 | } |
1350 | 1373 | ||
1351 | close(fd); | 1374 | close(fd); |
1352 | return 1; | 1375 | return (1); |
1353 | } | 1376 | } |
1354 | #endif /* USE_WTMPX */ | 1377 | #endif /* USE_WTMPX */ |
1355 | 1378 | ||
@@ -1363,15 +1386,12 @@ syslogin_perform_login(struct logininfo *li) | |||
1363 | { | 1386 | { |
1364 | struct utmp *ut; | 1387 | struct utmp *ut; |
1365 | 1388 | ||
1366 | if (! (ut = (struct utmp *)malloc(sizeof(*ut)))) { | 1389 | ut = xmalloc(sizeof(*ut)); |
1367 | logit("syslogin_perform_login: couldn't malloc()"); | ||
1368 | return 0; | ||
1369 | } | ||
1370 | construct_utmp(li, ut); | 1390 | construct_utmp(li, ut); |
1371 | login(ut); | 1391 | login(ut); |
1372 | free(ut); | 1392 | free(ut); |
1373 | 1393 | ||
1374 | return 1; | 1394 | return (1); |
1375 | } | 1395 | } |
1376 | 1396 | ||
1377 | static int | 1397 | static int |
@@ -1382,19 +1402,18 @@ syslogin_perform_logout(struct logininfo *li) | |||
1382 | 1402 | ||
1383 | (void)line_stripname(line, li->line, sizeof(line)); | 1403 | (void)line_stripname(line, li->line, sizeof(line)); |
1384 | 1404 | ||
1385 | if (!logout(line)) { | 1405 | if (!logout(line)) |
1386 | logit("syslogin_perform_logout: logout() returned an error"); | 1406 | logit("%s: logout() returned an error", __func__); |
1387 | # ifdef HAVE_LOGWTMP | 1407 | # ifdef HAVE_LOGWTMP |
1388 | } else { | 1408 | else |
1389 | logwtmp(line, "", ""); | 1409 | logwtmp(line, "", ""); |
1390 | # endif | 1410 | # endif |
1391 | } | ||
1392 | /* FIXME: (ATL - if the need arises) What to do if we have | 1411 | /* FIXME: (ATL - if the need arises) What to do if we have |
1393 | * login, but no logout? what if logout but no logwtmp? All | 1412 | * login, but no logout? what if logout but no logwtmp? All |
1394 | * routines are in libutil so they should all be there, | 1413 | * routines are in libutil so they should all be there, |
1395 | * but... */ | 1414 | * but... */ |
1396 | # endif | 1415 | # endif |
1397 | return 1; | 1416 | return (1); |
1398 | } | 1417 | } |
1399 | 1418 | ||
1400 | int | 1419 | int |
@@ -1402,12 +1421,12 @@ syslogin_write_entry(struct logininfo *li) | |||
1402 | { | 1421 | { |
1403 | switch (li->type) { | 1422 | switch (li->type) { |
1404 | case LTYPE_LOGIN: | 1423 | case LTYPE_LOGIN: |
1405 | return syslogin_perform_login(li); | 1424 | return (syslogin_perform_login(li)); |
1406 | case LTYPE_LOGOUT: | 1425 | case LTYPE_LOGOUT: |
1407 | return syslogin_perform_logout(li); | 1426 | return (syslogin_perform_logout(li)); |
1408 | default: | 1427 | default: |
1409 | logit("syslogin_write_entry: Invalid type field"); | 1428 | logit("%s: Invalid type field", __func__); |
1410 | return 0; | 1429 | return (0); |
1411 | } | 1430 | } |
1412 | } | 1431 | } |
1413 | #endif /* USE_LOGIN */ | 1432 | #endif /* USE_LOGIN */ |
@@ -1429,7 +1448,7 @@ lastlog_construct(struct logininfo *li, struct lastlog *last) | |||
1429 | /* clear the structure */ | 1448 | /* clear the structure */ |
1430 | memset(last, '\0', sizeof(*last)); | 1449 | memset(last, '\0', sizeof(*last)); |
1431 | 1450 | ||
1432 | (void)line_stripname(last->ll_line, li->line, sizeof(last->ll_line)); | 1451 | line_stripname(last->ll_line, li->line, sizeof(last->ll_line)); |
1433 | strlcpy(last->ll_host, li->hostname, | 1452 | strlcpy(last->ll_host, li->hostname, |
1434 | MIN_SIZEOF(last->ll_host, li->hostname)); | 1453 | MIN_SIZEOF(last->ll_host, li->hostname)); |
1435 | last->ll_time = li->tv_sec; | 1454 | last->ll_time = li->tv_sec; |
@@ -1441,16 +1460,16 @@ lastlog_filetype(char *filename) | |||
1441 | struct stat st; | 1460 | struct stat st; |
1442 | 1461 | ||
1443 | if (stat(LASTLOG_FILE, &st) != 0) { | 1462 | if (stat(LASTLOG_FILE, &st) != 0) { |
1444 | logit("lastlog_perform_login: Couldn't stat %s: %s", LASTLOG_FILE, | 1463 | logit("%s: Couldn't stat %s: %s", __func__, |
1445 | strerror(errno)); | 1464 | LASTLOG_FILE, strerror(errno)); |
1446 | return 0; | 1465 | return (0); |
1447 | } | 1466 | } |
1448 | if (S_ISDIR(st.st_mode)) | 1467 | if (S_ISDIR(st.st_mode)) |
1449 | return LL_DIR; | 1468 | return (LL_DIR); |
1450 | else if (S_ISREG(st.st_mode)) | 1469 | else if (S_ISREG(st.st_mode)) |
1451 | return LL_FILE; | 1470 | return (LL_FILE); |
1452 | else | 1471 | else |
1453 | return LL_OTHER; | 1472 | return (LL_OTHER); |
1454 | } | 1473 | } |
1455 | 1474 | ||
1456 | 1475 | ||
@@ -1464,38 +1483,39 @@ lastlog_openseek(struct logininfo *li, int *fd, int filemode) | |||
1464 | 1483 | ||
1465 | type = lastlog_filetype(LASTLOG_FILE); | 1484 | type = lastlog_filetype(LASTLOG_FILE); |
1466 | switch (type) { | 1485 | switch (type) { |
1467 | case LL_FILE: | 1486 | case LL_FILE: |
1468 | strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file)); | 1487 | strlcpy(lastlog_file, LASTLOG_FILE, |
1469 | break; | 1488 | sizeof(lastlog_file)); |
1470 | case LL_DIR: | 1489 | break; |
1471 | snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s", | 1490 | case LL_DIR: |
1472 | LASTLOG_FILE, li->username); | 1491 | snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s", |
1473 | break; | 1492 | LASTLOG_FILE, li->username); |
1474 | default: | 1493 | break; |
1475 | logit("lastlog_openseek: %.100s is not a file or directory!", | 1494 | default: |
1476 | LASTLOG_FILE); | 1495 | logit("%s: %.100s is not a file or directory!", __func__, |
1477 | return 0; | 1496 | LASTLOG_FILE); |
1497 | return (0); | ||
1478 | } | 1498 | } |
1479 | 1499 | ||
1480 | *fd = open(lastlog_file, filemode, 0600); | 1500 | *fd = open(lastlog_file, filemode, 0600); |
1481 | if ( *fd < 0) { | 1501 | if (*fd < 0) { |
1482 | debug("lastlog_openseek: Couldn't open %s: %s", | 1502 | debug("%s: Couldn't open %s: %s", __func__, |
1483 | lastlog_file, strerror(errno)); | 1503 | lastlog_file, strerror(errno)); |
1484 | return 0; | 1504 | return (0); |
1485 | } | 1505 | } |
1486 | 1506 | ||
1487 | if (type == LL_FILE) { | 1507 | if (type == LL_FILE) { |
1488 | /* find this uid's offset in the lastlog file */ | 1508 | /* find this uid's offset in the lastlog file */ |
1489 | offset = (off_t) ((long)li->uid * sizeof(struct lastlog)); | 1509 | offset = (off_t) ((long)li->uid * sizeof(struct lastlog)); |
1490 | 1510 | ||
1491 | if ( lseek(*fd, offset, SEEK_SET) != offset ) { | 1511 | if (lseek(*fd, offset, SEEK_SET) != offset) { |
1492 | logit("lastlog_openseek: %s->lseek(): %s", | 1512 | logit("%s: %s->lseek(): %s", __func__, |
1493 | lastlog_file, strerror(errno)); | 1513 | lastlog_file, strerror(errno)); |
1494 | return 0; | 1514 | return (0); |
1495 | } | 1515 | } |
1496 | } | 1516 | } |
1497 | 1517 | ||
1498 | return 1; | 1518 | return (1); |
1499 | } | 1519 | } |
1500 | 1520 | ||
1501 | static int | 1521 | static int |
@@ -1508,18 +1528,18 @@ lastlog_perform_login(struct logininfo *li) | |||
1508 | lastlog_construct(li, &last); | 1528 | lastlog_construct(li, &last); |
1509 | 1529 | ||
1510 | if (!lastlog_openseek(li, &fd, O_RDWR|O_CREAT)) | 1530 | if (!lastlog_openseek(li, &fd, O_RDWR|O_CREAT)) |
1511 | return(0); | 1531 | return (0); |
1512 | 1532 | ||
1513 | /* write the entry */ | 1533 | /* write the entry */ |
1514 | if (atomicio(vwrite, fd, &last, sizeof(last)) != sizeof(last)) { | 1534 | if (atomicio(vwrite, fd, &last, sizeof(last)) != sizeof(last)) { |
1515 | close(fd); | 1535 | close(fd); |
1516 | logit("lastlog_write_filemode: Error writing to %s: %s", | 1536 | logit("%s: Error writing to %s: %s", __func__, |
1517 | LASTLOG_FILE, strerror(errno)); | 1537 | LASTLOG_FILE, strerror(errno)); |
1518 | return 0; | 1538 | return (0); |
1519 | } | 1539 | } |
1520 | 1540 | ||
1521 | close(fd); | 1541 | close(fd); |
1522 | return 1; | 1542 | return (1); |
1523 | } | 1543 | } |
1524 | 1544 | ||
1525 | int | 1545 | int |
@@ -1527,10 +1547,10 @@ lastlog_write_entry(struct logininfo *li) | |||
1527 | { | 1547 | { |
1528 | switch(li->type) { | 1548 | switch(li->type) { |
1529 | case LTYPE_LOGIN: | 1549 | case LTYPE_LOGIN: |
1530 | return lastlog_perform_login(li); | 1550 | return (lastlog_perform_login(li)); |
1531 | default: | 1551 | default: |
1532 | logit("lastlog_write_entry: Invalid type field"); | 1552 | logit("%s: Invalid type field", __func__); |
1533 | return 0; | 1553 | return (0); |
1534 | } | 1554 | } |
1535 | } | 1555 | } |
1536 | 1556 | ||
@@ -1539,7 +1559,7 @@ lastlog_populate_entry(struct logininfo *li, struct lastlog *last) | |||
1539 | { | 1559 | { |
1540 | line_fullname(li->line, last->ll_line, sizeof(li->line)); | 1560 | line_fullname(li->line, last->ll_line, sizeof(li->line)); |
1541 | strlcpy(li->hostname, last->ll_host, | 1561 | strlcpy(li->hostname, last->ll_host, |
1542 | MIN_SIZEOF(li->hostname, last->ll_host)); | 1562 | MIN_SIZEOF(li->hostname, last->ll_host)); |
1543 | li->tv_sec = last->ll_time; | 1563 | li->tv_sec = last->ll_time; |
1544 | } | 1564 | } |
1545 | 1565 | ||
@@ -1576,3 +1596,82 @@ lastlog_get_entry(struct logininfo *li) | |||
1576 | return (0); | 1596 | return (0); |
1577 | } | 1597 | } |
1578 | #endif /* USE_LASTLOG */ | 1598 | #endif /* USE_LASTLOG */ |
1599 | |||
1600 | #ifdef USE_BTMP | ||
1601 | /* | ||
1602 | * Logs failed login attempts in _PATH_BTMP if that exists. | ||
1603 | * The most common login failure is to give password instead of username. | ||
1604 | * So the _PATH_BTMP file checked for the correct permission, so that | ||
1605 | * only root can read it. | ||
1606 | */ | ||
1607 | |||
1608 | void | ||
1609 | record_failed_login(const char *username, const char *hostname, | ||
1610 | const char *ttyn) | ||
1611 | { | ||
1612 | int fd; | ||
1613 | struct utmp ut; | ||
1614 | struct sockaddr_storage from; | ||
1615 | size_t fromlen = sizeof(from); | ||
1616 | struct sockaddr_in *a4; | ||
1617 | struct sockaddr_in6 *a6; | ||
1618 | time_t t; | ||
1619 | struct stat fst; | ||
1620 | |||
1621 | if (geteuid() != 0) | ||
1622 | return; | ||
1623 | if ((fd = open(_PATH_BTMP, O_WRONLY | O_APPEND)) < 0) { | ||
1624 | debug("Unable to open the btmp file %s: %s", _PATH_BTMP, | ||
1625 | strerror(errno)); | ||
1626 | return; | ||
1627 | } | ||
1628 | if (fstat(fd, &fst) < 0) { | ||
1629 | logit("%s: fstat of %s failed: %s", __func__, _PATH_BTMP, | ||
1630 | strerror(errno)); | ||
1631 | goto out; | ||
1632 | } | ||
1633 | if((fst.st_mode & (S_IRWXG | S_IRWXO)) || (fst.st_uid != 0)){ | ||
1634 | logit("Excess permission or bad ownership on file %s", | ||
1635 | _PATH_BTMP); | ||
1636 | goto out; | ||
1637 | } | ||
1638 | |||
1639 | memset(&ut, 0, sizeof(ut)); | ||
1640 | /* strncpy because we don't necessarily want nul termination */ | ||
1641 | strncpy(ut.ut_user, username, sizeof(ut.ut_user)); | ||
1642 | strlcpy(ut.ut_line, "ssh:notty", sizeof(ut.ut_line)); | ||
1643 | |||
1644 | time(&t); | ||
1645 | ut.ut_time = t; /* ut_time is not always a time_t */ | ||
1646 | ut.ut_type = LOGIN_PROCESS; | ||
1647 | ut.ut_pid = getpid(); | ||
1648 | |||
1649 | /* strncpy because we don't necessarily want nul termination */ | ||
1650 | strncpy(ut.ut_host, hostname, sizeof(ut.ut_host)); | ||
1651 | |||
1652 | if (packet_connection_is_on_socket() && | ||
1653 | getpeername(packet_get_connection_in(), | ||
1654 | (struct sockaddr *)&from, &fromlen) == 0) { | ||
1655 | ipv64_normalise_mapped(&from, &fromlen); | ||
1656 | if (from.ss_family == AF_INET) { | ||
1657 | a4 = (struct sockaddr_in *)&from; | ||
1658 | memcpy(&ut.ut_addr, &(a4->sin_addr), | ||
1659 | MIN_SIZEOF(ut.ut_addr, a4->sin_addr)); | ||
1660 | } | ||
1661 | #ifdef HAVE_ADDR_V6_IN_UTMP | ||
1662 | if (from.ss_family == AF_INET6) { | ||
1663 | a6 = (struct sockaddr_in6 *)&from; | ||
1664 | memcpy(&ut.ut_addr_v6, &(a6->sin6_addr), | ||
1665 | MIN_SIZEOF(ut.ut_addr_v6, a6->sin6_addr)); | ||
1666 | } | ||
1667 | #endif | ||
1668 | } | ||
1669 | |||
1670 | if (atomicio(vwrite, fd, &ut, sizeof(ut)) != sizeof(ut)) | ||
1671 | error("Failed to write to %s: %s", _PATH_BTMP, | ||
1672 | strerror(errno)); | ||
1673 | |||
1674 | out: | ||
1675 | close(fd); | ||
1676 | } | ||
1677 | #endif /* USE_BTMP */ | ||