]> andersk Git - openssh.git/blob - loginrec.c
- (stevesk) [auth1.c] fix password auth for protocol 1 when
[openssh.git] / loginrec.c
1 /*
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
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Markus Friedl.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 /**
34  ** loginrec.c:  platform-independent login recording and lastlog retrieval
35  **/
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.ac 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
133 /**
134  ** TODO:
135  **   homegrown ttyslot()
136  **   test, test, test
137  **
138  ** Platform status:
139  ** ----------------
140  **
141  ** Known good:
142  **   Linux (Redhat 6.2, Debian)
143  **   Solaris
144  **   HP-UX 10.20 (gcc only)
145  **   IRIX
146  **   NeXT - M68k/HPPA/Sparc (4.2/3.3)
147  **
148  ** Testing required: Please send reports!
149  **   NetBSD
150  **   HP-UX 11
151  **   AIX
152  **
153  ** Platforms with known problems:
154  **   Some variants of Slackware Linux
155  **
156  **/
157
158 #include "includes.h"
159
160 #include "ssh.h"
161 #include "xmalloc.h"
162 #include "loginrec.h"
163 #include "log.h"
164 #include "atomicio.h"
165
166 RCSID("$Id$");
167
168 #ifdef HAVE_UTIL_H
169 #  include <util.h>
170 #endif
171
172 #ifdef HAVE_LIBUTIL_H
173 #   include <libutil.h>
174 #endif
175
176 /**
177  ** prototypes for helper functions in this file
178  **/
179
180 #if HAVE_UTMP_H
181 void set_utmp_time(struct logininfo *li, struct utmp *ut);
182 void construct_utmp(struct logininfo *li, struct utmp *ut);
183 #endif
184
185 #ifdef HAVE_UTMPX_H
186 void set_utmpx_time(struct logininfo *li, struct utmpx *ut);
187 void construct_utmpx(struct logininfo *li, struct utmpx *ut);
188 #endif
189
190 int utmp_write_entry(struct logininfo *li);
191 int utmpx_write_entry(struct logininfo *li);
192 int wtmp_write_entry(struct logininfo *li);
193 int wtmpx_write_entry(struct logininfo *li);
194 int lastlog_write_entry(struct logininfo *li);
195 int syslogin_write_entry(struct logininfo *li);
196
197 int getlast_entry(struct logininfo *li);
198 int lastlog_get_entry(struct logininfo *li);
199 int wtmp_get_entry(struct logininfo *li);
200 int wtmpx_get_entry(struct logininfo *li);
201
202 /* pick the shortest string */
203 #define MIN_SIZEOF(s1,s2) ( sizeof(s1) < sizeof(s2) ? sizeof(s1) : sizeof(s2) )
204
205 /**
206  ** platform-independent login functions
207  **/
208
209 /* login_login(struct logininfo *)     -Record a login
210  *
211  * Call with a pointer to a struct logininfo initialised with
212  * login_init_entry() or login_alloc_entry()
213  *
214  * Returns:
215  *  >0 if successful
216  *  0  on failure (will use OpenSSH's logging facilities for diagnostics)
217  */
218 int
219 login_login (struct logininfo *li)
220 {
221         li->type = LTYPE_LOGIN;
222         return login_write(li);
223 }
224
225
226 /* login_logout(struct logininfo *)     - Record a logout
227  *
228  * Call as with login_login()
229  *
230  * Returns:
231  *  >0 if successful
232  *  0  on failure (will use OpenSSH's logging facilities for diagnostics)
233  */
234 int
235 login_logout(struct logininfo *li)
236 {
237         li->type = LTYPE_LOGOUT;
238         return login_write(li);
239 }
240
241 /* login_get_lastlog_time(int)           - Retrieve the last login time
242  *
243  * Retrieve the last login time for the given uid. Will try to use the
244  * system lastlog facilities if they are available, but will fall back
245  * to looking in wtmp/wtmpx if necessary
246  *
247  * Returns:
248  *   0 on failure, or if user has never logged in
249  *   Time in seconds from the epoch if successful
250  *
251  * Useful preprocessor symbols:
252  *   DISABLE_LASTLOG: If set, *never* even try to retrieve lastlog
253  *                    info
254  *   USE_LASTLOG: If set, indicates the presence of system lastlog
255  *                facilities. If this and DISABLE_LASTLOG are not set,
256  *                try to retrieve lastlog information from wtmp/wtmpx.
257  */
258 unsigned int
259 login_get_lastlog_time(const int uid)
260 {
261         struct logininfo li;
262
263         if (login_get_lastlog(&li, uid))
264                 return li.tv_sec;
265         else
266                 return 0;
267 }
268
269 /* login_get_lastlog(struct logininfo *, int)   - Retrieve a lastlog entry
270  *
271  * Retrieve a logininfo structure populated (only partially) with
272  * information from the system lastlog data, or from wtmp/wtmpx if no
273  * system lastlog information exists.
274  *
275  * Note this routine must be given a pre-allocated logininfo.
276  *
277  * Returns:
278  *  >0: A pointer to your struct logininfo if successful
279  *  0  on failure (will use OpenSSH's logging facilities for diagnostics)
280  *
281  */
282 struct logininfo *
283 login_get_lastlog(struct logininfo *li, const int uid)
284 {
285         struct passwd *pw;
286
287         memset(li, '\0', sizeof(*li));
288         li->uid = uid;
289
290         /*
291          * If we don't have a 'real' lastlog, we need the username to
292          * reliably search wtmp(x) for the last login (see
293          * wtmp_get_entry().)
294          */
295         pw = getpwuid(uid);
296         if (pw == NULL)
297                 fatal("login_get_lastlog: Cannot find account for uid %i", uid);
298
299         /* No MIN_SIZEOF here - we absolutely *must not* truncate the
300          * username */
301         strlcpy(li->username, pw->pw_name, sizeof(li->username));
302
303         if (getlast_entry(li))
304                 return li;
305         else
306                 return NULL;
307 }
308
309
310 /* login_alloc_entry(int, char*, char*, char*)    - Allocate and initialise
311  *                                                  a logininfo structure
312  *
313  * This function creates a new struct logininfo, a data structure
314  * meant to carry the information required to portably record login info.
315  *
316  * Returns a pointer to a newly created struct logininfo. If memory
317  * allocation fails, the program halts.
318  */
319 struct
320 logininfo *login_alloc_entry(int pid, const char *username,
321                              const char *hostname, const char *line)
322 {
323         struct logininfo *newli;
324
325         newli = (struct logininfo *) xmalloc (sizeof(*newli));
326         (void)login_init_entry(newli, pid, username, hostname, line);
327         return newli;
328 }
329
330
331 /* login_free_entry(struct logininfo *)    - free struct memory */
332 void
333 login_free_entry(struct logininfo *li)
334 {
335         xfree(li);
336 }
337
338
339 /* login_init_entry(struct logininfo *, int, char*, char*, char*)
340  *                                        - initialise a struct logininfo
341  *
342  * Populates a new struct logininfo, a data structure meant to carry
343  * the information required to portably record login info.
344  *
345  * Returns: 1
346  */
347 int
348 login_init_entry(struct logininfo *li, int pid, const char *username,
349                  const char *hostname, const char *line)
350 {
351         struct passwd *pw;
352
353         memset(li, 0, sizeof(*li));
354
355         li->pid = pid;
356
357         /* set the line information */
358         if (line)
359                 line_fullname(li->line, line, sizeof(li->line));
360
361         if (username) {
362                 strlcpy(li->username, username, sizeof(li->username));
363                 pw = getpwnam(li->username);
364                 if (pw == NULL)
365                         fatal("login_init_entry: Cannot find user \"%s\"", li->username);
366                 li->uid = pw->pw_uid;
367         }
368
369         if (hostname)
370                 strlcpy(li->hostname, hostname, sizeof(li->hostname));
371
372         return 1;
373 }
374
375 /* login_set_current_time(struct logininfo *)    - set the current time
376  *
377  * Set the current time in a logininfo structure. This function is
378  * meant to eliminate the need to deal with system dependencies for
379  * time handling.
380  */
381 void
382 login_set_current_time(struct logininfo *li)
383 {
384         struct timeval tv;
385
386         gettimeofday(&tv, NULL);
387
388         li->tv_sec = tv.tv_sec;
389         li->tv_usec = tv.tv_usec;
390 }
391
392 /* copy a sockaddr_* into our logininfo */
393 void
394 login_set_addr(struct logininfo *li, const struct sockaddr *sa,
395                const unsigned int sa_size)
396 {
397         unsigned int bufsize = sa_size;
398
399         /* make sure we don't overrun our union */
400         if (sizeof(li->hostaddr) < sa_size)
401                 bufsize = sizeof(li->hostaddr);
402
403         memcpy((void *)&(li->hostaddr.sa), (const void *)sa, bufsize);
404 }
405
406
407 /**
408  ** login_write: Call low-level recording functions based on autoconf
409  ** results
410  **/
411 int
412 login_write (struct logininfo *li)
413 {
414 #ifndef HAVE_CYGWIN
415         if ((int)geteuid() != 0) {
416           log("Attempt to write login records by non-root user (aborting)");
417           return 1;
418         }
419 #endif
420
421         /* set the timestamp */
422         login_set_current_time(li);
423 #ifdef USE_LOGIN
424         syslogin_write_entry(li);
425 #endif
426 #ifdef USE_LASTLOG
427         if (li->type == LTYPE_LOGIN) {
428                 lastlog_write_entry(li);
429         }
430 #endif
431 #ifdef USE_UTMP
432         utmp_write_entry(li);
433 #endif
434 #ifdef USE_WTMP
435         wtmp_write_entry(li);
436 #endif
437 #ifdef USE_UTMPX
438         utmpx_write_entry(li);
439 #endif
440 #ifdef USE_WTMPX
441         wtmpx_write_entry(li);
442 #endif
443         return 0;
444 }
445
446 #ifdef LOGIN_NEEDS_UTMPX
447 int
448 login_utmp_only(struct logininfo *li)
449 {
450         li->type = LTYPE_LOGIN; 
451         login_set_current_time(li);
452 # ifdef USE_UTMP
453         utmp_write_entry(li);
454 # endif
455 # ifdef USE_WTMP
456         wtmp_write_entry(li);
457 # endif
458 # ifdef USE_UTMPX
459         utmpx_write_entry(li);
460 # endif
461 # ifdef USE_WTMPX
462         wtmpx_write_entry(li);
463 # endif
464         return 0;
465 }
466 #endif
467
468 /**
469  ** getlast_entry: Call low-level functions to retrieve the last login
470  **                time.
471  **/
472
473 /* take the uid in li and return the last login time */
474 int
475 getlast_entry(struct logininfo *li)
476 {
477 #ifdef USE_LASTLOG
478         return(lastlog_get_entry(li));
479 #else /* !USE_LASTLOG */
480
481 #ifdef DISABLE_LASTLOG
482         /* On some systems we shouldn't even try to obtain last login
483          * time, e.g. AIX */
484         return 0;
485 # else /* DISABLE_LASTLOG */
486         /* Try to retrieve the last login time from wtmp */
487 #  if defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP))
488         /* retrieve last login time from utmp */
489         return (wtmp_get_entry(li));
490 #  else /* defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP)) */
491         /* If wtmp isn't available, try wtmpx */
492 #   if defined(USE_WTMPX) && (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX))
493         /* retrieve last login time from utmpx */
494         return (wtmpx_get_entry(li));
495 #   else
496         /* Give up: No means of retrieving last login time */
497         return 0;
498 #   endif /* USE_WTMPX && (HAVE_TIME_IN_UTMPX || HAVE_TV_IN_UTMPX) */
499 #  endif /* USE_WTMP && (HAVE_TIME_IN_UTMP || HAVE_TV_IN_UTMP) */
500 # endif /* DISABLE_LASTLOG */
501 #endif /* USE_LASTLOG */
502 }
503
504
505
506 /*
507  * 'line' string utility functions
508  *
509  * These functions process the 'line' string into one of three forms:
510  *
511  * 1. The full filename (including '/dev')
512  * 2. The stripped name (excluding '/dev')
513  * 3. The abbreviated name (e.g. /dev/ttyp00 -> yp00
514  *                               /dev/pts/1  -> ts/1 )
515  *
516  * Form 3 is used on some systems to identify a .tmp.? entry when
517  * attempting to remove it. Typically both addition and removal is
518  * performed by one application - say, sshd - so as long as the choice
519  * uniquely identifies a terminal it's ok.
520  */
521
522
523 /* line_fullname(): add the leading '/dev/' if it doesn't exist make
524  * sure dst has enough space, if not just copy src (ugh) */
525 char *
526 line_fullname(char *dst, const char *src, int dstsize)
527 {
528         memset(dst, '\0', dstsize);
529         if ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5))) {
530                 strlcpy(dst, src, dstsize);
531         } else {
532                 strlcpy(dst, "/dev/", dstsize);
533                 strlcat(dst, src, dstsize);
534         }
535         return dst;
536 }
537
538 /* line_stripname(): strip the leading '/dev' if it exists, return dst */
539 char *
540 line_stripname(char *dst, const char *src, int dstsize)
541 {
542         memset(dst, '\0', dstsize);
543         if (strncmp(src, "/dev/", 5) == 0)
544                 strlcpy(dst, src + 5, dstsize);
545         else
546                 strlcpy(dst, src, dstsize);
547         return dst;
548 }
549
550 /* line_abbrevname(): Return the abbreviated (usually four-character)
551  * form of the line (Just use the last <dstsize> characters of the
552  * full name.)
553  *
554  * NOTE: use strncpy because we do NOT necessarily want zero
555  * termination */
556 char *
557 line_abbrevname(char *dst, const char *src, int dstsize)
558 {
559         size_t len;
560
561         memset(dst, '\0', dstsize);
562
563         /* Always skip prefix if present */
564         if (strncmp(src, "/dev/", 5) == 0)
565                 src += 5;
566
567         len = strlen(src);
568
569         if (len > 0) {
570                 if (((int)len - dstsize) > 0)
571                         src +=  ((int)len - dstsize);
572
573                 /* note: _don't_ change this to strlcpy */
574                 strncpy(dst, src, (size_t)dstsize);
575         }
576
577         return dst;
578 }
579
580 /**
581  ** utmp utility functions
582  **
583  ** These functions manipulate struct utmp, taking system differences
584  ** into account.
585  **/
586
587 #if defined(USE_UTMP) || defined (USE_WTMP) || defined (USE_LOGIN)
588
589 /* build the utmp structure */
590 void
591 set_utmp_time(struct logininfo *li, struct utmp *ut)
592 {
593 # ifdef HAVE_TV_IN_UTMP
594         ut->ut_tv.tv_sec = li->tv_sec;
595         ut->ut_tv.tv_usec = li->tv_usec;
596 # else
597 #  ifdef HAVE_TIME_IN_UTMP
598         ut->ut_time = li->tv_sec;
599 #  endif
600 # endif
601 }
602
603 void
604 construct_utmp(struct logininfo *li,
605                     struct utmp *ut)
606 {
607         memset(ut, '\0', sizeof(*ut));
608
609         /* First fill out fields used for both logins and logouts */
610
611 # ifdef HAVE_ID_IN_UTMP
612         line_abbrevname(ut->ut_id, li->line, sizeof(ut->ut_id));
613 # endif
614
615 # ifdef HAVE_TYPE_IN_UTMP
616         /* This is done here to keep utmp constants out of struct logininfo */
617         switch (li->type) {
618         case LTYPE_LOGIN:
619                 ut->ut_type = USER_PROCESS;
620 #ifdef _CRAY
621                 cray_set_tmpdir(ut);
622 #endif
623                 break;
624         case LTYPE_LOGOUT:
625                 ut->ut_type = DEAD_PROCESS;
626 #ifdef _CRAY
627                 cray_retain_utmp(ut, li->pid);
628 #endif
629                 break;
630         }
631 # endif
632         set_utmp_time(li, ut);
633
634         line_stripname(ut->ut_line, li->line, sizeof(ut->ut_line));
635
636 # ifdef HAVE_PID_IN_UTMP
637         ut->ut_pid = li->pid;
638 # endif
639
640         /* If we're logging out, leave all other fields blank */
641         if (li->type == LTYPE_LOGOUT)
642           return;
643
644         /*
645          * These fields are only used when logging in, and are blank
646          * for logouts.
647          */
648
649         /* Use strncpy because we don't necessarily want null termination */
650         strncpy(ut->ut_name, li->username, MIN_SIZEOF(ut->ut_name, li->username));
651 # ifdef HAVE_HOST_IN_UTMP
652         strncpy(ut->ut_host, li->hostname, MIN_SIZEOF(ut->ut_host, li->hostname));
653 # endif
654 # ifdef HAVE_ADDR_IN_UTMP
655         /* this is just a 32-bit IP address */
656         if (li->hostaddr.sa.sa_family == AF_INET)
657                 ut->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
658 # endif
659 }
660 #endif /* USE_UTMP || USE_WTMP || USE_LOGIN */
661
662 /**
663  ** utmpx utility functions
664  **
665  ** These functions manipulate struct utmpx, accounting for system
666  ** variations.
667  **/
668
669 #if defined(USE_UTMPX) || defined (USE_WTMPX)
670 /* build the utmpx structure */
671 void
672 set_utmpx_time(struct logininfo *li, struct utmpx *utx)
673 {
674 # ifdef HAVE_TV_IN_UTMPX
675         utx->ut_tv.tv_sec = li->tv_sec;
676         utx->ut_tv.tv_usec = li->tv_usec;
677 # else /* HAVE_TV_IN_UTMPX */
678 #  ifdef HAVE_TIME_IN_UTMPX
679         utx->ut_time = li->tv_sec;
680 #  endif /* HAVE_TIME_IN_UTMPX */
681 # endif /* HAVE_TV_IN_UTMPX */
682 }
683
684 void
685 construct_utmpx(struct logininfo *li, struct utmpx *utx)
686 {
687         memset(utx, '\0', sizeof(*utx));
688 # ifdef HAVE_ID_IN_UTMPX
689         line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id));
690 # endif
691
692         /* this is done here to keep utmp constants out of loginrec.h */
693         switch (li->type) {
694         case LTYPE_LOGIN:
695                 utx->ut_type = USER_PROCESS;
696                 break;
697         case LTYPE_LOGOUT:
698                 utx->ut_type = DEAD_PROCESS;
699                 break;
700         }
701         line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line));
702         set_utmpx_time(li, utx);
703         utx->ut_pid = li->pid;
704         /* strncpy(): Don't necessarily want null termination */
705         strncpy(utx->ut_name, li->username, MIN_SIZEOF(utx->ut_name, li->username));
706
707         if (li->type == LTYPE_LOGOUT)
708                 return;
709
710         /*
711          * These fields are only used when logging in, and are blank
712          * for logouts.
713          */
714
715 # ifdef HAVE_HOST_IN_UTMPX
716         strncpy(utx->ut_host, li->hostname, MIN_SIZEOF(utx->ut_host, li->hostname));
717 # endif
718 # ifdef HAVE_ADDR_IN_UTMPX
719         /* this is just a 32-bit IP address */
720         if (li->hostaddr.sa.sa_family == AF_INET)
721                 utx->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
722 # endif
723 # ifdef HAVE_SYSLEN_IN_UTMPX
724         /* ut_syslen is the length of the utx_host string */
725         utx->ut_syslen = MIN(strlen(li->hostname), sizeof(utx->ut_host));
726 # endif
727 }
728 #endif /* USE_UTMPX || USE_WTMPX */
729
730 /**
731  ** Low-level utmp functions
732  **/
733
734 /* FIXME: (ATL) utmp_write_direct needs testing */
735 #ifdef USE_UTMP
736
737 /* if we can, use pututline() etc. */
738 # if !defined(DISABLE_PUTUTLINE) && defined(HAVE_SETUTENT) && \
739         defined(HAVE_PUTUTLINE)
740 #  define UTMP_USE_LIBRARY
741 # endif
742
743
744 /* write a utmp entry with the system's help (pututline() and pals) */
745 # ifdef UTMP_USE_LIBRARY
746 static int
747 utmp_write_library(struct logininfo *li, struct utmp *ut)
748 {
749         setutent();
750         pututline(ut);
751
752 #  ifdef HAVE_ENDUTENT
753         endutent();
754 #  endif
755         return 1;
756 }
757 # else /* UTMP_USE_LIBRARY */
758
759 /* write a utmp entry direct to the file */
760 /* This is a slightly modification of code in OpenBSD's login.c */
761 static int
762 utmp_write_direct(struct logininfo *li, struct utmp *ut)
763 {
764         struct utmp old_ut;
765         register int fd;
766         int tty;
767
768         /* FIXME: (ATL) ttyslot() needs local implementation */
769
770 #if defined(HAVE_GETTTYENT)
771         register struct ttyent *ty;
772
773         tty=0;
774
775         setttyent();
776         while ((struct ttyent *)0 != (ty = getttyent())) {
777                 tty++;
778                 if (!strncmp(ty->ty_name, ut->ut_line, sizeof(ut->ut_line)))
779                         break;
780         }
781         endttyent();
782
783         if((struct ttyent *)0 == ty) {
784                 log("utmp_write_entry: tty not found");
785                 return(1);
786         }
787 #else /* FIXME */
788
789         tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */
790
791 #endif /* HAVE_GETTTYENT */
792
793         if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) {
794                 (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
795                 /*
796                  * Prevent luser from zero'ing out ut_host.
797                  * If the new ut_line is empty but the old one is not
798                  * and ut_line and ut_name match, preserve the old ut_line.
799                  */
800                 if (atomicio(read, fd, &old_ut, sizeof(old_ut)) == sizeof(old_ut) &&
801                         (ut->ut_host[0] == '\0') && (old_ut.ut_host[0] != '\0') &&
802                         (strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0) &&
803                         (strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0)) {
804                         (void)memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host));
805                 }
806
807                 (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
808                 if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut))
809                         log("utmp_write_direct: error writing %s: %s",
810                             UTMP_FILE, strerror(errno));
811
812                 (void)close(fd);
813                 return 1;
814         } else {
815                 return 0;
816         }
817 }
818 # endif /* UTMP_USE_LIBRARY */
819
820 static int
821 utmp_perform_login(struct logininfo *li)
822 {
823         struct utmp ut;
824
825         construct_utmp(li, &ut);
826 # ifdef UTMP_USE_LIBRARY
827         if (!utmp_write_library(li, &ut)) {
828                 log("utmp_perform_login: utmp_write_library() failed");
829                 return 0;
830         }
831 # else
832         if (!utmp_write_direct(li, &ut)) {
833                 log("utmp_perform_login: utmp_write_direct() failed");
834                 return 0;
835         }
836 # endif
837         return 1;
838 }
839
840
841 static int
842 utmp_perform_logout(struct logininfo *li)
843 {
844         struct utmp ut;
845
846         construct_utmp(li, &ut);
847 # ifdef UTMP_USE_LIBRARY
848         if (!utmp_write_library(li, &ut)) {
849                 log("utmp_perform_logout: utmp_write_library() failed");
850                 return 0;
851         }
852 # else
853         if (!utmp_write_direct(li, &ut)) {
854                 log("utmp_perform_logout: utmp_write_direct() failed");
855                 return 0;
856         }
857 # endif
858         return 1;
859 }
860
861
862 int
863 utmp_write_entry(struct logininfo *li)
864 {
865         switch(li->type) {
866         case LTYPE_LOGIN:
867                 return utmp_perform_login(li);
868
869         case LTYPE_LOGOUT:
870                 return utmp_perform_logout(li);
871
872         default:
873                 log("utmp_write_entry: invalid type field");
874                 return 0;
875         }
876 }
877 #endif /* USE_UTMP */
878
879
880 /**
881  ** Low-level utmpx functions
882  **/
883
884 /* not much point if we don't want utmpx entries */
885 #ifdef USE_UTMPX
886
887 /* if we have the wherewithall, use pututxline etc. */
888 # if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) && \
889         defined(HAVE_PUTUTXLINE)
890 #  define UTMPX_USE_LIBRARY
891 # endif
892
893
894 /* write a utmpx entry with the system's help (pututxline() and pals) */
895 # ifdef UTMPX_USE_LIBRARY
896 static int
897 utmpx_write_library(struct logininfo *li, struct utmpx *utx)
898 {
899         setutxent();
900         pututxline(utx);
901
902 #  ifdef HAVE_ENDUTXENT
903         endutxent();
904 #  endif
905         return 1;
906 }
907
908 # else /* UTMPX_USE_LIBRARY */
909
910 /* write a utmp entry direct to the file */
911 static int
912 utmpx_write_direct(struct logininfo *li, struct utmpx *utx)
913 {
914         log("utmpx_write_direct: not implemented!");
915         return 0;
916 }
917 # endif /* UTMPX_USE_LIBRARY */
918
919 static int
920 utmpx_perform_login(struct logininfo *li)
921 {
922         struct utmpx utx;
923
924         construct_utmpx(li, &utx);
925 # ifdef UTMPX_USE_LIBRARY
926         if (!utmpx_write_library(li, &utx)) {
927                 log("utmpx_perform_login: utmp_write_library() failed");
928                 return 0;
929         }
930 # else
931         if (!utmpx_write_direct(li, &ut)) {
932                 log("utmpx_perform_login: utmp_write_direct() failed");
933                 return 0;
934         }
935 # endif
936         return 1;
937 }
938
939
940 static int
941 utmpx_perform_logout(struct logininfo *li)
942 {
943         struct utmpx utx;
944
945         construct_utmpx(li, &utx);
946 # ifdef HAVE_ID_IN_UTMPX
947         line_abbrevname(utx.ut_id, li->line, sizeof(utx.ut_id));
948 # endif
949 # ifdef HAVE_TYPE_IN_UTMPX
950         utx.ut_type = DEAD_PROCESS;
951 # endif
952
953 # ifdef UTMPX_USE_LIBRARY
954         utmpx_write_library(li, &utx);
955 # else
956         utmpx_write_direct(li, &utx);
957 # endif
958         return 1;
959 }
960
961 int
962 utmpx_write_entry(struct logininfo *li)
963 {
964         switch(li->type) {
965         case LTYPE_LOGIN:
966                 return utmpx_perform_login(li);
967         case LTYPE_LOGOUT:
968                 return utmpx_perform_logout(li);
969         default:
970                 log("utmpx_write_entry: invalid type field");
971                 return 0;
972         }
973 }
974 #endif /* USE_UTMPX */
975
976
977 /**
978  ** Low-level wtmp functions
979  **/
980
981 #ifdef USE_WTMP
982
983 /* write a wtmp entry direct to the end of the file */
984 /* This is a slight modification of code in OpenBSD's logwtmp.c */
985 static int
986 wtmp_write(struct logininfo *li, struct utmp *ut)
987 {
988         struct stat buf;
989         int fd, ret = 1;
990
991         if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
992                 log("wtmp_write: problem writing %s: %s",
993                     WTMP_FILE, strerror(errno));
994                 return 0;
995         }
996         if (fstat(fd, &buf) == 0)
997                 if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut)) {
998                         ftruncate(fd, buf.st_size);
999                         log("wtmp_write: problem writing %s: %s",
1000                             WTMP_FILE, strerror(errno));
1001                         ret = 0;
1002                 }
1003         (void)close(fd);
1004         return ret;
1005 }
1006
1007 static int
1008 wtmp_perform_login(struct logininfo *li)
1009 {
1010         struct utmp ut;
1011
1012         construct_utmp(li, &ut);
1013         return wtmp_write(li, &ut);
1014 }
1015
1016
1017 static int
1018 wtmp_perform_logout(struct logininfo *li)
1019 {
1020         struct utmp ut;
1021
1022         construct_utmp(li, &ut);
1023         return wtmp_write(li, &ut);
1024 }
1025
1026
1027 int
1028 wtmp_write_entry(struct logininfo *li)
1029 {
1030         switch(li->type) {
1031         case LTYPE_LOGIN:
1032                 return wtmp_perform_login(li);
1033         case LTYPE_LOGOUT:
1034                 return wtmp_perform_logout(li);
1035         default:
1036                 log("wtmp_write_entry: invalid type field");
1037                 return 0;
1038         }
1039 }
1040
1041
1042 /* Notes on fetching login data from wtmp/wtmpx
1043  *
1044  * Logouts are usually recorded with (amongst other things) a blank
1045  * username on a given tty line.  However, some systems (HP-UX is one)
1046  * leave all fields set, but change the ut_type field to DEAD_PROCESS.
1047  *
1048  * Since we're only looking for logins here, we know that the username
1049  * must be set correctly. On systems that leave it in, we check for
1050  * ut_type==USER_PROCESS (indicating a login.)
1051  *
1052  * Portability: Some systems may set something other than USER_PROCESS
1053  * to indicate a login process. I don't know of any as I write. Also,
1054  * it's possible that some systems may both leave the username in
1055  * place and not have ut_type.
1056  */
1057
1058 /* return true if this wtmp entry indicates a login */
1059 static int
1060 wtmp_islogin(struct logininfo *li, struct utmp *ut)
1061 {
1062         if (strncmp(li->username, ut->ut_name,
1063                 MIN_SIZEOF(li->username, ut->ut_name)) == 0) {
1064 # ifdef HAVE_TYPE_IN_UTMP
1065                 if (ut->ut_type & USER_PROCESS)
1066                         return 1;
1067 # else
1068                 return 1;
1069 # endif
1070         }
1071         return 0;
1072 }
1073
1074 int
1075 wtmp_get_entry(struct logininfo *li)
1076 {
1077         struct stat st;
1078         struct utmp ut;
1079         int fd, found=0;
1080
1081         /* Clear the time entries in our logininfo */
1082         li->tv_sec = li->tv_usec = 0;
1083
1084         if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) {
1085                 log("wtmp_get_entry: problem opening %s: %s",
1086                     WTMP_FILE, strerror(errno));
1087                 return 0;
1088         }
1089         if (fstat(fd, &st) != 0) {
1090                 log("wtmp_get_entry: couldn't stat %s: %s",
1091                     WTMP_FILE, strerror(errno));
1092                 close(fd);
1093                 return 0;
1094         }
1095
1096         /* Seek to the start of the last struct utmp */
1097         if (lseek(fd, -(off_t)sizeof(struct utmp), SEEK_END) == -1) {
1098                 /* Looks like we've got a fresh wtmp file */
1099                 close(fd);
1100                 return 0;
1101         }
1102
1103         while (!found) {
1104                 if (atomicio(read, fd, &ut, sizeof(ut)) != sizeof(ut)) {
1105                         log("wtmp_get_entry: read of %s failed: %s",
1106                             WTMP_FILE, strerror(errno));
1107                         close (fd);
1108                         return 0;
1109                 }
1110                 if ( wtmp_islogin(li, &ut) ) {
1111                         found = 1;
1112                         /* We've already checked for a time in struct
1113                          * utmp, in login_getlast(). */
1114 # ifdef HAVE_TIME_IN_UTMP
1115                         li->tv_sec = ut.ut_time;
1116 # else
1117 #  if HAVE_TV_IN_UTMP
1118                         li->tv_sec = ut.ut_tv.tv_sec;
1119 #  endif
1120 # endif
1121                         line_fullname(li->line, ut.ut_line,
1122                                       MIN_SIZEOF(li->line, ut.ut_line));
1123 # ifdef HAVE_HOST_IN_UTMP
1124                         strlcpy(li->hostname, ut.ut_host,
1125                                 MIN_SIZEOF(li->hostname, ut.ut_host));
1126 # endif
1127                         continue;
1128                 }
1129                 /* Seek back 2 x struct utmp */
1130                 if (lseek(fd, -(off_t)(2 * sizeof(struct utmp)), SEEK_CUR) == -1) {
1131                         /* We've found the start of the file, so quit */
1132                         close (fd);
1133                         return 0;
1134                 }
1135         }
1136
1137         /* We found an entry. Tidy up and return */
1138         close(fd);
1139         return 1;
1140 }
1141 # endif /* USE_WTMP */
1142
1143
1144 /**
1145  ** Low-level wtmpx functions
1146  **/
1147
1148 #ifdef USE_WTMPX
1149 /* write a wtmpx entry direct to the end of the file */
1150 /* This is a slight modification of code in OpenBSD's logwtmp.c */
1151 static int
1152 wtmpx_write(struct logininfo *li, struct utmpx *utx)
1153 {
1154         struct stat buf;
1155         int fd, ret = 1;
1156
1157         if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
1158                 log("wtmpx_write: problem opening %s: %s",
1159                     WTMPX_FILE, strerror(errno));
1160                 return 0;
1161         }
1162
1163         if (fstat(fd, &buf) == 0)
1164                 if (atomicio(write, fd, utx, sizeof(*utx)) != sizeof(*utx)) {
1165                         ftruncate(fd, buf.st_size);
1166                         log("wtmpx_write: problem writing %s: %s",
1167                             WTMPX_FILE, strerror(errno));
1168                         ret = 0;
1169                 }
1170         (void)close(fd);
1171
1172         return ret;
1173 }
1174
1175
1176 static int
1177 wtmpx_perform_login(struct logininfo *li)
1178 {
1179         struct utmpx utx;
1180
1181         construct_utmpx(li, &utx);
1182         return wtmpx_write(li, &utx);
1183 }
1184
1185
1186 static int
1187 wtmpx_perform_logout(struct logininfo *li)
1188 {
1189         struct utmpx utx;
1190
1191         construct_utmpx(li, &utx);
1192         return wtmpx_write(li, &utx);
1193 }
1194
1195
1196 int
1197 wtmpx_write_entry(struct logininfo *li)
1198 {
1199         switch(li->type) {
1200         case LTYPE_LOGIN:
1201                 return wtmpx_perform_login(li);
1202         case LTYPE_LOGOUT:
1203                 return wtmpx_perform_logout(li);
1204         default:
1205                 log("wtmpx_write_entry: invalid type field");
1206                 return 0;
1207         }
1208 }
1209
1210 /* Please see the notes above wtmp_islogin() for information about the
1211    next two functions */
1212
1213 /* Return true if this wtmpx entry indicates a login */
1214 static int
1215 wtmpx_islogin(struct logininfo *li, struct utmpx *utx)
1216 {
1217         if ( strncmp(li->username, utx->ut_name,
1218                 MIN_SIZEOF(li->username, utx->ut_name)) == 0 ) {
1219 # ifdef HAVE_TYPE_IN_UTMPX
1220                 if (utx->ut_type == USER_PROCESS)
1221                         return 1;
1222 # else
1223                 return 1;
1224 # endif
1225         }
1226         return 0;
1227 }
1228
1229
1230 int
1231 wtmpx_get_entry(struct logininfo *li)
1232 {
1233         struct stat st;
1234         struct utmpx utx;
1235         int fd, found=0;
1236
1237         /* Clear the time entries */
1238         li->tv_sec = li->tv_usec = 0;
1239
1240         if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) {
1241                 log("wtmpx_get_entry: problem opening %s: %s",
1242                     WTMPX_FILE, strerror(errno));
1243                 return 0;
1244         }
1245         if (fstat(fd, &st) != 0) {
1246                 log("wtmpx_get_entry: couldn't stat %s: %s",
1247                     WTMP_FILE, strerror(errno));
1248                 close(fd);
1249                 return 0;
1250         }
1251
1252         /* Seek to the start of the last struct utmpx */
1253         if (lseek(fd, -(off_t)sizeof(struct utmpx), SEEK_END) == -1 ) {
1254                 /* probably a newly rotated wtmpx file */
1255                 close(fd);
1256                 return 0;
1257         }
1258
1259         while (!found) {
1260                 if (atomicio(read, fd, &utx, sizeof(utx)) != sizeof(utx)) {
1261                         log("wtmpx_get_entry: read of %s failed: %s",
1262                             WTMPX_FILE, strerror(errno));
1263                         close (fd);
1264                         return 0;
1265                 }
1266                 /* Logouts are recorded as a blank username on a particular line.
1267                  * So, we just need to find the username in struct utmpx */
1268                 if ( wtmpx_islogin(li, &utx) ) {
1269 # ifdef HAVE_TV_IN_UTMPX
1270                         li->tv_sec = utx.ut_tv.tv_sec;
1271 # else
1272 #  ifdef HAVE_TIME_IN_UTMPX
1273                         li->tv_sec = utx.ut_time;
1274 #  endif
1275 # endif
1276                         line_fullname(li->line, utx.ut_line, sizeof(li->line));
1277 # ifdef HAVE_HOST_IN_UTMPX
1278                         strlcpy(li->hostname, utx.ut_host,
1279                                 MIN_SIZEOF(li->hostname, utx.ut_host));
1280 # endif
1281                         continue;
1282                 }
1283                 if (lseek(fd, -(off_t)(2 * sizeof(struct utmpx)), SEEK_CUR) == -1) {
1284                         close (fd);
1285                         return 0;
1286                 }
1287         }
1288
1289         close(fd);
1290         return 1;
1291 }
1292 #endif /* USE_WTMPX */
1293
1294 /**
1295  ** Low-level libutil login() functions
1296  **/
1297
1298 #ifdef USE_LOGIN
1299 static int
1300 syslogin_perform_login(struct logininfo *li)
1301 {
1302         struct utmp *ut;
1303
1304         if (! (ut = (struct utmp *)malloc(sizeof(*ut)))) {
1305                 log("syslogin_perform_login: couldn't malloc()");
1306                 return 0;
1307         }
1308         construct_utmp(li, ut);
1309         login(ut);
1310
1311         return 1;
1312 }
1313
1314 static int
1315 syslogin_perform_logout(struct logininfo *li)
1316 {
1317 # ifdef HAVE_LOGOUT
1318         char line[8];
1319
1320         (void)line_stripname(line, li->line, sizeof(line));
1321
1322         if (!logout(line)) {
1323                 log("syslogin_perform_logout: logout() returned an error");
1324 #  ifdef HAVE_LOGWTMP
1325         } else {
1326                 logwtmp(line, "", "");
1327 #  endif
1328         }
1329         /* FIXME: (ATL - if the need arises) What to do if we have
1330          * login, but no logout?  what if logout but no logwtmp? All
1331          * routines are in libutil so they should all be there,
1332          * but... */
1333 # endif
1334         return 1;
1335 }
1336
1337 int
1338 syslogin_write_entry(struct logininfo *li)
1339 {
1340         switch (li->type) {
1341         case LTYPE_LOGIN:
1342                 return syslogin_perform_login(li);
1343         case LTYPE_LOGOUT:
1344                 return syslogin_perform_logout(li);
1345         default:
1346                 log("syslogin_write_entry: Invalid type field");
1347                 return 0;
1348         }
1349 }
1350 #endif /* USE_LOGIN */
1351
1352 /* end of file log-syslogin.c */
1353
1354 /**
1355  ** Low-level lastlog functions
1356  **/
1357
1358 #ifdef USE_LASTLOG
1359 #define LL_FILE 1
1360 #define LL_DIR 2
1361 #define LL_OTHER 3
1362
1363 static void
1364 lastlog_construct(struct logininfo *li, struct lastlog *last)
1365 {
1366         /* clear the structure */
1367         memset(last, '\0', sizeof(*last));
1368
1369         (void)line_stripname(last->ll_line, li->line, sizeof(last->ll_line));
1370         strlcpy(last->ll_host, li->hostname,
1371                 MIN_SIZEOF(last->ll_host, li->hostname));
1372         last->ll_time = li->tv_sec;
1373 }
1374
1375 static int
1376 lastlog_filetype(char *filename)
1377 {
1378         struct stat st;
1379
1380         if (stat(LASTLOG_FILE, &st) != 0) {
1381                 log("lastlog_perform_login: Couldn't stat %s: %s", LASTLOG_FILE,
1382                         strerror(errno));
1383                 return 0;
1384         }
1385         if (S_ISDIR(st.st_mode))
1386                 return LL_DIR;
1387         else if (S_ISREG(st.st_mode))
1388                 return LL_FILE;
1389         else
1390                 return LL_OTHER;
1391 }
1392
1393
1394 /* open the file (using filemode) and seek to the login entry */
1395 static int
1396 lastlog_openseek(struct logininfo *li, int *fd, int filemode)
1397 {
1398         off_t offset;
1399         int type;
1400         char lastlog_file[1024];
1401
1402         type = lastlog_filetype(LASTLOG_FILE);
1403         switch (type) {
1404                 case LL_FILE:
1405                         strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file));
1406                         break;
1407                 case LL_DIR:
1408                         snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s",
1409                                  LASTLOG_FILE, li->username);
1410                         break;
1411                 default:
1412                         log("lastlog_openseek: %.100s is not a file or directory!",
1413                             LASTLOG_FILE);
1414                         return 0;
1415         }
1416
1417         *fd = open(lastlog_file, filemode);
1418         if ( *fd < 0) {
1419                 debug("lastlog_openseek: Couldn't open %s: %s",
1420                     lastlog_file, strerror(errno));
1421                 return 0;
1422         }
1423
1424         if (type == LL_FILE) {
1425                 /* find this uid's offset in the lastlog file */
1426                 offset = (off_t) ((long)li->uid * sizeof(struct lastlog));
1427
1428                 if ( lseek(*fd, offset, SEEK_SET) != offset ) {
1429                         log("lastlog_openseek: %s->lseek(): %s",
1430                          lastlog_file, strerror(errno));
1431                         return 0;
1432                 }
1433         }
1434
1435         return 1;
1436 }
1437
1438 static int
1439 lastlog_perform_login(struct logininfo *li)
1440 {
1441         struct lastlog last;
1442         int fd;
1443
1444         /* create our struct lastlog */
1445         lastlog_construct(li, &last);
1446
1447         if (!lastlog_openseek(li, &fd, O_RDWR|O_CREAT))
1448                 return(0);
1449
1450         /* write the entry */
1451         if (atomicio(write, fd, &last, sizeof(last)) != sizeof(last)) {
1452                 close(fd);
1453                 log("lastlog_write_filemode: Error writing to %s: %s",
1454                     LASTLOG_FILE, strerror(errno));
1455                 return 0;
1456         }
1457
1458         close(fd);
1459         return 1;
1460 }
1461
1462 int
1463 lastlog_write_entry(struct logininfo *li)
1464 {
1465         switch(li->type) {
1466         case LTYPE_LOGIN:
1467                 return lastlog_perform_login(li);
1468         default:
1469                 log("lastlog_write_entry: Invalid type field");
1470                 return 0;
1471         }
1472 }
1473
1474 static void
1475 lastlog_populate_entry(struct logininfo *li, struct lastlog *last)
1476 {
1477         line_fullname(li->line, last->ll_line, sizeof(li->line));
1478         strlcpy(li->hostname, last->ll_host,
1479                 MIN_SIZEOF(li->hostname, last->ll_host));
1480         li->tv_sec = last->ll_time;
1481 }
1482
1483 int
1484 lastlog_get_entry(struct logininfo *li)
1485 {
1486         struct lastlog last;
1487         int fd;
1488
1489         if (!lastlog_openseek(li, &fd, O_RDONLY))
1490                 return 0;
1491
1492         if (atomicio(read, fd, &last, sizeof(last)) != sizeof(last)) {
1493                 close(fd);
1494                 log("lastlog_get_entry: Error reading from %s: %s",
1495                     LASTLOG_FILE, strerror(errno));
1496                 return 0;
1497         }
1498
1499         close(fd);
1500
1501         lastlog_populate_entry(li, &last);
1502
1503         return 1;
1504 }
1505 #endif /* USE_LASTLOG */
This page took 0.151265 seconds and 5 git commands to generate.