diff options
Diffstat (limited to 'loginrec.c')
-rw-r--r-- | loginrec.c | 805 |
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 | ||
81 | RCSID("$Id: loginrec.c,v 1.2 2000/06/03 16:18:19 andre Exp $"); | 190 | RCSID("$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> | ||
90 | void set_utmp_time(struct logininfo *li, struct utmp *ut); | 198 | void set_utmp_time(struct logininfo *li, struct utmp *ut); |
91 | void construct_utmp(struct logininfo *li, struct utmp *ut); | 199 | void 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> | ||
96 | void set_utmpx_time(struct logininfo *li, struct utmpx *ut); | 203 | void set_utmpx_time(struct logininfo *li, struct utmpx *ut); |
97 | void construct_utmpx(struct logininfo *li, struct utmpx *ut); | 204 | void 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 */ |
118 | struct logininfo *login_alloc_entry(int pid, const char *username, | 225 | int |
119 | const char *hostname, | 226 | login_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) */ | ||
133 | void 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 */ | ||
141 | int 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 | ||
162 | void | 233 | /* Record a logout */ |
163 | login_set_progname(struct logininfo *li, const char *progname) { | 234 | int |
164 | memset(li->progname, '\0', sizeof(li->progname)); | 235 | login_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 | ||
171 | void | ||
172 | login_set_type(struct logininfo *li, int type) { | ||
173 | li->type = type; | ||
174 | } | ||
175 | 241 | ||
176 | void | 242 | /* Retrieve the last login time for a user (or fake on from wtmp/wtmpx) */ |
177 | login_set_pid(struct logininfo *li, int pid) { | 243 | unsigned int |
178 | if (!pid) | 244 | login_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 | ||
184 | void | 248 | login_get_lastlog(&li, uid); |
185 | login_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) */ | ||
253 | struct logininfo * | ||
254 | login_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 | ||
194 | void | ||
195 | login_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 | ||
203 | void | 265 | /* login_alloc_entry() - allocate and initialise a logininfo */ |
204 | login_set_username(struct logininfo *li, const char *username) { | 266 | struct |
205 | struct passwd *pw; | 267 | logininfo *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) */ | ||
219 | void | 279 | void |
220 | login_set_hostname(struct logininfo *li, const char *hostname) { | 280 | login_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 | ||
227 | void | 286 | /* login_init_entry() - initialise a struct logininfo */ |
228 | login_set_exitstatus(struct logininfo *li, | 287 | int |
229 | int exit, int termination) { | 288 | login_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) |
235 | void | 300 | strlcpy(li->username, username, sizeof(li->username)); |
236 | login_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 | ||
243 | void | 307 | void |
244 | login_set_current_time(struct logininfo *li) { | 308 | login_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 | ||
257 | void | ||
258 | login_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 */ |
265 | void | 324 | void |
266 | login_set_ip6(struct logininfo *li, | 325 | login_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 | ||
277 | int | 343 | int |
278 | login_write (struct logininfo *li) { | 344 | login_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 | ||
309 | int | ||
310 | login_login (struct logininfo *li) { | ||
311 | li->type = LTYPE_LOGIN; | ||
312 | return login_write(li); | ||
313 | } | ||
314 | 375 | ||
315 | int | 376 | /** |
316 | login_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 */ | ||
321 | int | 382 | int |
322 | login_log_entry(struct logininfo *li) { | 383 | getlast_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; | |
327 | unsigned int | ||
328 | login_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 | |||
340 | unsigned int | ||
341 | login_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 | ||
353 | struct logininfo * | 404 | # if defined(USE_WTMPX) && (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX)) |
354 | login_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 | ||
363 | struct logininfo * | 412 | /* Give up: No means of retrieving last login time */ |
364 | login_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) */ |
398 | char * | 441 | char * |
399 | line_fullname(char *dst, const char *src, int dstsize) { | 442 | line_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 */ | ||
411 | char * | 456 | char * |
412 | line_stripname(char *dst, const char *src, int dstsize) { | 457 | line_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 */ |
427 | char * | 474 | char * |
428 | line_abbrevname(char *dst, const char *src, int dstsize) { | 475 | line_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 */ |
452 | void | 493 | void |
453 | set_utmp_time(struct logininfo *li, struct utmp *ut) { | 494 | set_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 | |||
464 | void | 507 | void |
465 | construct_utmp(struct logininfo *li, | 508 | construct_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 */ |
519 | void | 559 | void |
520 | set_utmpx_time(struct logininfo *li, struct utmpx *utx) { | 560 | set_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 | |||
531 | void | 573 | void |
532 | construct_utmpx(struct logininfo *li, | 574 | construct_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 |
588 | static int | 626 | static int |
589 | utmp_write_library(struct logininfo *li, struct utmp *ut) { | 627 | utmp_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. */ | ||
605 | static int | 642 | static int |
606 | utmp_write_direct(struct logininfo *li, struct utmp *ut) { | 643 | utmp_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 | ||
641 | static int | 678 | static int |
642 | utmp_perform_login(struct logininfo *li) { | 679 | utmp_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 | ||
662 | static int | 699 | static int |
663 | utmp_perform_logout(struct logininfo *li) { | 700 | utmp_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 | ||
687 | int | 725 | int |
688 | utmp_write_entry(struct logininfo *li) { | 726 | utmp_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 |
726 | static int | 762 | static int |
727 | utmpx_write_library(struct logininfo *li, struct utmpx *utx) { | 763 | utmpx_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 */ |
743 | static int | 779 | static int |
744 | utmpx_write_direct(struct logininfo *li, struct utmpx *utx) { | 780 | utmpx_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 | ||
753 | static int | 789 | static int |
754 | utmpx_perform_login(struct logininfo *li) { | 790 | utmpx_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 | ||
774 | static int | 810 | static int |
775 | utmpx_perform_logout(struct logininfo *li) { | 811 | utmpx_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 | ||
798 | int | 834 | int |
799 | utmpx_write_entry(struct logininfo *li) { | 835 | utmpx_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 */ | ||
828 | static int | 861 | static int |
829 | wtmp_write(struct logininfo *li, struct utmp *ut) { | 862 | wtmp_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 | ||
854 | static int | 885 | static int |
855 | wtmp_perform_login(struct logininfo *li) { | 886 | wtmp_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 | ||
863 | static int | 894 | static int |
864 | wtmp_perform_logout(struct logininfo *li) { | 895 | wtmp_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 | ||
883 | int | 915 | int |
884 | wtmp_write_entry(struct logininfo *li) { | 916 | wtmp_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 | ||
899 | int | 930 | int |
900 | wtmp_get_entry(struct logininfo *li) { | 931 | wtmp_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 */ | ||
969 | static int | 995 | static int |
970 | wtmpx_write(struct logininfo *li, struct utmpx *utx) { | 996 | wtmpx_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 | ||
995 | static int | 1021 | static int |
996 | wtmpx_perform_login(struct logininfo *li) { | 1022 | wtmpx_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 | ||
1004 | static int | 1031 | static int |
1005 | wtmpx_perform_logout(struct logininfo *li) { | 1032 | wtmpx_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 | ||
1025 | int | 1053 | int |
1026 | wtmpx_write_entry(struct logininfo *li) { | 1054 | wtmpx_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 | ||
1041 | int | 1068 | int |
1042 | wtmpx_get_entry(struct logininfo *li) { | 1069 | wtmpx_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 | |||
1119 | static int | 1131 | static int |
1120 | syslogin_perform_login(struct logininfo *li) { | 1132 | syslogin_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 | ||
1133 | static int | ||
1134 | syslogin_perform_logout(struct logininfo *li) { | ||
1135 | 1146 | ||
1147 | static int | ||
1148 | syslogin_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 | ||
1157 | int | 1170 | int |
1158 | syslogin_write_entry(struct logininfo *li) { | 1171 | syslogin_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 | |||
1193 | static void | 1197 | static void |
1194 | lastlog_construct(struct logininfo *li, | 1198 | lastlog_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 | ||
1210 | static int | 1214 | static int |
1211 | lastlog_filetype(char *filename) { | 1215 | lastlog_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 */ |
1230 | static int | 1234 | static int |
1231 | lastlog_openseek(struct logininfo *li, int *fd, int filemode) { | 1235 | lastlog_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 | ||
1270 | static int | 1273 | static int |
1271 | lastlog_perform_login(struct logininfo *li) { | 1274 | lastlog_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 | ||
1292 | int | 1296 | int |
1293 | lastlog_write_entry(struct logininfo *li) { | 1297 | lastlog_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 | ||
1306 | static void | 1309 | static void |
1307 | lastlog_populate_entry(struct logininfo *li, | 1310 | lastlog_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 | ||
1316 | int | 1318 | int |
1317 | lastlog_get_entry(struct logininfo *li) { | 1319 | lastlog_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 */ | ||
1346 | int | ||
1347 | getlast_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 | } | ||