summaryrefslogtreecommitdiff
path: root/loginrec.c
diff options
context:
space:
mode:
authorandre <andre>2000-06-04 17:07:49 +0000
committerandre <andre>2000-06-04 17:07:49 +0000
commit61e67250dc0d6a3406c4b2cd6cb787663d194481 (patch)
tree96fa7767605aa224256e26a3ac8977ba3019ea57 /loginrec.c
parenta86c7eccbf2d2c53bac38b8194cb7fa8b71ad290 (diff)
Many changes to new login code based on Damien's feedback:
- Removed many redundant accessor/mutator methods as they're not necesary in OpenSSH - Added proper credits for OpenBSD code in loginrec.c - Changed function definitions to the OpenBSD style - Removed spurious 'L' prefix in line filename abbreviation for ut_line - Added some documentation in loginrec.c - Changed lastlog access function names - Removed #include lines in mid-file loginrec.c - loginrec.h, login.c and logintest.c changed to reflect new interface - Added TODO note for ttyslot() replacement
Diffstat (limited to 'loginrec.c')
-rw-r--r--loginrec.c805
1 files changed, 380 insertions, 425 deletions
diff --git a/loginrec.c b/loginrec.c
index 3991d91c5..ed14f3a74 100644
--- a/loginrec.c
+++ b/loginrec.c
@@ -1,5 +1,8 @@
1/* 1/*
2 * Copyright (c) 2000 Andre Lucas. All rights reserved. 2 * Copyright (c) 2000 Andre Lucas. All rights reserved.
3 * Portions copyright (c) 1998 Todd C. Miller
4 * Portions copyright (c) 1996 Jason Downs
5 * Portions copyright (c) 1996 Theo de Raadt
3 * 6 *
4 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
@@ -31,9 +34,106 @@
31 ** loginrec.c: platform-independent login recording and lastlog retrieval 34 ** loginrec.c: platform-independent login recording and lastlog retrieval
32 **/ 35 **/
33 36
37/*
38 The new login code explained
39 ============================
40
41 This code attempts to provide a common interface to login recording
42 (utmp and friends) and last login time retrieval.
43
44 Its primary means of achieving this is to use 'struct logininfo', a
45 union of all the useful fields in the various different types of
46 system login record structures one finds on UNIX variants.
47
48 We depend on autoconf to define which recording methods are to be
49 used, and which fields are contained in the relevant data structures
50 on the local system. Many C preprocessor symbols affect which code
51 gets compiled here.
52
53 The code is designed to make it easy to modify a particular
54 recording method, without affecting other methods nor requiring so
55 many nested conditional compilation blocks as were commonplace in
56 the old code.
57
58 For login recording, we try to use the local system's libraries as
59 these are clearly most likely to work correctly. For utmp systems
60 this usually means login() and logout() or setutent() etc., probably
61 in libutil, along with logwtmp() etc. On these systems, we fall back
62 to writing the files directly if we have to, though this method
63 requires very thorough testing so we do not corrupt local auditing
64 information. These files and their access methods are very system
65 specific indeed.
66
67 For utmpx systems, the corresponding library functions are
68 setutxent() etc. To the author's knowledge, all utmpx systems have
69 these library functions and so no direct write is attempted. If such
70 a system exists and needs support, direct analogues of the [uw]tmp
71 code should suffice.
72
73 Retrieving the time of last login ('lastlog') is in some ways even
74 more problemmatic than login recording. Some systems provide a
75 simple table of all users which we seek based on uid and retrieve a
76 relatively standard structure. Others record the same information in
77 a directory with a separate file, and others don't record the
78 information separately at all. For systems in the latter category,
79 we look backwards in the wtmp or wtmpx file for the last login entry
80 for our user. Naturally this is slower and on busy systems could
81 incur a significant performance penalty.
82
83 Calling the new code
84 --------------------
85
86 In OpenSSH all login recording and retrieval is performed in
87 login.c. Here you'll find working examples. Also, in the logintest.c
88 program there are more examples.
89
90 Internal handler calling method
91 -------------------------------
92
93 When a call is made to login_login() or login_logout(), both
94 routines set a struct logininfo flag defining which action (log in,
95 or log out) is to be taken. They both then call login_write(), which
96 calls whichever of the many structure-specific handlers autoconf
97 selects for the local system.
98
99 The handlers themselves handle system data structure specifics. Both
100 struct utmp and struct utmpx have utility functions (see
101 construct_utmp*()) to try to make it simpler to add extra systems
102 that introduce new features to either structure.
103
104 While it may seem terribly wasteful to replicate so much similar
105 code for each method, experience has shown that maintaining code to
106 write both struct utmp and utmpx in one function, whilst maintaining
107 support for all systems whether they have library support or not, is
108 a difficult and time-consuming task.
109
110 Lastlog support proceeds similarly. Functions login_get_lastlog()
111 (and its OpenSSH-tuned friend login_get_lastlog_time()) call
112 getlast_entry(), which tries one of three methods to find the last
113 login time. It uses local system lastlog support if it can,
114 otherwise it tries wtmp or wtmpx before giving up and returning 0,
115 meaning "tilt".
116
117 Maintenance
118 -----------
119
120 In many cases it's possible to tweak autoconf to select the correct
121 methods for a particular platform, either by improving the detection
122 code (best), or by presetting DISABLE_<method> or CONF_<method>_FILE
123 symbols for the platform.
124
125 Use logintest to check which symbols are defined before modifying
126 configure.in and loginrec.c. (You have to build logintest yourself
127 with 'make logintest' as it's not built by default.)
128
129 Otherwise, patches to the specific method(s) are very helpful!
130
131*/
132
34/** 133/**
35 ** TODO: 134 ** TODO:
36 ** sockaddr_* stuff isn't finished 135 ** homegrown ttyslot()q
136 ** test, test, test
37 ** 137 **
38 ** Platform status: 138 ** Platform status:
39 ** ---------------- 139 ** ----------------
@@ -66,19 +166,28 @@
66#include <stdio.h> 166#include <stdio.h>
67#include <errno.h> 167#include <errno.h>
68#ifdef HAVE_PWD_H 168#ifdef HAVE_PWD_H
69# include <pwd.h> 169# include <pwd.h>
70#endif 170#endif
71#ifdef HAVE_SYS_TIME_H 171#ifdef HAVE_SYS_TIME_H
72# include <sys/time.h> 172# include <sys/time.h>
73#else 173#else
74# include <time.h> 174# include <time.h>
75#endif 175#endif
176#if HAVE_UTMP_H
177# include <utmp.h>
178#endif
179#if HAVE_UTMPX_H
180# include <utmpx.h>
181#endif
182#if HAVE_LASTLOG_H
183# include <lastlog.h>
184#endif
76 185
77#include "ssh.h" 186#include "ssh.h"
78#include "xmalloc.h" 187#include "xmalloc.h"
79#include "loginrec.h" 188#include "loginrec.h"
80 189
81RCSID("$Id: loginrec.c,v 1.2 2000/06/03 16:18:19 andre Exp $"); 190RCSID("$Id: loginrec.c,v 1.3 2000/06/04 17:07:49 andre Exp $");
82 191
83 192
84/** 193/**
@@ -86,13 +195,11 @@ RCSID("$Id: loginrec.c,v 1.2 2000/06/03 16:18:19 andre Exp $");
86 **/ 195 **/
87 196
88#if HAVE_UTMP_H 197#if HAVE_UTMP_H
89# include <utmp.h>
90void set_utmp_time(struct logininfo *li, struct utmp *ut); 198void set_utmp_time(struct logininfo *li, struct utmp *ut);
91void construct_utmp(struct logininfo *li, struct utmp *ut); 199void construct_utmp(struct logininfo *li, struct utmp *ut);
92#endif 200#endif
93 201
94#ifdef HAVE_UTMPX_H 202#ifdef HAVE_UTMPX_H
95# include <utmpx.h>
96void set_utmpx_time(struct logininfo *li, struct utmpx *ut); 203void set_utmpx_time(struct logininfo *li, struct utmpx *ut);
97void construct_utmpx(struct logininfo *li, struct utmpx *ut); 204void construct_utmpx(struct logininfo *li, struct utmpx *ut);
98#endif 205#endif
@@ -114,169 +221,128 @@ int wtmpx_get_entry(struct logininfo *li);
114 ** platform-independent login functions 221 ** platform-independent login functions
115 **/ 222 **/
116 223
117/* login_alloc_entry() - allocate and initialise a logininfo */ 224/* Record a login */
118struct logininfo *login_alloc_entry(int pid, const char *username, 225int
119 const char *hostname, 226login_login (struct logininfo *li)
120 const char *line) { 227{
121 struct logininfo *newli; 228 li->type = LTYPE_LOGIN;
122 229 return login_write(li);
123 newli = (struct logininfo *) xmalloc (sizeof(struct logininfo)); 230}
124
125 if (login_init_entry(newli, pid, username, hostname, line))
126 return newli;
127 else
128 return 0; /* fail */
129} /* login_alloc_entry() */
130
131
132/* login_free_entry() - free struct memory (duh) */
133void login_free_entry(struct logininfo *li) {
134 if (li && (li->line[0] != '\0'))
135 free ((void *)li);
136 else
137 log("login_free_entry: attempt to free invalid entry (warning)");
138} /* login_free_entry() */
139
140/* login_init_entry() - initialise a struct logininfo */
141int login_init_entry(struct logininfo *li,
142 int pid, const char *username,
143 const char *hostname, const char *line) {
144
145 /* zero the structure */
146 memset(li, 0, sizeof(struct logininfo));
147
148 /* progname should be set outside this call */
149 /* type stays null by default */
150 login_set_pid(li, pid);
151 /* set the line information */
152 login_set_line(li, line);
153 login_set_username(li, username);
154 login_set_hostname(li, hostname);
155 /* exit status and termination stay null by default */
156 login_set_current_time(li);
157 /* sockaddr_* stuff must be set separately (for now) */
158 return 1;
159} /* login_init_entry() */
160 231
161 232
162void 233/* Record a logout */
163login_set_progname(struct logininfo *li, const char *progname) { 234int
164 memset(li->progname, '\0', sizeof(li->progname)); 235login_logout(struct logininfo *li)
165 if (progname) 236{
166 strlcpy(li->progname, progname, sizeof(li->progname)); 237 li->type = LTYPE_LOGOUT;
167 else 238 return login_write(li);
168 li->progname[0] = '\0'; /* set to null */
169} 239}
170 240
171void
172login_set_type(struct logininfo *li, int type) {
173 li->type = type;
174}
175 241
176void 242/* Retrieve the last login time for a user (or fake on from wtmp/wtmpx) */
177login_set_pid(struct logininfo *li, int pid) { 243unsigned int
178 if (!pid) 244login_get_lastlog_time(const int uid)
179 li->pid = (int)getpid(); 245{
180 else 246 struct logininfo li;
181 li->pid = pid;
182}
183 247
184void 248 login_get_lastlog(&li, uid);
185login_set_uid(struct logininfo *li, int uid) { 249 return li.tv_sec;
186 struct passwd *pw; 250}
187 251
252/* Retrieve a lastlog entry (or fake one from wtmp/wtmpx) */
253struct logininfo *
254login_get_lastlog(struct logininfo *li, const int uid)
255{
256 memset(li, '\0', sizeof(struct logininfo));
188 li->uid = uid; 257 li->uid = uid;
189 /* now update the username */ 258 if (getlast_entry(li))
190 pw = getpwuid(uid); 259 return li;
191 strlcpy(li->username, pw->pw_name, sizeof(li->username)); 260 else
261 return 0;
192} 262}
193 263
194void
195login_set_line(struct logininfo *li, const char *line) {
196 if (line) {
197 /* canonical form is the full name, i.e. including '/dev' */
198 line_fullname(li->line, line, sizeof(li->line));
199 } else
200 li->line[0] = '\0';
201}
202 264
203void 265/* login_alloc_entry() - allocate and initialise a logininfo */
204login_set_username(struct logininfo *li, const char *username) { 266struct
205 struct passwd *pw; 267logininfo *login_alloc_entry(int pid, const char *username,
268 const char *hostname, const char *line)
269{
270 struct logininfo *newli;
206 271
207 if (!username) { 272 newli = (struct logininfo *) xmalloc (sizeof(struct logininfo));
208 li->username[0] = '\0'; 273 (void)login_init_entry(newli, pid, username, hostname, line);
209 li->uid = -1; /* hmm... */ 274 return newli;
210 } else {
211 strlcpy(li->username, username, sizeof(li->username));
212 /* now update the uid */
213 pw = getpwnam(username);
214 li->uid = pw->pw_uid;
215 }
216} 275}
217 276
218 277
278/* login_free_entry() - free struct memory (trivial) */
219void 279void
220login_set_hostname(struct logininfo *li, const char *hostname) { 280login_free_entry(struct logininfo *li)
221 if (hostname) { /* can be null */ 281{
222 strlcpy(li->hostname, hostname, sizeof(li->hostname)); 282 xfree(li);
223 }
224} 283}
225 284
226 285
227void 286/* login_init_entry() - initialise a struct logininfo */
228login_set_exitstatus(struct logininfo *li, 287int
229 int exit, int termination) { 288login_init_entry(struct logininfo *li, int pid, const char *username,
230 /* FIXME: (ATL) And? */ 289 const char *hostname, const char *line)
231} 290{
232 291 /* zero the structure */
292 memset(li, 0, sizeof(struct logininfo));
293
294 li->pid = pid;
295 /* set the line information */
296 if (line)
297 line_fullname(li->line, line, sizeof(li->line));
233 298
234/* tv_usec should be null on systems without struct timeval */ 299 if (username)
235void 300 strlcpy(li->username, username, sizeof(li->username));
236login_set_time(struct logininfo *li, 301 if (hostname)
237 unsigned int tv_sec, unsigned int tv_usec) { 302 strlcpy(li->hostname, hostname, sizeof(li->hostname));
238 li->tv_sec = tv_sec; 303 return 1;
239 li->tv_usec = tv_usec;
240} 304}
241 305
242 306
243void 307void
244login_set_current_time(struct logininfo *li) { 308login_set_current_time(struct logininfo *li)
309{
245#ifdef HAVE_SYS_TIME_H 310#ifdef HAVE_SYS_TIME_H
246 struct timeval tv; 311 struct timeval tv;
247 312
248 gettimeofday(&tv, NULL); 313 gettimeofday(&tv, NULL);
249 li->tv_sec = tv.tv_sec ; li->tv_usec = tv.tv_usec; 314 li->tv_sec = tv.tv_sec ; li->tv_usec = tv.tv_usec;
250#else 315#else
251 time_t t = time(0); 316 time_t tm = time(0);
252 317
253 li->tv_sec = t; li->tv_usec = 0; 318 li->tv_sec = tm; li->tv_usec = 0;
254#endif 319#endif
255} 320}
256 321
257void
258login_set_ip4(struct logininfo *li,
259 const struct sockaddr_in *sa_in4) {
260 memcpy((void *)&(li->hostaddr.sa_in4), (const void *)sa_in4,
261 sizeof(struct sockaddr_in));
262}
263 322
264#ifdef HAVE_IP6 323/* copy a sockaddr_* into our logininfo */
265void 324void
266login_set_ip6(struct logininfo *li, 325login_set_addr(struct logininfo *li, const struct sockaddr *sa,
267 const struct sockaddr_in6 *sa_in6) { 326 const unsigned int sa_size)
268 memcpy((void *)&(li->hostaddr.sa_in4), (const void *)sa_in6, 327{
269 sizeof(struct sockaddr_in6)); 328 unsigned int bufsize = sa_size;
329
330 /* make sure we don't overrun our union */
331 if (sizeof(li->hostaddr) < sa_size)
332 bufsize = sizeof(li->hostaddr);
333
334 memcpy((void *)&(li->hostaddr.sa), (const void *)sa, bufsize);
270} 335}
271#endif
272 336
273/* 337
274 * record the entry 338/**
275 */ 339 ** login_write: Call low-level recording functions based on autoconf
340 ** results
341 **/
276 342
277int 343int
278login_write (struct logininfo *li) { 344login_write (struct logininfo *li)
279 345{
280 if ((int)geteuid() != 0) { 346 if ((int)geteuid() != 0) {
281 log("Attempt to write login records by non-root user (aborting)"); 347 log("Attempt to write login records by non-root user (aborting)");
282 return 1; 348 return 1;
@@ -306,97 +372,75 @@ login_write (struct logininfo *li) {
306 return 0; 372 return 0;
307} 373}
308 374
309int
310login_login (struct logininfo *li) {
311 li->type = LTYPE_LOGIN;
312 return login_write(li);
313}
314 375
315int 376/**
316login_logout(struct logininfo *li) { 377 ** getlast_entry: Call low-level functions to retrieve the last login
317 li->type = LTYPE_LOGOUT; 378 ** time.
318 return login_write(li); 379 **/
319}
320 380
381/* take the uid in li and return the last login time */
321int 382int
322login_log_entry(struct logininfo *li) { 383getlast_entry(struct logininfo *li)
323 return login_write(li); 384{
324} 385#ifdef USE_LASTLOG
325 386 if (lastlog_get_entry(li))
326 387 return 1;
327unsigned int
328login_getlasttime_name(const char *username) {
329 struct logininfo li;
330
331 memset(&li, '\0', sizeof(li));
332 login_set_username(&li, username);
333 if (getlast_entry(&li))
334 return li.tv_sec;
335 else 388 else
336 return 0; 389 return 0;
337} /* login_getlasttime_name() */ 390#else
338 391 /* !USE_LASTLOG */
339
340unsigned int
341login_getlasttime_uid(const int uid) {
342 struct logininfo li;
343 392
344 memset(&li, '\0', sizeof(li)); 393 /* Try to retrieve the last login time from wtmp */
345 login_set_uid(&li, uid); 394# if defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP))
346 if (getlast_entry(&li)) 395 /* retrieve last login time from utmp */
347 return li.tv_sec; 396 if (wtmp_get_entry(li))
397 return 1;
348 else 398 else
349 return 0; 399 return 0;
350} /* login_getlasttime_uid() */ 400# else
351 401
402 /* If wtmp isn't available, try wtmpx */
352 403
353struct logininfo * 404# if defined(USE_WTMPX) && (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX))
354login_getlastentry_name(struct logininfo *li, 405 /* retrieve last login time from utmpx */
355 const char *username) { 406 if (wtmpx_get_entry(li))
356 login_set_username(li, username); 407 return 1;
357 if (getlast_entry(li))
358 return li;
359 else 408 else
360 return 0; 409 return 0;
361} /* login_getlastentry_name() */ 410# else
362 411
363struct logininfo * 412 /* Give up: No means of retrieving last login time */
364login_getlastentry_uid(struct logininfo *li, 413 return 0;
365 const int uid) { 414# endif
366 login_set_uid(li, uid); 415# endif
367 if (getlast_entry(li)) 416#endif
368 return li; 417/* USE_LASTLOG */
369 else 418}
370 return 0;
371} /* login_getlastentry_uid() */
372 419
373 420
374/**
375 ** 'line' string utility functions
376 **/
377 421
378/* 422/*
379 * process the 'line' string into three forms: 423 * 'line' string utility functions
424 *
425 * These functions process the 'line' string into one of three forms:
426 *
380 * 1. The full filename (including '/dev') 427 * 1. The full filename (including '/dev')
381 * 2. The stripped name (excluding '/dev') 428 * 2. The stripped name (excluding '/dev')
382 * 3. The abbreviated name (e.g. /dev/ttyp00 429 * 3. The abbreviated name (e.g. /dev/ttyp00 -> yp00
430 * /dev/pts/1 -> ts/1 )
383 * 431 *
384 * Form 3 is used on some systems to identify a .tmp.? entry when 432 * Form 3 is used on some systems to identify a .tmp.? entry when
385 * attempting to remove it. Typically both addition and removal is 433 * attempting to remove it. Typically both addition and removal is
386 * performed by one application - say, sshd - so as long as the 434 * performed by one application - say, sshd - so as long as the choice
387 * choice uniquely identifies a terminal and is the same at login and 435 * uniquely identifies a terminal it's ok.
388 * logout time, we're in good shape.
389 *
390 * NOTE: None of these calls actually allocate any memory -
391 * since their target is probably a structure, they don't
392 * need to.
393 */ 436 */
394 437
395 438
396/* add the leading '/dev/' if it doesn't exist 439/* line_fullname(): add the leading '/dev/' if it doesn't exist make
397 * make sure dst has enough space, if not just copy src (ugh) */ 440 * sure dst has enough space, if not just copy src (ugh) */
398char * 441char *
399line_fullname(char *dst, const char *src, int dstsize) { 442line_fullname(char *dst, const char *src, int dstsize)
443{
400 memset(dst, '\0', dstsize); 444 memset(dst, '\0', dstsize);
401 if ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5))) 445 if ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5)))
402 strlcpy(dst, src, dstsize); 446 strlcpy(dst, src, dstsize);
@@ -407,50 +451,48 @@ line_fullname(char *dst, const char *src, int dstsize) {
407 return dst; 451 return dst;
408} 452}
409 453
410/* strip the leading '/dev' if it exists, return dst */ 454
455/* line_stripname(): strip the leading '/dev' if it exists, return dst */
411char * 456char *
412line_stripname(char *dst, const char *src, int dstsize) { 457line_stripname(char *dst, const char *src, int dstsize)
458{
413 memset(dst, '\0', dstsize); 459 memset(dst, '\0', dstsize);
414 if (strncmp(src, "/dev/", 5) == 0) 460 if (strncmp(src, "/dev/", 5) == 0)
415 strlcpy(dst, &src[5], dstsize); 461 strlcpy(dst, &src[5], dstsize);
416 else 462 else
417 strlcpy(dst, src, dstsize); 463 strlcpy(dst, src, dstsize);
418 return dst; 464 return dst;
419} /* stripdev() */ 465}
466
420 467
421/* return the abbreviated (usually four-character) form * 468/* line_abbrevname(): Return the abbreviated (usually four-character)
422 * simple algorithm for making name: 469 * form of the line (Just use the last <dstsize> characters of the
423 * - first character is 'L' (arbitrary - 'lib(L)ogin' :-) ) 470 * full name.)
424 * - remaining n characters are last n characters of line 471 *
425 * This is good for up to 999 ptys, I hope that's enough... 472 * NOTE: use strncpy because we do NOT necessarily want zero
426 */ 473 * termination */
427char * 474char *
428line_abbrevname(char *dst, const char *src, int dstsize) { 475line_abbrevname(char *dst, const char *src, int dstsize) {
429 memset(dst, '\0', dstsize); 476 memset(dst, '\0', dstsize);
430 dst[0]='L'; 477 src += (strlen(src) - dstsize);
431 strlcpy(dst+1, &src[strlen(src)-(dstsize)], dstsize); 478 strncpy(dst, src, dstsize); /* note: _don't_ change this to strlcpy */
432 return dst; 479 return dst;
433} 480}
434 481
435 482
436/** 483/**
437 ** utmp utility functions 484 ** utmp utility functions
485 **
486 ** These functions manipulate struct utmp, taking system differences
487 ** into account.
438 **/ 488 **/
439 489
440#if defined(USE_UTMP) || defined (USE_WTMP) || defined (USE_LOGIN) 490#if defined(USE_UTMP) || defined (USE_WTMP) || defined (USE_LOGIN)
441 491
442#ifdef HAVE_UTMP_H
443# include <utmp.h>
444#endif
445#ifdef USE_TIMEVAL
446# include <sys/time.h>
447#else
448# include <time.h>
449#endif
450
451/* build the utmp structure */ 492/* build the utmp structure */
452void 493void
453set_utmp_time(struct logininfo *li, struct utmp *ut) { 494set_utmp_time(struct logininfo *li, struct utmp *ut)
495{
454#ifdef HAVE_TV_IN_UTMP 496#ifdef HAVE_TV_IN_UTMP
455 ut->ut_tv.tv_sec = li->tv_sec; 497 ut->ut_tv.tv_sec = li->tv_sec;
456 ut->ut_tv.tv_usec = li->tv_usec; 498 ut->ut_tv.tv_usec = li->tv_usec;
@@ -461,17 +503,18 @@ set_utmp_time(struct logininfo *li, struct utmp *ut) {
461#endif 503#endif
462} 504}
463 505
506
464void 507void
465construct_utmp(struct logininfo *li, 508construct_utmp(struct logininfo *li,
466 struct utmp *ut) { 509 struct utmp *ut)
510{
467 memset(ut, '\0', sizeof(struct utmp)); 511 memset(ut, '\0', sizeof(struct utmp));
468
469#ifdef HAVE_ID_IN_UTMP 512#ifdef HAVE_ID_IN_UTMP
470 line_abbrevname(ut->ut_id, li->line, sizeof(ut->ut_id)); 513 line_abbrevname(ut->ut_id, li->line, sizeof(ut->ut_id));
471#endif 514#endif
472 515
473#ifdef HAVE_TYPE_IN_UTMP 516#ifdef HAVE_TYPE_IN_UTMP
474 /* this is done here to keep utmp constants out of login.h */ 517 /* This is done here to keep utmp constants out of login.h */
475 switch (li->type) { 518 switch (li->type) {
476 case LTYPE_LOGIN: 519 case LTYPE_LOGIN:
477 ut->ut_type = USER_PROCESS; 520 ut->ut_type = USER_PROCESS;
@@ -492,32 +535,30 @@ construct_utmp(struct logininfo *li,
492 strlcpy(ut->ut_host, li->hostname, sizeof(ut->ut_host)); 535 strlcpy(ut->ut_host, li->hostname, sizeof(ut->ut_host));
493#endif 536#endif
494#ifdef HAVE_ADDR_IN_UTMP 537#ifdef HAVE_ADDR_IN_UTMP
495 /* !!! not supported yet (can't see its big use either) */ 538 /* this is just a 32-bit IP address */
496#endif 539 if (li->hostaddr.sa.sa_family == AF_INET)
497 540 ut->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
498} /* construct_utmp() */ 541#endif
542}
499 543
500#endif 544#endif
501/* USE_UTMP || USE_WTMP || USE_LOGIN */ 545/* USE_UTMP || USE_WTMP || USE_LOGIN */
502 546
547
548
503/** 549/**
504 ** utmpx utility functions 550 ** utmpx utility functions
551 **
552 ** These functions manipulate struct utmpx, accounting for system
553 ** variations.
505 **/ 554 **/
506 555
507#if defined(USE_UTMPX) || defined (USE_WTMPX) 556#if defined(USE_UTMPX) || defined (USE_WTMPX)
508 557
509#ifdef HAVE_UTMPX_H
510# include <utmpx.h>
511#endif
512#ifdef USE_TIMEVAL
513# include <sys/time.h>
514#else
515# include <time.h>
516#endif
517
518/* build the utmpx structure */ 558/* build the utmpx structure */
519void 559void
520set_utmpx_time(struct logininfo *li, struct utmpx *utx) { 560set_utmpx_time(struct logininfo *li, struct utmpx *utx)
561{
521#ifdef HAVE_TV_IN_UTMPX 562#ifdef HAVE_TV_IN_UTMPX
522 utx->ut_tv.tv_sec = li->tv_sec; 563 utx->ut_tv.tv_sec = li->tv_sec;
523 utx->ut_tv.tv_usec = li->tv_usec; 564 utx->ut_tv.tv_usec = li->tv_usec;
@@ -528,11 +569,11 @@ set_utmpx_time(struct logininfo *li, struct utmpx *utx) {
528#endif 569#endif
529} 570}
530 571
572
531void 573void
532construct_utmpx(struct logininfo *li, 574construct_utmpx(struct logininfo *li, struct utmpx *utx)
533 struct utmpx *utx) { 575{
534 memset(utx, '\0', sizeof(struct utmpx)); 576 memset(utx, '\0', sizeof(struct utmpx));
535
536 line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id)); 577 line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id));
537 578
538 /* this is done here to keep utmp constants out of loginrec.h */ 579 /* this is done here to keep utmp constants out of loginrec.h */
@@ -544,7 +585,6 @@ construct_utmpx(struct logininfo *li,
544 utx->ut_type = DEAD_PROCESS; 585 utx->ut_type = DEAD_PROCESS;
545 break; 586 break;
546 } 587 }
547
548 utx->ut_pid = li->pid; 588 utx->ut_pid = li->pid;
549 line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line)); 589 line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line));
550 strlcpy(utx->ut_name, li->username, sizeof(utx->ut_name)); 590 strlcpy(utx->ut_name, li->username, sizeof(utx->ut_name));
@@ -553,13 +593,13 @@ construct_utmpx(struct logininfo *li,
553 strlcpy(utx->ut_host, li->hostname, sizeof(utx->ut_host)); 593 strlcpy(utx->ut_host, li->hostname, sizeof(utx->ut_host));
554#endif 594#endif
555#ifdef HAVE_ADDR_IN_UTMPX 595#ifdef HAVE_ADDR_IN_UTMPX
556 /* !!! not supported yet (some issues with types of addresses) */ 596 /* FIXME: (ATL) not supported yet */
557#endif 597#endif
558#ifdef HAVE_SYSLEN_IN_UTMPX 598#ifdef HAVE_SYSLEN_IN_UTMPX
559 /* this is safe because of the extra nulls in logininfo */ 599 /* this is safe because of the extra nulls in logininfo */
560 utx->ut_syslen = strlen(li->hostname); 600 utx->ut_syslen = strlen(li->hostname);
561#endif 601#endif
562} /* construct_utmpx() */ 602}
563 603
564#endif 604#endif
565/* USE_UTMPX || USE_WTMPX */ 605/* USE_UTMPX || USE_WTMPX */
@@ -567,15 +607,13 @@ construct_utmpx(struct logininfo *li,
567 607
568 608
569/** 609/**
570 ** utmp functions 610 ** Low-level utmp functions
571 **/ 611 **/
572 612
573/* FIXME: (ATL) utmp_write_direct needs testing */ 613/* FIXME: (ATL) utmp_write_direct needs testing */
574 614
575#ifdef USE_UTMP 615#ifdef USE_UTMP
576 616
577#include <utmp.h>
578
579/* if we can, use pututline() etc. */ 617/* if we can, use pututline() etc. */
580#if !defined(DISABLE_PUTUTLINE) && defined(HAVE_SETUTENT) && \ 618#if !defined(DISABLE_PUTUTLINE) && defined(HAVE_SETUTENT) && \
581 defined(HAVE_PUTUTLINE) 619 defined(HAVE_PUTUTLINE)
@@ -586,8 +624,8 @@ construct_utmpx(struct logininfo *li,
586/* write a utmp entry with the system's help (pututline() and pals) */ 624/* write a utmp entry with the system's help (pututline() and pals) */
587#ifdef UTMP_USE_LIBRARY 625#ifdef UTMP_USE_LIBRARY
588static int 626static int
589utmp_write_library(struct logininfo *li, struct utmp *ut) { 627utmp_write_library(struct logininfo *li, struct utmp *ut)
590 628{
591 setutent(); 629 setutent();
592 pututline(ut); 630 pututline(ut);
593 631
@@ -595,15 +633,15 @@ utmp_write_library(struct logininfo *li, struct utmp *ut) {
595 endutent(); 633 endutent();
596#endif 634#endif
597 return 1; 635 return 1;
598} /* utmp_write_library() */ 636}
599 637
600#else 638#else
601 639
602/* write a utmp entry direct to the file */ 640/* write a utmp entry direct to the file */
603/* This code is a slightly modification of code in OpenBSD's login.c 641/* This is a slightly modification of code in OpenBSD's login.c */
604 * (in libutil) and so is subject to the OpenBSD Licensing terms. */
605static int 642static int
606utmp_write_direct(struct logininfo *li, struct utmp *ut) { 643utmp_write_direct(struct logininfo *li, struct utmp *ut)
644{
607 struct utmp old_ut; 645 struct utmp old_ut;
608 register int fd; 646 register int fd;
609 int tty; 647 int tty;
@@ -633,17 +671,16 @@ utmp_write_direct(struct logininfo *li, struct utmp *ut) {
633 return 1; 671 return 1;
634 } else 672 } else
635 return 0; 673 return 0;
636} /* utmp_write_direct() */ 674}
637
638#endif /* UTMP_USE_LIBRARY */ 675#endif /* UTMP_USE_LIBRARY */
639 676
640 677
641static int 678static int
642utmp_perform_login(struct logininfo *li) { 679utmp_perform_login(struct logininfo *li)
680{
643 struct utmp ut; 681 struct utmp ut;
644 682
645 construct_utmp(li, &ut); 683 construct_utmp(li, &ut);
646
647#ifdef UTMP_USE_LIBRARY 684#ifdef UTMP_USE_LIBRARY
648 if (!utmp_write_library(li, &ut)) { 685 if (!utmp_write_library(li, &ut)) {
649 log("utmp_perform_login: utmp_write_library() failed"); 686 log("utmp_perform_login: utmp_write_library() failed");
@@ -656,11 +693,12 @@ utmp_perform_login(struct logininfo *li) {
656 } 693 }
657#endif 694#endif
658 return 1; 695 return 1;
659} /* utmp_perform_login() */ 696}
660 697
661 698
662static int 699static int
663utmp_perform_logout(struct logininfo *li) { 700utmp_perform_logout(struct logininfo *li)
701{
664 struct utmp ut; 702 struct utmp ut;
665 703
666 memset(&ut, '\0', sizeof(ut)); 704 memset(&ut, '\0', sizeof(ut));
@@ -681,12 +719,12 @@ utmp_perform_logout(struct logininfo *li) {
681#endif 719#endif
682 720
683 return 1; 721 return 1;
684} /* utmp_perform_logout() */ 722}
685 723
686 724
687int 725int
688utmp_write_entry(struct logininfo *li) { 726utmp_write_entry(struct logininfo *li)
689 727{
690 switch(li->type) { 728 switch(li->type) {
691 case LTYPE_LOGIN: 729 case LTYPE_LOGIN:
692 return utmp_perform_login(li); 730 return utmp_perform_login(li);
@@ -698,7 +736,7 @@ utmp_write_entry(struct logininfo *li) {
698 log("utmp_write_entry: invalid type field"); 736 log("utmp_write_entry: invalid type field");
699 return 0; 737 return 0;
700 } 738 }
701} /* utmp_write_entry() */ 739}
702 740
703 741
704#endif 742#endif
@@ -706,14 +744,12 @@ utmp_write_entry(struct logininfo *li) {
706 744
707 745
708/** 746/**
709 ** utmpx functions 747 ** Low-level utmpx functions
710 **/ 748 **/
711 749
712/* not much point if we don't want utmpx entries */ 750/* not much point if we don't want utmpx entries */
713#ifdef USE_UTMPX 751#ifdef USE_UTMPX
714 752
715#include <utmpx.h>
716
717/* if we have the wherewithall, use pututxline etc. */ 753/* if we have the wherewithall, use pututxline etc. */
718#if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) \ 754#if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) \
719 && defined(HAVE_PUTUTXLINE) 755 && defined(HAVE_PUTUTXLINE)
@@ -724,8 +760,8 @@ utmp_write_entry(struct logininfo *li) {
724/* write a utmpx entry with the system's help (pututxline() and pals) */ 760/* write a utmpx entry with the system's help (pututxline() and pals) */
725#ifdef UTMPX_USE_LIBRARY 761#ifdef UTMPX_USE_LIBRARY
726static int 762static int
727utmpx_write_library(struct logininfo *li, struct utmpx *utx) { 763utmpx_write_library(struct logininfo *li, struct utmpx *utx)
728 764{
729 setutxent(); 765 setutxent();
730 pututxline(utx); 766 pututxline(utx);
731 767
@@ -733,7 +769,7 @@ utmpx_write_library(struct logininfo *li, struct utmpx *utx) {
733 endutxent(); 769 endutxent();
734#endif 770#endif
735 return 1; 771 return 1;
736} /* utmpx_write_library() */ 772}
737 773
738#else 774#else
739/* UTMPX_USE_LIBRARY */ 775/* UTMPX_USE_LIBRARY */
@@ -741,21 +777,21 @@ utmpx_write_library(struct logininfo *li, struct utmpx *utx) {
741 777
742/* write a utmp entry direct to the file */ 778/* write a utmp entry direct to the file */
743static int 779static int
744utmpx_write_direct(struct logininfo *li, struct utmpx *utx) { 780utmpx_write_direct(struct logininfo *li, struct utmpx *utx)
745 781{
746 log("utmpx_write_direct: not implemented!"); 782 log("utmpx_write_direct: not implemented!");
747 return 0; 783 return 0;
748 } /* utmpx_write_direct() */ 784}
749 785
750#endif 786#endif
751/* UTMPX_USE_LIBRARY */ 787/* UTMPX_USE_LIBRARY */
752 788
753static int 789static int
754utmpx_perform_login(struct logininfo *li) { 790utmpx_perform_login(struct logininfo *li)
791{
755 struct utmpx utx; 792 struct utmpx utx;
756 793
757 construct_utmpx(li, &utx); 794 construct_utmpx(li, &utx);
758
759#ifdef UTMPX_USE_LIBRARY 795#ifdef UTMPX_USE_LIBRARY
760 if (!utmpx_write_library(li, &utx)) { 796 if (!utmpx_write_library(li, &utx)) {
761 log("utmpx_perform_login: utmp_write_library() failed"); 797 log("utmpx_perform_login: utmp_write_library() failed");
@@ -768,11 +804,12 @@ utmpx_perform_login(struct logininfo *li) {
768 } 804 }
769#endif 805#endif
770 return 1; 806 return 1;
771} /* utmpx_perform_login() */ 807}
772 808
773 809
774static int 810static int
775utmpx_perform_logout(struct logininfo *li) { 811utmpx_perform_logout(struct logininfo *li)
812{
776 struct utmpx utx; 813 struct utmpx utx;
777 814
778 memset(&utx, '\0', sizeof(utx)); 815 memset(&utx, '\0', sizeof(utx));
@@ -790,14 +827,13 @@ utmpx_perform_logout(struct logininfo *li) {
790#else 827#else
791 utmpx_write_direct(li, &utx); 828 utmpx_write_direct(li, &utx);
792#endif 829#endif
793
794 return 1; 830 return 1;
795} /* utmpx_perform_logout() */ 831}
796 832
797 833
798int 834int
799utmpx_write_entry(struct logininfo *li) { 835utmpx_write_entry(struct logininfo *li)
800 836{
801 switch(li->type) { 837 switch(li->type) {
802 case LTYPE_LOGIN: 838 case LTYPE_LOGIN:
803 return utmpx_perform_login(li); 839 return utmpx_perform_login(li);
@@ -807,7 +843,7 @@ utmpx_write_entry(struct logininfo *li) {
807 log("utmpx_write_entry: invalid type field"); 843 log("utmpx_write_entry: invalid type field");
808 return 0; 844 return 0;
809 } 845 }
810} /* utmpx_write_entry() */ 846}
811 847
812 848
813#endif 849#endif
@@ -815,18 +851,16 @@ utmpx_write_entry(struct logininfo *li) {
815 851
816 852
817/** 853/**
818 ** wtmp functions 854 ** Low-level wtmp functions
819 **/ 855 **/
820 856
821#ifdef USE_WTMP 857#ifdef USE_WTMP
822 858
823# include <utmp.h>
824
825/* write a wtmp entry direct to the end of the file */ 859/* write a wtmp entry direct to the end of the file */
826/* This code is a slight modification of code in OpenBSD's logwtmp.c 860/* This is a slight modification of code in OpenBSD's logwtmp.c */
827 * (in libutil) and so is subject to the OpenBSD licensing terms */
828static int 861static int
829wtmp_write(struct logininfo *li, struct utmp *ut) { 862wtmp_write(struct logininfo *li, struct utmp *ut)
863{
830 struct stat buf; 864 struct stat buf;
831 int fd, ret = 1; 865 int fd, ret = 1;
832 866
@@ -835,8 +869,7 @@ wtmp_write(struct logininfo *li, struct utmp *ut) {
835 WTMP_FILE, strerror(errno)); 869 WTMP_FILE, strerror(errno));
836 return 0; 870 return 0;
837 } 871 }
838 872 if (fstat(fd, &buf) == 0)
839 if (fstat(fd, &buf) == 0)
840 if (write(fd, (char *)ut, sizeof(struct utmp)) != 873 if (write(fd, (char *)ut, sizeof(struct utmp)) !=
841 sizeof(struct utmp)) { 874 sizeof(struct utmp)) {
842 ftruncate(fd, buf.st_size); 875 ftruncate(fd, buf.st_size);
@@ -845,23 +878,22 @@ wtmp_write(struct logininfo *li, struct utmp *ut) {
845 ret = 0; 878 ret = 0;
846 } 879 }
847 (void)close(fd); 880 (void)close(fd);
848
849 return ret; 881 return ret;
850} /* wtmp_write() */ 882}
851
852 883
853 884
854static int 885static int
855wtmp_perform_login(struct logininfo *li) { 886wtmp_perform_login(struct logininfo *li){
856 struct utmp ut; 887 struct utmp ut;
857 888
858 construct_utmp(li, &ut); 889 construct_utmp(li, &ut);
859 return wtmp_write(li, &ut); 890 return wtmp_write(li, &ut);
860} /* wtmp_perform_login() */ 891}
861 892
862 893
863static int 894static int
864wtmp_perform_logout(struct logininfo *li) { 895wtmp_perform_logout(struct logininfo *li)
896{
865 struct utmp ut; 897 struct utmp ut;
866 898
867 construct_utmp(li, &ut); 899 construct_utmp(li, &ut);
@@ -877,12 +909,12 @@ wtmp_perform_logout(struct logininfo *li) {
877 memset(&(ut.ut_addr), '\0', sizeof(ut.ut_addr)); 909 memset(&(ut.ut_addr), '\0', sizeof(ut.ut_addr));
878#endif 910#endif
879 return wtmp_write(li, &ut); 911 return wtmp_write(li, &ut);
880} /* wtmp_perform_logout() */ 912}
881 913
882 914
883int 915int
884wtmp_write_entry(struct logininfo *li) { 916wtmp_write_entry(struct logininfo *li)
885 917{
886 switch(li->type) { 918 switch(li->type) {
887 case LTYPE_LOGIN: 919 case LTYPE_LOGIN:
888 return wtmp_perform_login(li); 920 return wtmp_perform_login(li);
@@ -892,12 +924,12 @@ wtmp_write_entry(struct logininfo *li) {
892 log("wtmp_write_entry: invalid type field"); 924 log("wtmp_write_entry: invalid type field");
893 return 0; 925 return 0;
894 } 926 }
895} /* wtmp_write_entry() */ 927}
896
897 928
898 929
899int 930int
900wtmp_get_entry(struct logininfo *li) { 931wtmp_get_entry(struct logininfo *li)
932{
901 struct stat st; 933 struct stat st;
902 struct utmp ut; 934 struct utmp ut;
903 int fd; 935 int fd;
@@ -907,14 +939,12 @@ wtmp_get_entry(struct logininfo *li) {
907 WTMP_FILE, strerror(errno)); 939 WTMP_FILE, strerror(errno));
908 return 0; 940 return 0;
909 } 941 }
910 942 if (fstat(fd, &st) != 0) {
911 if (fstat(fd, &st) != 0) {
912 log("wtmp_get_entry: couldn't stat %s: %s", 943 log("wtmp_get_entry: couldn't stat %s: %s",
913 WTMP_FILE, strerror(errno)); 944 WTMP_FILE, strerror(errno));
914 close(fd); 945 close(fd);
915 return 0; 946 return 0;
916 } 947 }
917
918 (void)lseek(fd, (off_t)(0-sizeof(struct utmp)), SEEK_END); 948 (void)lseek(fd, (off_t)(0-sizeof(struct utmp)), SEEK_END);
919 949
920 do { 950 do {
@@ -924,7 +954,6 @@ wtmp_get_entry(struct logininfo *li) {
924 close (fd); 954 close (fd);
925 return 0; 955 return 0;
926 } 956 }
927
928 /* Logouts are recorded as a blank username on a particular line. 957 /* Logouts are recorded as a blank username on a particular line.
929 * So, we just need to find the username in struct utmp */ 958 * So, we just need to find the username in struct utmp */
930 if ( strncmp(li->username, ut.ut_user, 8) == 0 ) { 959 if ( strncmp(li->username, ut.ut_user, 8) == 0 ) {
@@ -948,7 +977,7 @@ wtmp_get_entry(struct logininfo *li) {
948 } while (li->tv_sec == 0); 977 } while (li->tv_sec == 0);
949 978
950 return 1; 979 return 1;
951} /* wtmp_get_entry() */ 980}
952 981
953 982
954#endif 983#endif
@@ -956,18 +985,16 @@ wtmp_get_entry(struct logininfo *li) {
956 985
957 986
958/** 987/**
959 ** wtmpx functions 988 ** Low-level wtmpx functions
960 **/ 989 **/
961 990
962#ifdef USE_WTMPX 991#ifdef USE_WTMPX
963 992
964# include <utmpx.h>
965
966/* write a wtmpx entry direct to the end of the file */ 993/* write a wtmpx entry direct to the end of the file */
967/* This code is a slight modification of code in OpenBSD's logwtmp.c 994/* This is a slight modification of code in OpenBSD's logwtmp.c */
968 * (in libutil) and so is subject to the OpenBSD licensing terms */
969static int 995static int
970wtmpx_write(struct logininfo *li, struct utmpx *utx) { 996wtmpx_write(struct logininfo *li, struct utmpx *utx)
997{
971 struct stat buf; 998 struct stat buf;
972 int fd, ret = 1; 999 int fd, ret = 1;
973 1000
@@ -988,21 +1015,22 @@ wtmpx_write(struct logininfo *li, struct utmpx *utx) {
988 (void)close(fd); 1015 (void)close(fd);
989 1016
990 return ret; 1017 return ret;
991} /* wtmpx_write() */ 1018}
992
993 1019
994 1020
995static int 1021static int
996wtmpx_perform_login(struct logininfo *li) { 1022wtmpx_perform_login(struct logininfo *li)
1023{
997 struct utmpx utx; 1024 struct utmpx utx;
998 1025
999 construct_utmpx(li, &utx); 1026 construct_utmpx(li, &utx);
1000 return wtmpx_write(li, &utx); 1027 return wtmpx_write(li, &utx);
1001} /* wtmpx_perform_login() */ 1028}
1002 1029
1003 1030
1004static int 1031static int
1005wtmpx_perform_logout(struct logininfo *li) { 1032wtmpx_perform_logout(struct logininfo *li)
1033{
1006 struct utmpx utx; 1034 struct utmpx utx;
1007 1035
1008 construct_utmpx(li, &utx); 1036 construct_utmpx(li, &utx);
@@ -1019,12 +1047,12 @@ wtmpx_perform_logout(struct logininfo *li) {
1019#endif 1047#endif
1020 return wtmpx_write(li, &utx); 1048 return wtmpx_write(li, &utx);
1021 1049
1022} /* wtmpx_perform_logout() */ 1050}
1023 1051
1024 1052
1025int 1053int
1026wtmpx_write_entry(struct logininfo *li) { 1054wtmpx_write_entry(struct logininfo *li)
1027 1055{
1028 switch(li->type) { 1056 switch(li->type) {
1029 case LTYPE_LOGIN: 1057 case LTYPE_LOGIN:
1030 return wtmpx_perform_login(li); 1058 return wtmpx_perform_login(li);
@@ -1034,12 +1062,12 @@ wtmpx_write_entry(struct logininfo *li) {
1034 log("wtmpx_write_entry: invalid type field"); 1062 log("wtmpx_write_entry: invalid type field");
1035 return 0; 1063 return 0;
1036 } 1064 }
1037} /* wtmpx_write_entry() */ 1065}
1038
1039 1066
1040 1067
1041int 1068int
1042wtmpx_get_entry(struct logininfo *li) { 1069wtmpx_get_entry(struct logininfo *li)
1070{
1043 struct stat st; 1071 struct stat st;
1044 struct utmpx utx; 1072 struct utmpx utx;
1045 int fd; 1073 int fd;
@@ -1049,14 +1077,12 @@ wtmpx_get_entry(struct logininfo *li) {
1049 WTMPX_FILE, strerror(errno)); 1077 WTMPX_FILE, strerror(errno));
1050 return 0; 1078 return 0;
1051 } 1079 }
1052 1080 if (fstat(fd, &st) != 0) {
1053 if (fstat(fd, &st) != 0) {
1054 log("wtmpx_get_entry: couldn't stat %s: %s", 1081 log("wtmpx_get_entry: couldn't stat %s: %s",
1055 WTMP_FILE, strerror(errno)); 1082 WTMP_FILE, strerror(errno));
1056 close(fd); 1083 close(fd);
1057 return 0; 1084 return 0;
1058 } 1085 }
1059
1060 (void)lseek(fd, (off_t)(0-sizeof(struct utmpx)), SEEK_END); 1086 (void)lseek(fd, (off_t)(0-sizeof(struct utmpx)), SEEK_END);
1061 1087
1062 do { 1088 do {
@@ -1066,7 +1092,6 @@ wtmpx_get_entry(struct logininfo *li) {
1066 close (fd); 1092 close (fd);
1067 return 0; 1093 return 0;
1068 } 1094 }
1069
1070 /* Logouts are recorded as a blank username on a particular line. 1095 /* Logouts are recorded as a blank username on a particular line.
1071 * So, we just need to find the username in struct utmpx */ 1096 * So, we just need to find the username in struct utmpx */
1072 if ( strncmp(li->username, utx.ut_user, 8) == 0 ) { 1097 if ( strncmp(li->username, utx.ut_user, 8) == 0 ) {
@@ -1089,8 +1114,7 @@ wtmpx_get_entry(struct logininfo *li) {
1089 } 1114 }
1090 } while (li->tv_sec == 0); 1115 } while (li->tv_sec == 0);
1091 return 1; 1116 return 1;
1092} /* wtmpx_get_entry() */ 1117}
1093
1094 1118
1095 1119
1096#endif 1120#endif
@@ -1099,25 +1123,14 @@ wtmpx_get_entry(struct logininfo *li) {
1099 1123
1100 1124
1101/** 1125/**
1102 ** libutil login() functions 1126 ** Low-level libutil login() functions
1103 **/ 1127 **/
1104 1128
1105#ifdef USE_LOGIN 1129#ifdef USE_LOGIN
1106 1130
1107#ifdef HAVE_UTMP_H
1108# include <utmp.h>
1109#endif
1110#ifdef HAVE_UTIL_H
1111# include <util.h>
1112#endif
1113#ifdef USE_TIMEVAL
1114# include <sys/time.h>
1115#else
1116# include <time.h>
1117#endif
1118
1119static int 1131static int
1120syslogin_perform_login(struct logininfo *li) { 1132syslogin_perform_login(struct logininfo *li)
1133{
1121 struct utmp *ut; 1134 struct utmp *ut;
1122 1135
1123 if (! (ut = (struct utmp *)malloc(sizeof(struct utmp)))) { 1136 if (! (ut = (struct utmp *)malloc(sizeof(struct utmp)))) {
@@ -1128,11 +1141,12 @@ syslogin_perform_login(struct logininfo *li) {
1128 login(ut); 1141 login(ut);
1129 1142
1130 return 1; 1143 return 1;
1131} /* syslogin_perform_login() */ 1144}
1132 1145
1133static int
1134syslogin_perform_logout(struct logininfo *li) {
1135 1146
1147static int
1148syslogin_perform_logout(struct logininfo *li)
1149{
1136#ifdef HAVE_LOGOUT 1150#ifdef HAVE_LOGOUT
1137 char line[8]; 1151 char line[8];
1138 1152
@@ -1150,13 +1164,12 @@ syslogin_perform_logout(struct logininfo *li) {
1150 * so they should all be there, but... */ 1164 * so they should all be there, but... */
1151#endif 1165#endif
1152 return 1; 1166 return 1;
1153} /* syslogin_perform_logout() */ 1167}
1154
1155 1168
1156 1169
1157int 1170int
1158syslogin_write_entry(struct logininfo *li) { 1171syslogin_write_entry(struct logininfo *li)
1159 1172{
1160 switch (li->type) { 1173 switch (li->type) {
1161 case LTYPE_LOGIN: 1174 case LTYPE_LOGIN:
1162 return syslogin_perform_login(li); 1175 return syslogin_perform_login(li);
@@ -1166,7 +1179,7 @@ syslogin_write_entry(struct logininfo *li) {
1166 log("syslogin_write_entry: Invalid type field"); 1179 log("syslogin_write_entry: Invalid type field");
1167 return 0; 1180 return 0;
1168 } 1181 }
1169} /* utmp_write_entry() */ 1182}
1170 1183
1171 1184
1172#endif 1185#endif
@@ -1176,23 +1189,14 @@ syslogin_write_entry(struct logininfo *li) {
1176 1189
1177 1190
1178/** 1191/**
1179 ** lastlog functions 1192 ** Low-level lastlog functions
1180 **/ 1193 **/
1181 1194
1182#ifdef USE_LASTLOG 1195#ifdef USE_LASTLOG
1183 1196
1184#ifdef HAVE_LASTLOG_H
1185# include <lastlog.h>
1186#else
1187# if !defined(USE_UTMP) && !defined(USE_WTMP)
1188# include <utmp.h>
1189# endif
1190#endif
1191
1192
1193static void 1197static void
1194lastlog_construct(struct logininfo *li, 1198lastlog_construct(struct logininfo *li, struct lastlog *last)
1195 struct lastlog *last) { 1199{
1196 /* clear the structure */ 1200 /* clear the structure */
1197 memset(last, '\0', sizeof(struct lastlog)); 1201 memset(last, '\0', sizeof(struct lastlog));
1198 1202
@@ -1200,7 +1204,7 @@ lastlog_construct(struct logininfo *li,
1200 sizeof(last->ll_line)); 1204 sizeof(last->ll_line));
1201 strlcpy(last->ll_host, li->hostname, sizeof(last->ll_host)); 1205 strlcpy(last->ll_host, li->hostname, sizeof(last->ll_host));
1202 last->ll_time = li->tv_sec; 1206 last->ll_time = li->tv_sec;
1203} /* lastlog_construct() */ 1207}
1204 1208
1205 1209
1206#define LL_FILE 1 1210#define LL_FILE 1
@@ -1208,7 +1212,8 @@ lastlog_construct(struct logininfo *li,
1208#define LL_OTHER 3 1212#define LL_OTHER 3
1209 1213
1210static int 1214static int
1211lastlog_filetype(char *filename) { 1215lastlog_filetype(char *filename)
1216{
1212 struct stat st; 1217 struct stat st;
1213 1218
1214 if ( stat(LASTLOG_FILE, &st) != 0) { 1219 if ( stat(LASTLOG_FILE, &st) != 0) {
@@ -1216,20 +1221,19 @@ lastlog_filetype(char *filename) {
1216 LASTLOG_FILE, strerror(errno)); 1221 LASTLOG_FILE, strerror(errno));
1217 return 0; 1222 return 0;
1218 } 1223 }
1219
1220 if (S_ISDIR(st.st_mode)) 1224 if (S_ISDIR(st.st_mode))
1221 return LL_DIR; 1225 return LL_DIR;
1222 else if (S_ISREG(st.st_mode)) 1226 else if (S_ISREG(st.st_mode))
1223 return LL_FILE; 1227 return LL_FILE;
1224 else 1228 else
1225 return LL_OTHER; 1229 return LL_OTHER;
1226} /* lastlog_filetype() */ 1230}
1227 1231
1228 1232
1229/* open the file (using filemode) and seek to the login entry */ 1233/* open the file (using filemode) and seek to the login entry */
1230static int 1234static int
1231lastlog_openseek(struct logininfo *li, int *fd, int filemode) { 1235lastlog_openseek(struct logininfo *li, int *fd, int filemode)
1232 1236{
1233 off_t offset; 1237 off_t offset;
1234 int type; 1238 int type;
1235 char lastlog_file[1024]; 1239 char lastlog_file[1024];
@@ -1255,7 +1259,6 @@ lastlog_openseek(struct logininfo *li, int *fd, int filemode) {
1255 lastlog_file, strerror(errno)); 1259 lastlog_file, strerror(errno));
1256 return 0; 1260 return 0;
1257 } 1261 }
1258
1259 /* find this uid's offset in the lastlog file */ 1262 /* find this uid's offset in the lastlog file */
1260 offset = (off_t) ( (long)li->uid * sizeof(struct lastlog)); 1263 offset = (off_t) ( (long)li->uid * sizeof(struct lastlog));
1261 1264
@@ -1265,10 +1268,11 @@ lastlog_openseek(struct logininfo *li, int *fd, int filemode) {
1265 return 0; 1268 return 0;
1266 } 1269 }
1267 return 1; 1270 return 1;
1268} /* lastlog_openseek() */ 1271}
1269 1272
1270static int 1273static int
1271lastlog_perform_login(struct logininfo *li) { 1274lastlog_perform_login(struct logininfo *li)
1275{
1272 struct lastlog last; 1276 struct lastlog last;
1273 int fd; 1277 int fd;
1274 1278
@@ -1286,12 +1290,12 @@ lastlog_perform_login(struct logininfo *li) {
1286 return 1; 1290 return 1;
1287 } else 1291 } else
1288 return 0; 1292 return 0;
1289} /* lastlog_perform_login() */ 1293}
1290 1294
1291 1295
1292int 1296int
1293lastlog_write_entry(struct logininfo *li) { 1297lastlog_write_entry(struct logininfo *li)
1294 1298{
1295 switch(li->type) { 1299 switch(li->type) {
1296 case LTYPE_LOGIN: 1300 case LTYPE_LOGIN:
1297 return lastlog_perform_login(li); 1301 return lastlog_perform_login(li);
@@ -1299,22 +1303,21 @@ lastlog_write_entry(struct logininfo *li) {
1299 log("lastlog_write_entry: Invalid type field"); 1303 log("lastlog_write_entry: Invalid type field");
1300 return 0; 1304 return 0;
1301 } 1305 }
1302} /* lastlog_write_entry() */ 1306}
1303
1304 1307
1305 1308
1306static void 1309static void
1307lastlog_populate_entry(struct logininfo *li, 1310lastlog_populate_entry(struct logininfo *li, struct lastlog *last)
1308 struct lastlog *last) { 1311{
1309 line_fullname(li->line, last->ll_line, sizeof(li->line)); 1312 line_fullname(li->line, last->ll_line, sizeof(li->line));
1310 strlcpy(li->hostname, last->ll_host, sizeof(li->hostname)); 1313 strlcpy(li->hostname, last->ll_host, sizeof(li->hostname));
1311 li->tv_sec = last->ll_time; 1314 li->tv_sec = last->ll_time;
1312} /* lastlog_populate_entry() */ 1315}
1313
1314 1316
1315 1317
1316int 1318int
1317lastlog_get_entry(struct logininfo *li) { 1319lastlog_get_entry(struct logininfo *li)
1320{
1318 struct lastlog last; 1321 struct lastlog last;
1319 int fd; 1322 int fd;
1320 1323
@@ -1328,58 +1331,10 @@ lastlog_get_entry(struct logininfo *li) {
1328 lastlog_populate_entry(li, &last); 1331 lastlog_populate_entry(li, &last);
1329 return 1; 1332 return 1;
1330 } 1333 }
1331
1332 } else 1334 } else
1333 return 0; 1335 return 0;
1334} /* lastlog_get_entry() */ 1336}
1335 1337
1336 1338
1337#endif 1339#endif
1338/* USE_LASTLOG */ 1340/* USE_LASTLOG */
1339
1340
1341/**
1342 ** lastlog retrieval functions
1343 **/
1344
1345/* take the uid in li and return the last login time */
1346int
1347getlast_entry(struct logininfo *li) {
1348
1349#ifdef USE_LASTLOG
1350 if (lastlog_get_entry(li))
1351 return 1;
1352 else
1353 return 0;
1354#else
1355 /* !USE_LASTLOG */
1356 /* Try to retrieve the last login time from another source */
1357
1358# if defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP))
1359
1360 /* retrieve last login time from utmp */
1361 if (wtmp_get_entry(li))
1362 return 1;
1363 else
1364 return 0;
1365
1366# else
1367# if defined(USE_WTMPX) && (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX))
1368
1369 /* retrieve last login time from utmpx */
1370 if (wtmpx_get_entry(li))
1371 return 1;
1372 else
1373 return 0;
1374
1375# else
1376
1377 /* no means of retrieving last login time */
1378 return 0;
1379# endif
1380# endif
1381
1382#endif
1383 /* USE_LASTLOG */
1384
1385}