summaryrefslogtreecommitdiff
path: root/loginrec.c
diff options
context:
space:
mode:
Diffstat (limited to 'loginrec.c')
-rw-r--r--loginrec.c825
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"
161RCSID("$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
168RCSID("$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);
194int wtmp_get_entry(struct logininfo *li); 193int wtmp_get_entry(struct logininfo *li);
195int wtmpx_get_entry(struct logininfo *li); 194int wtmpx_get_entry(struct logininfo *li);
196 195
196extern 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 */
213int 215int
214login_login (struct logininfo *li) 216login_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
230login_logout(struct logininfo *li) 233login_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 */
277struct logininfo * 281struct logininfo *
278login_get_lastlog(struct logininfo *li, const int uid) 282login_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 */
314struct 319struct
315logininfo *login_alloc_entry(int pid, const char *username, 320logininfo *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 */
342int 347int
343login_init_entry(struct logininfo *li, int pid, const char *username, 348login_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 */
388void 396void
389login_set_addr(struct logininfo *li, const struct sockaddr *sa, 397login_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 **/
406int 414int
407login_write (struct logininfo *li) 415login_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 */
525char * 536char *
526line_fullname(char *dst, const char *src, int dstsize) 537line_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 */
556char * 569char *
557line_abbrevname(char *dst, const char *src, int dstsize) 570line_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)
595void 608void
596set_utmp_time(struct logininfo *li, struct utmp *ut) 609set_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,
692void 706void
693set_utmpx_time(struct logininfo *li, struct utmpx *utx) 707set_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
705void 717void
@@ -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 */
798static int 815static int
799utmp_write_direct(struct logininfo *li, struct utmp *ut) 816utmp_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)
967static int 983static int
968utmpx_write_direct(struct logininfo *li, struct utmpx *utx) 984utmpx_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
1017int 1033int
@@ -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 */
1041static int 1059static int
1042wtmp_write(struct logininfo *li, struct utmp *ut) 1060wtmp_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
1063static int 1081static 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
1116wtmp_islogin(struct logininfo *li, struct utmp *ut) 1135wtmp_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
1130int 1149int
@@ -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 */
1207static int 1230static int
1208wtmpx_write(struct logininfo *li, struct utmpx *utx) 1231wtmpx_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)
1275static int 1298static int
1276wtmpx_islogin(struct logininfo *li, struct utmpx *utx) 1299wtmpx_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
1377static int 1397static 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
1400int 1419int
@@ -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
1501static int 1521static 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
1525int 1545int
@@ -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
1608void
1609record_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
1674out:
1675 close(fd);
1676}
1677#endif /* USE_BTMP */