LCOV - code coverage report
Current view: top level - openssh-6.6p1 - loginrec.c (source / functions) Hit Total Coverage
Test: lcov_coverage_final.info Lines: 0 213 0.0 %
Date: 2014-08-01 Functions: 0 23 0.0 %
Branches: 0 98 0.0 %

           Branch data     Line data    Source code
       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                 :            :  *
      16                 :            :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
      17                 :            :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      18                 :            :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      19                 :            :  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
      20                 :            :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      21                 :            :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      22                 :            :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      23                 :            :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      24                 :            :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      25                 :            :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      26                 :            :  */
      27                 :            : 
      28                 :            : /*
      29                 :            :  * The btmp logging code is derived from login.c from util-linux and is under
      30                 :            :  * the the following license:
      31                 :            :  *
      32                 :            :  * Copyright (c) 1980, 1987, 1988 The Regents of the University of California.
      33                 :            :  * All rights reserved.
      34                 :            :  *
      35                 :            :  * Redistribution and use in source and binary forms are permitted
      36                 :            :  * provided that the above copyright notice and this paragraph are
      37                 :            :  * duplicated in all such forms and that any documentation,
      38                 :            :  * advertising materials, and other materials related to such
      39                 :            :  * distribution and use acknowledge that the software was developed
      40                 :            :  * by the University of California, Berkeley.  The name of the
      41                 :            :  * University may not be used to endorse or promote products derived
      42                 :            :  * from this software without specific prior written permission.
      43                 :            :  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
      44                 :            :  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
      45                 :            :  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
      46                 :            :  */
      47                 :            : 
      48                 :            : 
      49                 :            : /**
      50                 :            :  ** loginrec.c:  platform-independent login recording and lastlog retrieval
      51                 :            :  **/
      52                 :            : 
      53                 :            : /*
      54                 :            :  *  The new login code explained
      55                 :            :  *  ============================
      56                 :            :  *
      57                 :            :  *  This code attempts to provide a common interface to login recording
      58                 :            :  *  (utmp and friends) and last login time retrieval.
      59                 :            :  *
      60                 :            :  *  Its primary means of achieving this is to use 'struct logininfo', a
      61                 :            :  *  union of all the useful fields in the various different types of
      62                 :            :  *  system login record structures one finds on UNIX variants.
      63                 :            :  *
      64                 :            :  *  We depend on autoconf to define which recording methods are to be
      65                 :            :  *  used, and which fields are contained in the relevant data structures
      66                 :            :  *  on the local system. Many C preprocessor symbols affect which code
      67                 :            :  *  gets compiled here.
      68                 :            :  *
      69                 :            :  *  The code is designed to make it easy to modify a particular
      70                 :            :  *  recording method, without affecting other methods nor requiring so
      71                 :            :  *  many nested conditional compilation blocks as were commonplace in
      72                 :            :  *  the old code.
      73                 :            :  *
      74                 :            :  *  For login recording, we try to use the local system's libraries as
      75                 :            :  *  these are clearly most likely to work correctly. For utmp systems
      76                 :            :  *  this usually means login() and logout() or setutent() etc., probably
      77                 :            :  *  in libutil, along with logwtmp() etc. On these systems, we fall back
      78                 :            :  *  to writing the files directly if we have to, though this method
      79                 :            :  *  requires very thorough testing so we do not corrupt local auditing
      80                 :            :  *  information. These files and their access methods are very system
      81                 :            :  *  specific indeed.
      82                 :            :  *
      83                 :            :  *  For utmpx systems, the corresponding library functions are
      84                 :            :  *  setutxent() etc. To the author's knowledge, all utmpx systems have
      85                 :            :  *  these library functions and so no direct write is attempted. If such
      86                 :            :  *  a system exists and needs support, direct analogues of the [uw]tmp
      87                 :            :  *  code should suffice.
      88                 :            :  *
      89                 :            :  *  Retrieving the time of last login ('lastlog') is in some ways even
      90                 :            :  *  more problemmatic than login recording. Some systems provide a
      91                 :            :  *  simple table of all users which we seek based on uid and retrieve a
      92                 :            :  *  relatively standard structure. Others record the same information in
      93                 :            :  *  a directory with a separate file, and others don't record the
      94                 :            :  *  information separately at all. For systems in the latter category,
      95                 :            :  *  we look backwards in the wtmp or wtmpx file for the last login entry
      96                 :            :  *  for our user. Naturally this is slower and on busy systems could
      97                 :            :  *  incur a significant performance penalty.
      98                 :            :  *
      99                 :            :  *  Calling the new code
     100                 :            :  *  --------------------
     101                 :            :  *
     102                 :            :  *  In OpenSSH all login recording and retrieval is performed in
     103                 :            :  *  login.c. Here you'll find working examples. Also, in the logintest.c
     104                 :            :  *  program there are more examples.
     105                 :            :  *
     106                 :            :  *  Internal handler calling method
     107                 :            :  *  -------------------------------
     108                 :            :  *
     109                 :            :  *  When a call is made to login_login() or login_logout(), both
     110                 :            :  *  routines set a struct logininfo flag defining which action (log in,
     111                 :            :  *  or log out) is to be taken. They both then call login_write(), which
     112                 :            :  *  calls whichever of the many structure-specific handlers autoconf
     113                 :            :  *  selects for the local system.
     114                 :            :  *
     115                 :            :  *  The handlers themselves handle system data structure specifics. Both
     116                 :            :  *  struct utmp and struct utmpx have utility functions (see
     117                 :            :  *  construct_utmp*()) to try to make it simpler to add extra systems
     118                 :            :  *  that introduce new features to either structure.
     119                 :            :  *
     120                 :            :  *  While it may seem terribly wasteful to replicate so much similar
     121                 :            :  *  code for each method, experience has shown that maintaining code to
     122                 :            :  *  write both struct utmp and utmpx in one function, whilst maintaining
     123                 :            :  *  support for all systems whether they have library support or not, is
     124                 :            :  *  a difficult and time-consuming task.
     125                 :            :  *
     126                 :            :  *  Lastlog support proceeds similarly. Functions login_get_lastlog()
     127                 :            :  *  (and its OpenSSH-tuned friend login_get_lastlog_time()) call
     128                 :            :  *  getlast_entry(), which tries one of three methods to find the last
     129                 :            :  *  login time. It uses local system lastlog support if it can,
     130                 :            :  *  otherwise it tries wtmp or wtmpx before giving up and returning 0,
     131                 :            :  *  meaning "tilt".
     132                 :            :  *
     133                 :            :  *  Maintenance
     134                 :            :  *  -----------
     135                 :            :  *
     136                 :            :  *  In many cases it's possible to tweak autoconf to select the correct
     137                 :            :  *  methods for a particular platform, either by improving the detection
     138                 :            :  *  code (best), or by presetting DISABLE_<method> or CONF_<method>_FILE
     139                 :            :  *  symbols for the platform.
     140                 :            :  *
     141                 :            :  *  Use logintest to check which symbols are defined before modifying
     142                 :            :  *  configure.ac and loginrec.c. (You have to build logintest yourself
     143                 :            :  *  with 'make logintest' as it's not built by default.)
     144                 :            :  *
     145                 :            :  *  Otherwise, patches to the specific method(s) are very helpful!
     146                 :            :  */
     147                 :            : 
     148                 :            : #include "includes.h"
     149                 :            : 
     150                 :            : #include <sys/types.h>
     151                 :            : #include <sys/stat.h>
     152                 :            : #include <sys/socket.h>
     153                 :            : 
     154                 :            : #include <netinet/in.h>
     155                 :            : 
     156                 :            : #include <errno.h>
     157                 :            : #include <fcntl.h>
     158                 :            : #ifdef HAVE_PATHS_H
     159                 :            : # include <paths.h>
     160                 :            : #endif
     161                 :            : #include <pwd.h>
     162                 :            : #include <stdarg.h>
     163                 :            : #include <string.h>
     164                 :            : #include <time.h>
     165                 :            : #include <unistd.h>
     166                 :            : 
     167                 :            : #include "xmalloc.h"
     168                 :            : #include "key.h"
     169                 :            : #include "hostfile.h"
     170                 :            : #include "ssh.h"
     171                 :            : #include "loginrec.h"
     172                 :            : #include "log.h"
     173                 :            : #include "atomicio.h"
     174                 :            : #include "packet.h"
     175                 :            : #include "canohost.h"
     176                 :            : #include "auth.h"
     177                 :            : #include "buffer.h"
     178                 :            : 
     179                 :            : #ifdef HAVE_UTIL_H
     180                 :            : # include <util.h>
     181                 :            : #endif
     182                 :            : 
     183                 :            : /**
     184                 :            :  ** prototypes for helper functions in this file
     185                 :            :  **/
     186                 :            : 
     187                 :            : #if HAVE_UTMP_H
     188                 :            : void set_utmp_time(struct logininfo *li, struct utmp *ut);
     189                 :            : void construct_utmp(struct logininfo *li, struct utmp *ut);
     190                 :            : #endif
     191                 :            : 
     192                 :            : #ifdef HAVE_UTMPX_H
     193                 :            : void set_utmpx_time(struct logininfo *li, struct utmpx *ut);
     194                 :            : void construct_utmpx(struct logininfo *li, struct utmpx *ut);
     195                 :            : #endif
     196                 :            : 
     197                 :            : int utmp_write_entry(struct logininfo *li);
     198                 :            : int utmpx_write_entry(struct logininfo *li);
     199                 :            : int wtmp_write_entry(struct logininfo *li);
     200                 :            : int wtmpx_write_entry(struct logininfo *li);
     201                 :            : int lastlog_write_entry(struct logininfo *li);
     202                 :            : int syslogin_write_entry(struct logininfo *li);
     203                 :            : 
     204                 :            : int getlast_entry(struct logininfo *li);
     205                 :            : int lastlog_get_entry(struct logininfo *li);
     206                 :            : int utmpx_get_entry(struct logininfo *li);
     207                 :            : int wtmp_get_entry(struct logininfo *li);
     208                 :            : int wtmpx_get_entry(struct logininfo *li);
     209                 :            : 
     210                 :            : extern Buffer loginmsg;
     211                 :            : 
     212                 :            : /* pick the shortest string */
     213                 :            : #define MIN_SIZEOF(s1,s2) (sizeof(s1) < sizeof(s2) ? sizeof(s1) : sizeof(s2))
     214                 :            : 
     215                 :            : /**
     216                 :            :  ** platform-independent login functions
     217                 :            :  **/
     218                 :            : 
     219                 :            : /*
     220                 :            :  * login_login(struct logininfo *) - Record a login
     221                 :            :  *
     222                 :            :  * Call with a pointer to a struct logininfo initialised with
     223                 :            :  * login_init_entry() or login_alloc_entry()
     224                 :            :  *
     225                 :            :  * Returns:
     226                 :            :  *  >0 if successful
     227                 :            :  *  0  on failure (will use OpenSSH's logging facilities for diagnostics)
     228                 :            :  */
     229                 :            : int
     230                 :          0 : login_login(struct logininfo *li)
     231                 :            : {
     232                 :          0 :         li->type = LTYPE_LOGIN;
     233                 :          0 :         return (login_write(li));
     234                 :            : }
     235                 :            : 
     236                 :            : 
     237                 :            : /*
     238                 :            :  * login_logout(struct logininfo *) - Record a logout
     239                 :            :  *
     240                 :            :  * Call as with login_login()
     241                 :            :  *
     242                 :            :  * Returns:
     243                 :            :  *  >0 if successful
     244                 :            :  *  0  on failure (will use OpenSSH's logging facilities for diagnostics)
     245                 :            :  */
     246                 :            : int
     247                 :          0 : login_logout(struct logininfo *li)
     248                 :            : {
     249                 :          0 :         li->type = LTYPE_LOGOUT;
     250                 :          0 :         return (login_write(li));
     251                 :            : }
     252                 :            : 
     253                 :            : /*
     254                 :            :  * login_get_lastlog_time(int) - Retrieve the last login time
     255                 :            :  *
     256                 :            :  * Retrieve the last login time for the given uid. Will try to use the
     257                 :            :  * system lastlog facilities if they are available, but will fall back
     258                 :            :  * to looking in wtmp/wtmpx if necessary
     259                 :            :  *
     260                 :            :  * Returns:
     261                 :            :  *   0 on failure, or if user has never logged in
     262                 :            :  *   Time in seconds from the epoch if successful
     263                 :            :  *
     264                 :            :  * Useful preprocessor symbols:
     265                 :            :  *   DISABLE_LASTLOG: If set, *never* even try to retrieve lastlog
     266                 :            :  *                    info
     267                 :            :  *   USE_LASTLOG: If set, indicates the presence of system lastlog
     268                 :            :  *                facilities. If this and DISABLE_LASTLOG are not set,
     269                 :            :  *                try to retrieve lastlog information from wtmp/wtmpx.
     270                 :            :  */
     271                 :            : unsigned int
     272                 :          0 : login_get_lastlog_time(const uid_t uid)
     273                 :            : {
     274                 :            :         struct logininfo li;
     275                 :            : 
     276         [ #  # ]:          0 :         if (login_get_lastlog(&li, uid))
     277                 :          0 :                 return (li.tv_sec);
     278                 :            :         else
     279                 :            :                 return (0);
     280                 :            : }
     281                 :            : 
     282                 :            : /*
     283                 :            :  * login_get_lastlog(struct logininfo *, int)   - Retrieve a lastlog entry
     284                 :            :  *
     285                 :            :  * Retrieve a logininfo structure populated (only partially) with
     286                 :            :  * information from the system lastlog data, or from wtmp/wtmpx if no
     287                 :            :  * system lastlog information exists.
     288                 :            :  *
     289                 :            :  * Note this routine must be given a pre-allocated logininfo.
     290                 :            :  *
     291                 :            :  * Returns:
     292                 :            :  *  >0: A pointer to your struct logininfo if successful
     293                 :            :  *  0  on failure (will use OpenSSH's logging facilities for diagnostics)
     294                 :            :  */
     295                 :            : struct logininfo *
     296                 :          0 : login_get_lastlog(struct logininfo *li, const uid_t uid)
     297                 :            : {
     298                 :            :         struct passwd *pw;
     299                 :            : 
     300                 :            :         memset(li, '\0', sizeof(*li));
     301                 :          0 :         li->uid = uid;
     302                 :            : 
     303                 :            :         /*
     304                 :            :          * If we don't have a 'real' lastlog, we need the username to
     305                 :            :          * reliably search wtmp(x) for the last login (see
     306                 :            :          * wtmp_get_entry().)
     307                 :            :          */
     308                 :          0 :         pw = getpwuid(uid);
     309         [ #  # ]:          0 :         if (pw == NULL)
     310                 :          0 :                 fatal("%s: Cannot find account for uid %ld", __func__,
     311                 :            :                     (long)uid);
     312                 :            : 
     313         [ #  # ]:          0 :         if (strlcpy(li->username, pw->pw_name, sizeof(li->username)) >=
     314                 :            :             sizeof(li->username)) {
     315                 :          0 :                 error("%s: username too long (%lu > max %lu)", __func__,
     316                 :          0 :                     (unsigned long)strlen(pw->pw_name),
     317                 :            :                     (unsigned long)sizeof(li->username) - 1);
     318                 :          0 :                 return NULL;
     319                 :            :         }
     320                 :            : 
     321         [ #  # ]:          0 :         if (getlast_entry(li))
     322                 :          0 :                 return (li);
     323                 :            :         else
     324                 :            :                 return (NULL);
     325                 :            : }
     326                 :            : 
     327                 :            : /*
     328                 :            :  * login_alloc_entry(int, char*, char*, char*)    - Allocate and initialise
     329                 :            :  *                                                  a logininfo structure
     330                 :            :  *
     331                 :            :  * This function creates a new struct logininfo, a data structure
     332                 :            :  * meant to carry the information required to portably record login info.
     333                 :            :  *
     334                 :            :  * Returns a pointer to a newly created struct logininfo. If memory
     335                 :            :  * allocation fails, the program halts.
     336                 :            :  */
     337                 :            : struct
     338                 :          0 : logininfo *login_alloc_entry(pid_t pid, const char *username,
     339                 :            :     const char *hostname, const char *line)
     340                 :            : {
     341                 :            :         struct logininfo *newli;
     342                 :            : 
     343                 :          0 :         newli = xmalloc(sizeof(*newli));
     344                 :          0 :         login_init_entry(newli, pid, username, hostname, line);
     345                 :          0 :         return (newli);
     346                 :            : }
     347                 :            : 
     348                 :            : 
     349                 :            : /* login_free_entry(struct logininfo *)    - free struct memory */
     350                 :            : void
     351                 :          0 : login_free_entry(struct logininfo *li)
     352                 :            : {
     353                 :          0 :         free(li);
     354                 :          0 : }
     355                 :            : 
     356                 :            : 
     357                 :            : /* login_init_entry(struct logininfo *, int, char*, char*, char*)
     358                 :            :  *                                        - initialise a struct logininfo
     359                 :            :  *
     360                 :            :  * Populates a new struct logininfo, a data structure meant to carry
     361                 :            :  * the information required to portably record login info.
     362                 :            :  *
     363                 :            :  * Returns: 1
     364                 :            :  */
     365                 :            : int
     366                 :          0 : login_init_entry(struct logininfo *li, pid_t pid, const char *username,
     367                 :            :     const char *hostname, const char *line)
     368                 :            : {
     369                 :            :         struct passwd *pw;
     370                 :            : 
     371                 :            :         memset(li, 0, sizeof(*li));
     372                 :            : 
     373                 :          0 :         li->pid = pid;
     374                 :            : 
     375                 :            :         /* set the line information */
     376         [ #  # ]:          0 :         if (line)
     377                 :          0 :                 line_fullname(li->line, line, sizeof(li->line));
     378                 :            : 
     379         [ #  # ]:          0 :         if (username) {
     380                 :          0 :                 strlcpy(li->username, username, sizeof(li->username));
     381                 :          0 :                 pw = getpwnam(li->username);
     382         [ #  # ]:          0 :                 if (pw == NULL) {
     383                 :          0 :                         fatal("%s: Cannot find user \"%s\"", __func__,
     384                 :            :                             li->username);
     385                 :            :                 }
     386                 :          0 :                 li->uid = pw->pw_uid;
     387                 :            :         }
     388                 :            : 
     389         [ #  # ]:          0 :         if (hostname)
     390                 :          0 :                 strlcpy(li->hostname, hostname, sizeof(li->hostname));
     391                 :            : 
     392                 :          0 :         return (1);
     393                 :            : }
     394                 :            : 
     395                 :            : /*
     396                 :            :  * login_set_current_time(struct logininfo *)    - set the current time
     397                 :            :  *
     398                 :            :  * Set the current time in a logininfo structure. This function is
     399                 :            :  * meant to eliminate the need to deal with system dependencies for
     400                 :            :  * time handling.
     401                 :            :  */
     402                 :            : void
     403                 :          0 : login_set_current_time(struct logininfo *li)
     404                 :            : {
     405                 :            :         struct timeval tv;
     406                 :            : 
     407                 :          0 :         gettimeofday(&tv, NULL);
     408                 :            : 
     409                 :          0 :         li->tv_sec = tv.tv_sec;
     410                 :          0 :         li->tv_usec = tv.tv_usec;
     411                 :          0 : }
     412                 :            : 
     413                 :            : /* copy a sockaddr_* into our logininfo */
     414                 :            : void
     415                 :          0 : login_set_addr(struct logininfo *li, const struct sockaddr *sa,
     416                 :            :     const unsigned int sa_size)
     417                 :            : {
     418                 :          0 :         unsigned int bufsize = sa_size;
     419                 :            : 
     420                 :            :         /* make sure we don't overrun our union */
     421         [ #  # ]:          0 :         if (sizeof(li->hostaddr) < sa_size)
     422                 :          0 :                 bufsize = sizeof(li->hostaddr);
     423                 :            : 
     424                 :          0 :         memcpy(&li->hostaddr.sa, sa, bufsize);
     425                 :          0 : }
     426                 :            : 
     427                 :            : 
     428                 :            : /**
     429                 :            :  ** login_write: Call low-level recording functions based on autoconf
     430                 :            :  ** results
     431                 :            :  **/
     432                 :            : int
     433                 :          0 : login_write(struct logininfo *li)
     434                 :            : {
     435                 :            : #ifndef HAVE_CYGWIN
     436         [ #  # ]:          0 :         if (geteuid() != 0) {
     437                 :          0 :                 logit("Attempt to write login records by non-root user (aborting)");
     438                 :          0 :                 return (1);
     439                 :            :         }
     440                 :            : #endif
     441                 :            : 
     442                 :            :         /* set the timestamp */
     443                 :            :         login_set_current_time(li);
     444                 :            : #ifdef USE_LOGIN
     445                 :          0 :         syslogin_write_entry(li);
     446                 :            : #endif
     447                 :            : #ifdef USE_LASTLOG
     448         [ #  # ]:          0 :         if (li->type == LTYPE_LOGIN)
     449                 :          0 :                 lastlog_write_entry(li);
     450                 :            : #endif
     451                 :            : #ifdef USE_UTMP
     452                 :            :         utmp_write_entry(li);
     453                 :            : #endif
     454                 :            : #ifdef USE_WTMP
     455                 :            :         wtmp_write_entry(li);
     456                 :            : #endif
     457                 :            : #ifdef USE_UTMPX
     458                 :            :         utmpx_write_entry(li);
     459                 :            : #endif
     460                 :            : #ifdef USE_WTMPX
     461                 :            :         wtmpx_write_entry(li);
     462                 :            : #endif
     463                 :            : #ifdef CUSTOM_SYS_AUTH_RECORD_LOGIN
     464                 :            :         if (li->type == LTYPE_LOGIN &&
     465                 :            :             !sys_auth_record_login(li->username,li->hostname,li->line,
     466                 :            :             &loginmsg))
     467                 :            :                 logit("Writing login record failed for %s", li->username);
     468                 :            : #endif
     469                 :            : #ifdef SSH_AUDIT_EVENTS
     470                 :            :         if (li->type == LTYPE_LOGIN)
     471                 :            :                 audit_session_open(li);
     472                 :            :         else if (li->type == LTYPE_LOGOUT)
     473                 :            :                 audit_session_close(li);
     474                 :            : #endif
     475                 :            :         return (0);
     476                 :            : }
     477                 :            : 
     478                 :            : #ifdef LOGIN_NEEDS_UTMPX
     479                 :            : int
     480                 :            : login_utmp_only(struct logininfo *li)
     481                 :            : {
     482                 :            :         li->type = LTYPE_LOGIN;
     483                 :            :         login_set_current_time(li);
     484                 :            : # ifdef USE_UTMP
     485                 :            :         utmp_write_entry(li);
     486                 :            : # endif
     487                 :            : # ifdef USE_WTMP
     488                 :            :         wtmp_write_entry(li);
     489                 :            : # endif
     490                 :            : # ifdef USE_UTMPX
     491                 :            :         utmpx_write_entry(li);
     492                 :            : # endif
     493                 :            : # ifdef USE_WTMPX
     494                 :            :         wtmpx_write_entry(li);
     495                 :            : # endif
     496                 :            :         return (0);
     497                 :            : }
     498                 :            : #endif
     499                 :            : 
     500                 :            : /**
     501                 :            :  ** getlast_entry: Call low-level functions to retrieve the last login
     502                 :            :  **                time.
     503                 :            :  **/
     504                 :            : 
     505                 :            : /* take the uid in li and return the last login time */
     506                 :            : int
     507                 :          0 : getlast_entry(struct logininfo *li)
     508                 :            : {
     509                 :            : #ifdef USE_LASTLOG
     510                 :          0 :         return(lastlog_get_entry(li));
     511                 :            : #else /* !USE_LASTLOG */
     512                 :            : #if defined(USE_UTMPX) && defined(HAVE_SETUTXDB) && \
     513                 :            :     defined(UTXDB_LASTLOGIN) && defined(HAVE_GETUTXUSER)
     514                 :            :         return (utmpx_get_entry(li));
     515                 :            : #endif
     516                 :            : 
     517                 :            : #if defined(DISABLE_LASTLOG)
     518                 :            :         /* On some systems we shouldn't even try to obtain last login
     519                 :            :          * time, e.g. AIX */
     520                 :            :         return (0);
     521                 :            : # elif defined(USE_WTMP) && \
     522                 :            :     (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP))
     523                 :            :         /* retrieve last login time from utmp */
     524                 :            :         return (wtmp_get_entry(li));
     525                 :            : # elif defined(USE_WTMPX) && \
     526                 :            :     (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX))
     527                 :            :         /* If wtmp isn't available, try wtmpx */
     528                 :            :         return (wtmpx_get_entry(li));
     529                 :            : # else
     530                 :            :         /* Give up: No means of retrieving last login time */
     531                 :            :         return (0);
     532                 :            : # endif /* DISABLE_LASTLOG */
     533                 :            : #endif /* USE_LASTLOG */
     534                 :            : }
     535                 :            : 
     536                 :            : 
     537                 :            : 
     538                 :            : /*
     539                 :            :  * 'line' string utility functions
     540                 :            :  *
     541                 :            :  * These functions process the 'line' string into one of three forms:
     542                 :            :  *
     543                 :            :  * 1. The full filename (including '/dev')
     544                 :            :  * 2. The stripped name (excluding '/dev')
     545                 :            :  * 3. The abbreviated name (e.g. /dev/ttyp00 -> yp00
     546                 :            :  *                               /dev/pts/1  -> ts/1 )
     547                 :            :  *
     548                 :            :  * Form 3 is used on some systems to identify a .tmp.? entry when
     549                 :            :  * attempting to remove it. Typically both addition and removal is
     550                 :            :  * performed by one application - say, sshd - so as long as the choice
     551                 :            :  * uniquely identifies a terminal it's ok.
     552                 :            :  */
     553                 :            : 
     554                 :            : 
     555                 :            : /*
     556                 :            :  * line_fullname(): add the leading '/dev/' if it doesn't exist make
     557                 :            :  * sure dst has enough space, if not just copy src (ugh)
     558                 :            :  */
     559                 :            : char *
     560                 :          0 : line_fullname(char *dst, const char *src, u_int dstsize)
     561                 :            : {
     562                 :          0 :         memset(dst, '\0', dstsize);
     563 [ #  # ][ #  # ]:          0 :         if ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5)))
     564                 :          0 :                 strlcpy(dst, src, dstsize);
     565                 :            :         else {
     566                 :          0 :                 strlcpy(dst, "/dev/", dstsize);
     567                 :          0 :                 strlcat(dst, src, dstsize);
     568                 :            :         }
     569                 :          0 :         return (dst);
     570                 :            : }
     571                 :            : 
     572                 :            : /* line_stripname(): strip the leading '/dev' if it exists, return dst */
     573                 :            : char *
     574                 :          0 : line_stripname(char *dst, const char *src, int dstsize)
     575                 :            : {
     576                 :          0 :         memset(dst, '\0', dstsize);
     577         [ #  # ]:          0 :         if (strncmp(src, "/dev/", 5) == 0)
     578                 :          0 :                 strlcpy(dst, src + 5, dstsize);
     579                 :            :         else
     580                 :          0 :                 strlcpy(dst, src, dstsize);
     581                 :          0 :         return (dst);
     582                 :            : }
     583                 :            : 
     584                 :            : /*
     585                 :            :  * line_abbrevname(): Return the abbreviated (usually four-character)
     586                 :            :  * form of the line (Just use the last <dstsize> characters of the
     587                 :            :  * full name.)
     588                 :            :  *
     589                 :            :  * NOTE: use strncpy because we do NOT necessarily want zero
     590                 :            :  * termination
     591                 :            :  */
     592                 :            : char *
     593                 :          0 : line_abbrevname(char *dst, const char *src, int dstsize)
     594                 :            : {
     595                 :            :         size_t len;
     596                 :            : 
     597                 :          0 :         memset(dst, '\0', dstsize);
     598                 :            : 
     599                 :            :         /* Always skip prefix if present */
     600         [ #  # ]:          0 :         if (strncmp(src, "/dev/", 5) == 0)
     601                 :          0 :                 src += 5;
     602                 :            : 
     603                 :            : #ifdef WITH_ABBREV_NO_TTY
     604                 :            :         if (strncmp(src, "tty", 3) == 0)
     605                 :            :                 src += 3;
     606                 :            : #endif
     607                 :            : 
     608                 :          0 :         len = strlen(src);
     609                 :            : 
     610         [ #  # ]:          0 :         if (len > 0) {
     611         [ #  # ]:          0 :                 if (((int)len - dstsize) > 0)
     612                 :          0 :                         src +=  ((int)len - dstsize);
     613                 :            : 
     614                 :            :                 /* note: _don't_ change this to strlcpy */
     615                 :          0 :                 strncpy(dst, src, (size_t)dstsize);
     616                 :            :         }
     617                 :            : 
     618                 :          0 :         return (dst);
     619                 :            : }
     620                 :            : 
     621                 :            : /**
     622                 :            :  ** utmp utility functions
     623                 :            :  **
     624                 :            :  ** These functions manipulate struct utmp, taking system differences
     625                 :            :  ** into account.
     626                 :            :  **/
     627                 :            : 
     628                 :            : #if defined(USE_UTMP) || defined (USE_WTMP) || defined (USE_LOGIN)
     629                 :            : 
     630                 :            : /* build the utmp structure */
     631                 :            : void
     632                 :          0 : set_utmp_time(struct logininfo *li, struct utmp *ut)
     633                 :            : {
     634                 :            : # if defined(HAVE_TV_IN_UTMP)
     635                 :          0 :         ut->ut_tv.tv_sec = li->tv_sec;
     636                 :          0 :         ut->ut_tv.tv_usec = li->tv_usec;
     637                 :            : # elif defined(HAVE_TIME_IN_UTMP)
     638                 :            :         ut->ut_time = li->tv_sec;
     639                 :            : # endif
     640                 :          0 : }
     641                 :            : 
     642                 :            : void
     643                 :          0 : construct_utmp(struct logininfo *li,
     644                 :            :                     struct utmp *ut)
     645                 :            : {
     646                 :            : # ifdef HAVE_ADDR_V6_IN_UTMP
     647                 :            :         struct sockaddr_in6 *sa6;
     648                 :            : # endif
     649                 :            : 
     650                 :            :         memset(ut, '\0', sizeof(*ut));
     651                 :            : 
     652                 :            :         /* First fill out fields used for both logins and logouts */
     653                 :            : 
     654                 :            : # ifdef HAVE_ID_IN_UTMP
     655                 :          0 :         line_abbrevname(ut->ut_id, li->line, sizeof(ut->ut_id));
     656                 :            : # endif
     657                 :            : 
     658                 :            : # ifdef HAVE_TYPE_IN_UTMP
     659                 :            :         /* This is done here to keep utmp constants out of struct logininfo */
     660      [ #  #  # ]:          0 :         switch (li->type) {
     661                 :            :         case LTYPE_LOGIN:
     662                 :          0 :                 ut->ut_type = USER_PROCESS;
     663                 :            : #ifdef _UNICOS
     664                 :            :                 cray_set_tmpdir(ut);
     665                 :            : #endif
     666                 :          0 :                 break;
     667                 :            :         case LTYPE_LOGOUT:
     668                 :          0 :                 ut->ut_type = DEAD_PROCESS;
     669                 :            : #ifdef _UNICOS
     670                 :            :                 cray_retain_utmp(ut, li->pid);
     671                 :            : #endif
     672                 :          0 :                 break;
     673                 :            :         }
     674                 :            : # endif
     675                 :            :         set_utmp_time(li, ut);
     676                 :            : 
     677                 :          0 :         line_stripname(ut->ut_line, li->line, sizeof(ut->ut_line));
     678                 :            : 
     679                 :            : # ifdef HAVE_PID_IN_UTMP
     680                 :          0 :         ut->ut_pid = li->pid;
     681                 :            : # endif
     682                 :            : 
     683                 :            :         /* If we're logging out, leave all other fields blank */
     684         [ #  # ]:          0 :         if (li->type == LTYPE_LOGOUT)
     685                 :          0 :                 return;
     686                 :            : 
     687                 :            :         /*
     688                 :            :          * These fields are only used when logging in, and are blank
     689                 :            :          * for logouts.
     690                 :            :          */
     691                 :            : 
     692                 :            :         /* Use strncpy because we don't necessarily want null termination */
     693                 :          0 :         strncpy(ut->ut_name, li->username,
     694                 :            :             MIN_SIZEOF(ut->ut_name, li->username));
     695                 :            : # ifdef HAVE_HOST_IN_UTMP
     696                 :          0 :         strncpy(ut->ut_host, li->hostname,
     697                 :            :             MIN_SIZEOF(ut->ut_host, li->hostname));
     698                 :            : # endif
     699                 :            : # ifdef HAVE_ADDR_IN_UTMP
     700                 :            :         /* this is just a 32-bit IP address */
     701         [ #  # ]:          0 :         if (li->hostaddr.sa.sa_family == AF_INET)
     702                 :          0 :                 ut->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
     703                 :            : # endif
     704                 :            : # ifdef HAVE_ADDR_V6_IN_UTMP
     705                 :            :         /* this is just a 128-bit IPv6 address */
     706         [ #  # ]:          0 :         if (li->hostaddr.sa.sa_family == AF_INET6) {
     707                 :          0 :                 sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa);
     708                 :          0 :                 memcpy(ut->ut_addr_v6, sa6->sin6_addr.s6_addr, 16);
     709 [ #  # ][ #  # ]:          0 :                 if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
         [ #  # ][ #  # ]
     710                 :          0 :                         ut->ut_addr_v6[0] = ut->ut_addr_v6[3];
     711                 :          0 :                         ut->ut_addr_v6[1] = 0;
     712                 :          0 :                         ut->ut_addr_v6[2] = 0;
     713                 :          0 :                         ut->ut_addr_v6[3] = 0;
     714                 :            :                 }
     715                 :            :         }
     716                 :            : # endif
     717                 :            : }
     718                 :            : #endif /* USE_UTMP || USE_WTMP || USE_LOGIN */
     719                 :            : 
     720                 :            : /**
     721                 :            :  ** utmpx utility functions
     722                 :            :  **
     723                 :            :  ** These functions manipulate struct utmpx, accounting for system
     724                 :            :  ** variations.
     725                 :            :  **/
     726                 :            : 
     727                 :            : #if defined(USE_UTMPX) || defined (USE_WTMPX)
     728                 :            : /* build the utmpx structure */
     729                 :            : void
     730                 :            : set_utmpx_time(struct logininfo *li, struct utmpx *utx)
     731                 :            : {
     732                 :            : # if defined(HAVE_TV_IN_UTMPX)
     733                 :            :         utx->ut_tv.tv_sec = li->tv_sec;
     734                 :            :         utx->ut_tv.tv_usec = li->tv_usec;
     735                 :            : # elif defined(HAVE_TIME_IN_UTMPX)
     736                 :            :         utx->ut_time = li->tv_sec;
     737                 :            : # endif
     738                 :            : }
     739                 :            : 
     740                 :            : void
     741                 :            : construct_utmpx(struct logininfo *li, struct utmpx *utx)
     742                 :            : {
     743                 :            : # ifdef HAVE_ADDR_V6_IN_UTMP
     744                 :            :         struct sockaddr_in6 *sa6;
     745                 :            : #  endif
     746                 :            :         memset(utx, '\0', sizeof(*utx));
     747                 :            : 
     748                 :            : # ifdef HAVE_ID_IN_UTMPX
     749                 :            :         line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id));
     750                 :            : # endif
     751                 :            : 
     752                 :            :         /* this is done here to keep utmp constants out of loginrec.h */
     753                 :            :         switch (li->type) {
     754                 :            :         case LTYPE_LOGIN:
     755                 :            :                 utx->ut_type = USER_PROCESS;
     756                 :            :                 break;
     757                 :            :         case LTYPE_LOGOUT:
     758                 :            :                 utx->ut_type = DEAD_PROCESS;
     759                 :            :                 break;
     760                 :            :         }
     761                 :            :         line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line));
     762                 :            :         set_utmpx_time(li, utx);
     763                 :            :         utx->ut_pid = li->pid;
     764                 :            : 
     765                 :            :         /* strncpy(): Don't necessarily want null termination */
     766                 :            :         strncpy(utx->ut_user, li->username,
     767                 :            :             MIN_SIZEOF(utx->ut_user, li->username));
     768                 :            : 
     769                 :            :         if (li->type == LTYPE_LOGOUT)
     770                 :            :                 return;
     771                 :            : 
     772                 :            :         /*
     773                 :            :          * These fields are only used when logging in, and are blank
     774                 :            :          * for logouts.
     775                 :            :          */
     776                 :            : 
     777                 :            : # ifdef HAVE_HOST_IN_UTMPX
     778                 :            :         strncpy(utx->ut_host, li->hostname,
     779                 :            :             MIN_SIZEOF(utx->ut_host, li->hostname));
     780                 :            : # endif
     781                 :            : # ifdef HAVE_ADDR_IN_UTMPX
     782                 :            :         /* this is just a 32-bit IP address */
     783                 :            :         if (li->hostaddr.sa.sa_family == AF_INET)
     784                 :            :                 utx->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr;
     785                 :            : # endif
     786                 :            : # ifdef HAVE_ADDR_V6_IN_UTMP
     787                 :            :         /* this is just a 128-bit IPv6 address */
     788                 :            :         if (li->hostaddr.sa.sa_family == AF_INET6) {
     789                 :            :                 sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa);
     790                 :            :                 memcpy(ut->ut_addr_v6, sa6->sin6_addr.s6_addr, 16);
     791                 :            :                 if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
     792                 :            :                         ut->ut_addr_v6[0] = ut->ut_addr_v6[3];
     793                 :            :                         ut->ut_addr_v6[1] = 0;
     794                 :            :                         ut->ut_addr_v6[2] = 0;
     795                 :            :                         ut->ut_addr_v6[3] = 0;
     796                 :            :                 }
     797                 :            :         }
     798                 :            : # endif
     799                 :            : # ifdef HAVE_SYSLEN_IN_UTMPX
     800                 :            :         /* ut_syslen is the length of the utx_host string */
     801                 :            :         utx->ut_syslen = MIN(strlen(li->hostname), sizeof(utx->ut_host));
     802                 :            : # endif
     803                 :            : }
     804                 :            : #endif /* USE_UTMPX || USE_WTMPX */
     805                 :            : 
     806                 :            : /**
     807                 :            :  ** Low-level utmp functions
     808                 :            :  **/
     809                 :            : 
     810                 :            : /* FIXME: (ATL) utmp_write_direct needs testing */
     811                 :            : #ifdef USE_UTMP
     812                 :            : 
     813                 :            : /* if we can, use pututline() etc. */
     814                 :            : # if !defined(DISABLE_PUTUTLINE) && defined(HAVE_SETUTENT) && \
     815                 :            :         defined(HAVE_PUTUTLINE)
     816                 :            : #  define UTMP_USE_LIBRARY
     817                 :            : # endif
     818                 :            : 
     819                 :            : 
     820                 :            : /* write a utmp entry with the system's help (pututline() and pals) */
     821                 :            : # ifdef UTMP_USE_LIBRARY
     822                 :            : static int
     823                 :            : utmp_write_library(struct logininfo *li, struct utmp *ut)
     824                 :            : {
     825                 :            :         setutent();
     826                 :            :         pututline(ut);
     827                 :            : #  ifdef HAVE_ENDUTENT
     828                 :            :         endutent();
     829                 :            : #  endif
     830                 :            :         return (1);
     831                 :            : }
     832                 :            : # else /* UTMP_USE_LIBRARY */
     833                 :            : 
     834                 :            : /*
     835                 :            :  * Write a utmp entry direct to the file
     836                 :            :  * This is a slightly modification of code in OpenBSD's login.c
     837                 :            :  */
     838                 :            : static int
     839                 :            : utmp_write_direct(struct logininfo *li, struct utmp *ut)
     840                 :            : {
     841                 :            :         struct utmp old_ut;
     842                 :            :         register int fd;
     843                 :            :         int tty;
     844                 :            : 
     845                 :            :         /* FIXME: (ATL) ttyslot() needs local implementation */
     846                 :            : 
     847                 :            : #if defined(HAVE_GETTTYENT)
     848                 :            :         struct ttyent *ty;
     849                 :            : 
     850                 :            :         tty=0;
     851                 :            :         setttyent();
     852                 :            :         while (NULL != (ty = getttyent())) {
     853                 :            :                 tty++;
     854                 :            :                 if (!strncmp(ty->ty_name, ut->ut_line, sizeof(ut->ut_line)))
     855                 :            :                         break;
     856                 :            :         }
     857                 :            :         endttyent();
     858                 :            : 
     859                 :            :         if (NULL == ty) {
     860                 :            :                 logit("%s: tty not found", __func__);
     861                 :            :                 return (0);
     862                 :            :         }
     863                 :            : #else /* FIXME */
     864                 :            : 
     865                 :            :         tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */
     866                 :            : 
     867                 :            : #endif /* HAVE_GETTTYENT */
     868                 :            : 
     869                 :            :         if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) {
     870                 :            :                 off_t pos, ret;
     871                 :            : 
     872                 :            :                 pos = (off_t)tty * sizeof(struct utmp);
     873                 :            :                 if ((ret = lseek(fd, pos, SEEK_SET)) == -1) {
     874                 :            :                         logit("%s: lseek: %s", __func__, strerror(errno));
     875                 :            :                         close(fd);
     876                 :            :                         return (0);
     877                 :            :                 }
     878                 :            :                 if (ret != pos) {
     879                 :            :                         logit("%s: Couldn't seek to tty %d slot in %s",
     880                 :            :                             __func__, tty, UTMP_FILE);
     881                 :            :                         close(fd);
     882                 :            :                         return (0);
     883                 :            :                 }
     884                 :            :                 /*
     885                 :            :                  * Prevent luser from zero'ing out ut_host.
     886                 :            :                  * If the new ut_line is empty but the old one is not
     887                 :            :                  * and ut_line and ut_name match, preserve the old ut_line.
     888                 :            :                  */
     889                 :            :                 if (atomicio(read, fd, &old_ut, sizeof(old_ut)) == sizeof(old_ut) &&
     890                 :            :                     (ut->ut_host[0] == '\0') && (old_ut.ut_host[0] != '\0') &&
     891                 :            :                     (strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0) &&
     892                 :            :                     (strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0))
     893                 :            :                         memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host));
     894                 :            : 
     895                 :            :                 if ((ret = lseek(fd, pos, SEEK_SET)) == -1) {
     896                 :            :                         logit("%s: lseek: %s", __func__, strerror(errno));
     897                 :            :                         close(fd);
     898                 :            :                         return (0);
     899                 :            :                 }
     900                 :            :                 if (ret != pos) {
     901                 :            :                         logit("%s: Couldn't seek to tty %d slot in %s",
     902                 :            :                             __func__, tty, UTMP_FILE);
     903                 :            :                         close(fd);
     904                 :            :                         return (0);
     905                 :            :                 }
     906                 :            :                 if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) {
     907                 :            :                         logit("%s: error writing %s: %s", __func__,
     908                 :            :                             UTMP_FILE, strerror(errno));
     909                 :            :                         close(fd);
     910                 :            :                         return (0);
     911                 :            :                 }
     912                 :            : 
     913                 :            :                 close(fd);
     914                 :            :                 return (1);
     915                 :            :         } else {
     916                 :            :                 return (0);
     917                 :            :         }
     918                 :            : }
     919                 :            : # endif /* UTMP_USE_LIBRARY */
     920                 :            : 
     921                 :            : static int
     922                 :            : utmp_perform_login(struct logininfo *li)
     923                 :            : {
     924                 :            :         struct utmp ut;
     925                 :            : 
     926                 :            :         construct_utmp(li, &ut);
     927                 :            : # ifdef UTMP_USE_LIBRARY
     928                 :            :         if (!utmp_write_library(li, &ut)) {
     929                 :            :                 logit("%s: utmp_write_library() failed", __func__);
     930                 :            :                 return (0);
     931                 :            :         }
     932                 :            : # else
     933                 :            :         if (!utmp_write_direct(li, &ut)) {
     934                 :            :                 logit("%s: utmp_write_direct() failed", __func__);
     935                 :            :                 return (0);
     936                 :            :         }
     937                 :            : # endif
     938                 :            :         return (1);
     939                 :            : }
     940                 :            : 
     941                 :            : 
     942                 :            : static int
     943                 :            : utmp_perform_logout(struct logininfo *li)
     944                 :            : {
     945                 :            :         struct utmp ut;
     946                 :            : 
     947                 :            :         construct_utmp(li, &ut);
     948                 :            : # ifdef UTMP_USE_LIBRARY
     949                 :            :         if (!utmp_write_library(li, &ut)) {
     950                 :            :                 logit("%s: utmp_write_library() failed", __func__);
     951                 :            :                 return (0);
     952                 :            :         }
     953                 :            : # else
     954                 :            :         if (!utmp_write_direct(li, &ut)) {
     955                 :            :                 logit("%s: utmp_write_direct() failed", __func__);
     956                 :            :                 return (0);
     957                 :            :         }
     958                 :            : # endif
     959                 :            :         return (1);
     960                 :            : }
     961                 :            : 
     962                 :            : 
     963                 :            : int
     964                 :            : utmp_write_entry(struct logininfo *li)
     965                 :            : {
     966                 :            :         switch(li->type) {
     967                 :            :         case LTYPE_LOGIN:
     968                 :            :                 return (utmp_perform_login(li));
     969                 :            : 
     970                 :            :         case LTYPE_LOGOUT:
     971                 :            :                 return (utmp_perform_logout(li));
     972                 :            : 
     973                 :            :         default:
     974                 :            :                 logit("%s: invalid type field", __func__);
     975                 :            :                 return (0);
     976                 :            :         }
     977                 :            : }
     978                 :            : #endif /* USE_UTMP */
     979                 :            : 
     980                 :            : 
     981                 :            : /**
     982                 :            :  ** Low-level utmpx functions
     983                 :            :  **/
     984                 :            : 
     985                 :            : /* not much point if we don't want utmpx entries */
     986                 :            : #ifdef USE_UTMPX
     987                 :            : 
     988                 :            : /* if we have the wherewithall, use pututxline etc. */
     989                 :            : # if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) && \
     990                 :            :         defined(HAVE_PUTUTXLINE)
     991                 :            : #  define UTMPX_USE_LIBRARY
     992                 :            : # endif
     993                 :            : 
     994                 :            : 
     995                 :            : /* write a utmpx entry with the system's help (pututxline() and pals) */
     996                 :            : # ifdef UTMPX_USE_LIBRARY
     997                 :            : static int
     998                 :            : utmpx_write_library(struct logininfo *li, struct utmpx *utx)
     999                 :            : {
    1000                 :            :         setutxent();
    1001                 :            :         pututxline(utx);
    1002                 :            : 
    1003                 :            : #  ifdef HAVE_ENDUTXENT
    1004                 :            :         endutxent();
    1005                 :            : #  endif
    1006                 :            :         return (1);
    1007                 :            : }
    1008                 :            : 
    1009                 :            : # else /* UTMPX_USE_LIBRARY */
    1010                 :            : 
    1011                 :            : /* write a utmp entry direct to the file */
    1012                 :            : static int
    1013                 :            : utmpx_write_direct(struct logininfo *li, struct utmpx *utx)
    1014                 :            : {
    1015                 :            :         logit("%s: not implemented!", __func__);
    1016                 :            :         return (0);
    1017                 :            : }
    1018                 :            : # endif /* UTMPX_USE_LIBRARY */
    1019                 :            : 
    1020                 :            : static int
    1021                 :            : utmpx_perform_login(struct logininfo *li)
    1022                 :            : {
    1023                 :            :         struct utmpx utx;
    1024                 :            : 
    1025                 :            :         construct_utmpx(li, &utx);
    1026                 :            : # ifdef UTMPX_USE_LIBRARY
    1027                 :            :         if (!utmpx_write_library(li, &utx)) {
    1028                 :            :                 logit("%s: utmp_write_library() failed", __func__);
    1029                 :            :                 return (0);
    1030                 :            :         }
    1031                 :            : # else
    1032                 :            :         if (!utmpx_write_direct(li, &ut)) {
    1033                 :            :                 logit("%s: utmp_write_direct() failed", __func__);
    1034                 :            :                 return (0);
    1035                 :            :         }
    1036                 :            : # endif
    1037                 :            :         return (1);
    1038                 :            : }
    1039                 :            : 
    1040                 :            : 
    1041                 :            : static int
    1042                 :            : utmpx_perform_logout(struct logininfo *li)
    1043                 :            : {
    1044                 :            :         struct utmpx utx;
    1045                 :            : 
    1046                 :            :         construct_utmpx(li, &utx);
    1047                 :            : # ifdef HAVE_ID_IN_UTMPX
    1048                 :            :         line_abbrevname(utx.ut_id, li->line, sizeof(utx.ut_id));
    1049                 :            : # endif
    1050                 :            : # ifdef HAVE_TYPE_IN_UTMPX
    1051                 :            :         utx.ut_type = DEAD_PROCESS;
    1052                 :            : # endif
    1053                 :            : 
    1054                 :            : # ifdef UTMPX_USE_LIBRARY
    1055                 :            :         utmpx_write_library(li, &utx);
    1056                 :            : # else
    1057                 :            :         utmpx_write_direct(li, &utx);
    1058                 :            : # endif
    1059                 :            :         return (1);
    1060                 :            : }
    1061                 :            : 
    1062                 :            : int
    1063                 :            : utmpx_write_entry(struct logininfo *li)
    1064                 :            : {
    1065                 :            :         switch(li->type) {
    1066                 :            :         case LTYPE_LOGIN:
    1067                 :            :                 return (utmpx_perform_login(li));
    1068                 :            :         case LTYPE_LOGOUT:
    1069                 :            :                 return (utmpx_perform_logout(li));
    1070                 :            :         default:
    1071                 :            :                 logit("%s: invalid type field", __func__);
    1072                 :            :                 return (0);
    1073                 :            :         }
    1074                 :            : }
    1075                 :            : #endif /* USE_UTMPX */
    1076                 :            : 
    1077                 :            : 
    1078                 :            : /**
    1079                 :            :  ** Low-level wtmp functions
    1080                 :            :  **/
    1081                 :            : 
    1082                 :            : #ifdef USE_WTMP
    1083                 :            : 
    1084                 :            : /*
    1085                 :            :  * Write a wtmp entry direct to the end of the file
    1086                 :            :  * This is a slight modification of code in OpenBSD's logwtmp.c
    1087                 :            :  */
    1088                 :            : static int
    1089                 :            : wtmp_write(struct logininfo *li, struct utmp *ut)
    1090                 :            : {
    1091                 :            :         struct stat buf;
    1092                 :            :         int fd, ret = 1;
    1093                 :            : 
    1094                 :            :         if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
    1095                 :            :                 logit("%s: problem writing %s: %s", __func__,
    1096                 :            :                     WTMP_FILE, strerror(errno));
    1097                 :            :                 return (0);
    1098                 :            :         }
    1099                 :            :         if (fstat(fd, &buf) == 0)
    1100                 :            :                 if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) {
    1101                 :            :                         ftruncate(fd, buf.st_size);
    1102                 :            :                         logit("%s: problem writing %s: %s", __func__,
    1103                 :            :                             WTMP_FILE, strerror(errno));
    1104                 :            :                         ret = 0;
    1105                 :            :                 }
    1106                 :            :         close(fd);
    1107                 :            :         return (ret);
    1108                 :            : }
    1109                 :            : 
    1110                 :            : static int
    1111                 :            : wtmp_perform_login(struct logininfo *li)
    1112                 :            : {
    1113                 :            :         struct utmp ut;
    1114                 :            : 
    1115                 :            :         construct_utmp(li, &ut);
    1116                 :            :         return (wtmp_write(li, &ut));
    1117                 :            : }
    1118                 :            : 
    1119                 :            : 
    1120                 :            : static int
    1121                 :            : wtmp_perform_logout(struct logininfo *li)
    1122                 :            : {
    1123                 :            :         struct utmp ut;
    1124                 :            : 
    1125                 :            :         construct_utmp(li, &ut);
    1126                 :            :         return (wtmp_write(li, &ut));
    1127                 :            : }
    1128                 :            : 
    1129                 :            : 
    1130                 :            : int
    1131                 :            : wtmp_write_entry(struct logininfo *li)
    1132                 :            : {
    1133                 :            :         switch(li->type) {
    1134                 :            :         case LTYPE_LOGIN:
    1135                 :            :                 return (wtmp_perform_login(li));
    1136                 :            :         case LTYPE_LOGOUT:
    1137                 :            :                 return (wtmp_perform_logout(li));
    1138                 :            :         default:
    1139                 :            :                 logit("%s: invalid type field", __func__);
    1140                 :            :                 return (0);
    1141                 :            :         }
    1142                 :            : }
    1143                 :            : 
    1144                 :            : 
    1145                 :            : /*
    1146                 :            :  * Notes on fetching login data from wtmp/wtmpx
    1147                 :            :  *
    1148                 :            :  * Logouts are usually recorded with (amongst other things) a blank
    1149                 :            :  * username on a given tty line.  However, some systems (HP-UX is one)
    1150                 :            :  * leave all fields set, but change the ut_type field to DEAD_PROCESS.
    1151                 :            :  *
    1152                 :            :  * Since we're only looking for logins here, we know that the username
    1153                 :            :  * must be set correctly. On systems that leave it in, we check for
    1154                 :            :  * ut_type==USER_PROCESS (indicating a login.)
    1155                 :            :  *
    1156                 :            :  * Portability: Some systems may set something other than USER_PROCESS
    1157                 :            :  * to indicate a login process. I don't know of any as I write. Also,
    1158                 :            :  * it's possible that some systems may both leave the username in
    1159                 :            :  * place and not have ut_type.
    1160                 :            :  */
    1161                 :            : 
    1162                 :            : /* return true if this wtmp entry indicates a login */
    1163                 :            : static int
    1164                 :            : wtmp_islogin(struct logininfo *li, struct utmp *ut)
    1165                 :            : {
    1166                 :            :         if (strncmp(li->username, ut->ut_name,
    1167                 :            :             MIN_SIZEOF(li->username, ut->ut_name)) == 0) {
    1168                 :            : # ifdef HAVE_TYPE_IN_UTMP
    1169                 :            :                 if (ut->ut_type & USER_PROCESS)
    1170                 :            :                         return (1);
    1171                 :            : # else
    1172                 :            :                 return (1);
    1173                 :            : # endif
    1174                 :            :         }
    1175                 :            :         return (0);
    1176                 :            : }
    1177                 :            : 
    1178                 :            : int
    1179                 :            : wtmp_get_entry(struct logininfo *li)
    1180                 :            : {
    1181                 :            :         struct stat st;
    1182                 :            :         struct utmp ut;
    1183                 :            :         int fd, found = 0;
    1184                 :            : 
    1185                 :            :         /* Clear the time entries in our logininfo */
    1186                 :            :         li->tv_sec = li->tv_usec = 0;
    1187                 :            : 
    1188                 :            :         if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) {
    1189                 :            :                 logit("%s: problem opening %s: %s", __func__,
    1190                 :            :                     WTMP_FILE, strerror(errno));
    1191                 :            :                 return (0);
    1192                 :            :         }
    1193                 :            :         if (fstat(fd, &st) != 0) {
    1194                 :            :                 logit("%s: couldn't stat %s: %s", __func__,
    1195                 :            :                     WTMP_FILE, strerror(errno));
    1196                 :            :                 close(fd);
    1197                 :            :                 return (0);
    1198                 :            :         }
    1199                 :            : 
    1200                 :            :         /* Seek to the start of the last struct utmp */
    1201                 :            :         if (lseek(fd, -(off_t)sizeof(struct utmp), SEEK_END) == -1) {
    1202                 :            :                 /* Looks like we've got a fresh wtmp file */
    1203                 :            :                 close(fd);
    1204                 :            :                 return (0);
    1205                 :            :         }
    1206                 :            : 
    1207                 :            :         while (!found) {
    1208                 :            :                 if (atomicio(read, fd, &ut, sizeof(ut)) != sizeof(ut)) {
    1209                 :            :                         logit("%s: read of %s failed: %s", __func__,
    1210                 :            :                             WTMP_FILE, strerror(errno));
    1211                 :            :                         close (fd);
    1212                 :            :                         return (0);
    1213                 :            :                 }
    1214                 :            :                 if (wtmp_islogin(li, &ut) ) {
    1215                 :            :                         found = 1;
    1216                 :            :                         /*
    1217                 :            :                          * We've already checked for a time in struct
    1218                 :            :                          * utmp, in login_getlast()
    1219                 :            :                          */
    1220                 :            : # ifdef HAVE_TIME_IN_UTMP
    1221                 :            :                         li->tv_sec = ut.ut_time;
    1222                 :            : # else
    1223                 :            : #  if HAVE_TV_IN_UTMP
    1224                 :            :                         li->tv_sec = ut.ut_tv.tv_sec;
    1225                 :            : #  endif
    1226                 :            : # endif
    1227                 :            :                         line_fullname(li->line, ut.ut_line,
    1228                 :            :                             MIN_SIZEOF(li->line, ut.ut_line));
    1229                 :            : # ifdef HAVE_HOST_IN_UTMP
    1230                 :            :                         strlcpy(li->hostname, ut.ut_host,
    1231                 :            :                             MIN_SIZEOF(li->hostname, ut.ut_host));
    1232                 :            : # endif
    1233                 :            :                         continue;
    1234                 :            :                 }
    1235                 :            :                 /* Seek back 2 x struct utmp */
    1236                 :            :                 if (lseek(fd, -(off_t)(2 * sizeof(struct utmp)), SEEK_CUR) == -1) {
    1237                 :            :                         /* We've found the start of the file, so quit */
    1238                 :            :                         close(fd);
    1239                 :            :                         return (0);
    1240                 :            :                 }
    1241                 :            :         }
    1242                 :            : 
    1243                 :            :         /* We found an entry. Tidy up and return */
    1244                 :            :         close(fd);
    1245                 :            :         return (1);
    1246                 :            : }
    1247                 :            : # endif /* USE_WTMP */
    1248                 :            : 
    1249                 :            : 
    1250                 :            : /**
    1251                 :            :  ** Low-level wtmpx functions
    1252                 :            :  **/
    1253                 :            : 
    1254                 :            : #ifdef USE_WTMPX
    1255                 :            : /*
    1256                 :            :  * Write a wtmpx entry direct to the end of the file
    1257                 :            :  * This is a slight modification of code in OpenBSD's logwtmp.c
    1258                 :            :  */
    1259                 :            : static int
    1260                 :            : wtmpx_write(struct logininfo *li, struct utmpx *utx)
    1261                 :            : {
    1262                 :            : #ifndef HAVE_UPDWTMPX
    1263                 :            :         struct stat buf;
    1264                 :            :         int fd, ret = 1;
    1265                 :            : 
    1266                 :            :         if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
    1267                 :            :                 logit("%s: problem opening %s: %s", __func__,
    1268                 :            :                     WTMPX_FILE, strerror(errno));
    1269                 :            :                 return (0);
    1270                 :            :         }
    1271                 :            : 
    1272                 :            :         if (fstat(fd, &buf) == 0)
    1273                 :            :                 if (atomicio(vwrite, fd, utx, sizeof(*utx)) != sizeof(*utx)) {
    1274                 :            :                         ftruncate(fd, buf.st_size);
    1275                 :            :                         logit("%s: problem writing %s: %s", __func__,
    1276                 :            :                             WTMPX_FILE, strerror(errno));
    1277                 :            :                         ret = 0;
    1278                 :            :                 }
    1279                 :            :         close(fd);
    1280                 :            : 
    1281                 :            :         return (ret);
    1282                 :            : #else
    1283                 :            :         updwtmpx(WTMPX_FILE, utx);
    1284                 :            :         return (1);
    1285                 :            : #endif
    1286                 :            : }
    1287                 :            : 
    1288                 :            : 
    1289                 :            : static int
    1290                 :            : wtmpx_perform_login(struct logininfo *li)
    1291                 :            : {
    1292                 :            :         struct utmpx utx;
    1293                 :            : 
    1294                 :            :         construct_utmpx(li, &utx);
    1295                 :            :         return (wtmpx_write(li, &utx));
    1296                 :            : }
    1297                 :            : 
    1298                 :            : 
    1299                 :            : static int
    1300                 :            : wtmpx_perform_logout(struct logininfo *li)
    1301                 :            : {
    1302                 :            :         struct utmpx utx;
    1303                 :            : 
    1304                 :            :         construct_utmpx(li, &utx);
    1305                 :            :         return (wtmpx_write(li, &utx));
    1306                 :            : }
    1307                 :            : 
    1308                 :            : 
    1309                 :            : int
    1310                 :            : wtmpx_write_entry(struct logininfo *li)
    1311                 :            : {
    1312                 :            :         switch(li->type) {
    1313                 :            :         case LTYPE_LOGIN:
    1314                 :            :                 return (wtmpx_perform_login(li));
    1315                 :            :         case LTYPE_LOGOUT:
    1316                 :            :                 return (wtmpx_perform_logout(li));
    1317                 :            :         default:
    1318                 :            :                 logit("%s: invalid type field", __func__);
    1319                 :            :                 return (0);
    1320                 :            :         }
    1321                 :            : }
    1322                 :            : 
    1323                 :            : /* Please see the notes above wtmp_islogin() for information about the
    1324                 :            :    next two functions */
    1325                 :            : 
    1326                 :            : /* Return true if this wtmpx entry indicates a login */
    1327                 :            : static int
    1328                 :            : wtmpx_islogin(struct logininfo *li, struct utmpx *utx)
    1329                 :            : {
    1330                 :            :         if (strncmp(li->username, utx->ut_user,
    1331                 :            :             MIN_SIZEOF(li->username, utx->ut_user)) == 0 ) {
    1332                 :            : # ifdef HAVE_TYPE_IN_UTMPX
    1333                 :            :                 if (utx->ut_type == USER_PROCESS)
    1334                 :            :                         return (1);
    1335                 :            : # else
    1336                 :            :                 return (1);
    1337                 :            : # endif
    1338                 :            :         }
    1339                 :            :         return (0);
    1340                 :            : }
    1341                 :            : 
    1342                 :            : 
    1343                 :            : int
    1344                 :            : wtmpx_get_entry(struct logininfo *li)
    1345                 :            : {
    1346                 :            :         struct stat st;
    1347                 :            :         struct utmpx utx;
    1348                 :            :         int fd, found=0;
    1349                 :            : 
    1350                 :            :         /* Clear the time entries */
    1351                 :            :         li->tv_sec = li->tv_usec = 0;
    1352                 :            : 
    1353                 :            :         if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) {
    1354                 :            :                 logit("%s: problem opening %s: %s", __func__,
    1355                 :            :                     WTMPX_FILE, strerror(errno));
    1356                 :            :                 return (0);
    1357                 :            :         }
    1358                 :            :         if (fstat(fd, &st) != 0) {
    1359                 :            :                 logit("%s: couldn't stat %s: %s", __func__,
    1360                 :            :                     WTMPX_FILE, strerror(errno));
    1361                 :            :                 close(fd);
    1362                 :            :                 return (0);
    1363                 :            :         }
    1364                 :            : 
    1365                 :            :         /* Seek to the start of the last struct utmpx */
    1366                 :            :         if (lseek(fd, -(off_t)sizeof(struct utmpx), SEEK_END) == -1 ) {
    1367                 :            :                 /* probably a newly rotated wtmpx file */
    1368                 :            :                 close(fd);
    1369                 :            :                 return (0);
    1370                 :            :         }
    1371                 :            : 
    1372                 :            :         while (!found) {
    1373                 :            :                 if (atomicio(read, fd, &utx, sizeof(utx)) != sizeof(utx)) {
    1374                 :            :                         logit("%s: read of %s failed: %s", __func__,
    1375                 :            :                             WTMPX_FILE, strerror(errno));
    1376                 :            :                         close (fd);
    1377                 :            :                         return (0);
    1378                 :            :                 }
    1379                 :            :                 /*
    1380                 :            :                  * Logouts are recorded as a blank username on a particular
    1381                 :            :                  * line. So, we just need to find the username in struct utmpx
    1382                 :            :                  */
    1383                 :            :                 if (wtmpx_islogin(li, &utx)) {
    1384                 :            :                         found = 1;
    1385                 :            : # if defined(HAVE_TV_IN_UTMPX)
    1386                 :            :                         li->tv_sec = utx.ut_tv.tv_sec;
    1387                 :            : # elif defined(HAVE_TIME_IN_UTMPX)
    1388                 :            :                         li->tv_sec = utx.ut_time;
    1389                 :            : # endif
    1390                 :            :                         line_fullname(li->line, utx.ut_line, sizeof(li->line));
    1391                 :            : # if defined(HAVE_HOST_IN_UTMPX)
    1392                 :            :                         strlcpy(li->hostname, utx.ut_host,
    1393                 :            :                             MIN_SIZEOF(li->hostname, utx.ut_host));
    1394                 :            : # endif
    1395                 :            :                         continue;
    1396                 :            :                 }
    1397                 :            :                 if (lseek(fd, -(off_t)(2 * sizeof(struct utmpx)), SEEK_CUR) == -1) {
    1398                 :            :                         close(fd);
    1399                 :            :                         return (0);
    1400                 :            :                 }
    1401                 :            :         }
    1402                 :            : 
    1403                 :            :         close(fd);
    1404                 :            :         return (1);
    1405                 :            : }
    1406                 :            : #endif /* USE_WTMPX */
    1407                 :            : 
    1408                 :            : /**
    1409                 :            :  ** Low-level libutil login() functions
    1410                 :            :  **/
    1411                 :            : 
    1412                 :            : #ifdef USE_LOGIN
    1413                 :            : static int
    1414                 :          0 : syslogin_perform_login(struct logininfo *li)
    1415                 :            : {
    1416                 :            :         struct utmp *ut;
    1417                 :            : 
    1418                 :          0 :         ut = xmalloc(sizeof(*ut));
    1419                 :          0 :         construct_utmp(li, ut);
    1420                 :          0 :         login(ut);
    1421                 :          0 :         free(ut);
    1422                 :            : 
    1423                 :          0 :         return (1);
    1424                 :            : }
    1425                 :            : 
    1426                 :            : static int
    1427                 :          0 : syslogin_perform_logout(struct logininfo *li)
    1428                 :            : {
    1429                 :            : # ifdef HAVE_LOGOUT
    1430                 :            :         char line[UT_LINESIZE];
    1431                 :            : 
    1432                 :          0 :         (void)line_stripname(line, li->line, sizeof(line));
    1433                 :            : 
    1434         [ #  # ]:          0 :         if (!logout(line))
    1435                 :          0 :                 logit("%s: logout() returned an error", __func__);
    1436                 :            : #  ifdef HAVE_LOGWTMP
    1437                 :            :         else
    1438                 :          0 :                 logwtmp(line, "", "");
    1439                 :            : #  endif
    1440                 :            :         /* FIXME: (ATL - if the need arises) What to do if we have
    1441                 :            :          * login, but no logout?  what if logout but no logwtmp? All
    1442                 :            :          * routines are in libutil so they should all be there,
    1443                 :            :          * but... */
    1444                 :            : # endif
    1445                 :          0 :         return (1);
    1446                 :            : }
    1447                 :            : 
    1448                 :            : int
    1449                 :          0 : syslogin_write_entry(struct logininfo *li)
    1450                 :            : {
    1451      [ #  #  # ]:          0 :         switch (li->type) {
    1452                 :            :         case LTYPE_LOGIN:
    1453                 :          0 :                 return (syslogin_perform_login(li));
    1454                 :            :         case LTYPE_LOGOUT:
    1455                 :          0 :                 return (syslogin_perform_logout(li));
    1456                 :            :         default:
    1457                 :          0 :                 logit("%s: Invalid type field", __func__);
    1458                 :          0 :                 return (0);
    1459                 :            :         }
    1460                 :            : }
    1461                 :            : #endif /* USE_LOGIN */
    1462                 :            : 
    1463                 :            : /* end of file log-syslogin.c */
    1464                 :            : 
    1465                 :            : /**
    1466                 :            :  ** Low-level lastlog functions
    1467                 :            :  **/
    1468                 :            : 
    1469                 :            : #ifdef USE_LASTLOG
    1470                 :            : 
    1471                 :            : #if !defined(LASTLOG_WRITE_PUTUTXLINE) || !defined(HAVE_GETLASTLOGXBYNAME)
    1472                 :            : /* open the file (using filemode) and seek to the login entry */
    1473                 :            : static int
    1474                 :          0 : lastlog_openseek(struct logininfo *li, int *fd, int filemode)
    1475                 :            : {
    1476                 :            :         off_t offset;
    1477                 :            :         char lastlog_file[1024];
    1478                 :            :         struct stat st;
    1479                 :            : 
    1480         [ #  # ]:          0 :         if (stat(LASTLOG_FILE, &st) != 0) {
    1481                 :          0 :                 logit("%s: Couldn't stat %s: %s", __func__,
    1482                 :          0 :                     LASTLOG_FILE, strerror(errno));
    1483                 :          0 :                 return (0);
    1484                 :            :         }
    1485         [ #  # ]:          0 :         if (S_ISDIR(st.st_mode)) {
    1486                 :            :                 snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s",
    1487                 :          0 :                     LASTLOG_FILE, li->username);
    1488         [ #  # ]:          0 :         } else if (S_ISREG(st.st_mode)) {
    1489                 :          0 :                 strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file));
    1490                 :            :         } else {
    1491                 :          0 :                 logit("%s: %.100s is not a file or directory!", __func__,
    1492                 :            :                     LASTLOG_FILE);
    1493                 :          0 :                 return (0);
    1494                 :            :         }
    1495                 :            : 
    1496                 :          0 :         *fd = open(lastlog_file, filemode, 0600);
    1497         [ #  # ]:          0 :         if (*fd < 0) {
    1498                 :          0 :                 debug("%s: Couldn't open %s: %s", __func__,
    1499                 :          0 :                     lastlog_file, strerror(errno));
    1500                 :          0 :                 return (0);
    1501                 :            :         }
    1502                 :            : 
    1503         [ #  # ]:          0 :         if (S_ISREG(st.st_mode)) {
    1504                 :            :                 /* find this uid's offset in the lastlog file */
    1505                 :          0 :                 offset = (off_t) ((u_long)li->uid * sizeof(struct lastlog));
    1506                 :            : 
    1507         [ #  # ]:          0 :                 if (lseek(*fd, offset, SEEK_SET) != offset) {
    1508                 :          0 :                         logit("%s: %s->lseek(): %s", __func__,
    1509                 :          0 :                             lastlog_file, strerror(errno));
    1510                 :          0 :                         close(*fd);
    1511                 :          0 :                         return (0);
    1512                 :            :                 }
    1513                 :            :         }
    1514                 :            : 
    1515                 :            :         return (1);
    1516                 :            : }
    1517                 :            : #endif /* !LASTLOG_WRITE_PUTUTXLINE || !HAVE_GETLASTLOGXBYNAME */
    1518                 :            : 
    1519                 :            : #ifdef LASTLOG_WRITE_PUTUTXLINE
    1520                 :            : int
    1521                 :            : lastlog_write_entry(struct logininfo *li)
    1522                 :            : {
    1523                 :            :         switch(li->type) {
    1524                 :            :         case LTYPE_LOGIN:
    1525                 :            :                 return 1; /* lastlog written by pututxline */
    1526                 :            :         default:
    1527                 :            :                 logit("lastlog_write_entry: Invalid type field");
    1528                 :            :                 return 0;
    1529                 :            :         }
    1530                 :            : }
    1531                 :            : #else /* LASTLOG_WRITE_PUTUTXLINE */
    1532                 :            : int
    1533                 :          0 : lastlog_write_entry(struct logininfo *li)
    1534                 :            : {
    1535                 :            :         struct lastlog last;
    1536                 :            :         int fd;
    1537                 :            : 
    1538         [ #  # ]:          0 :         switch(li->type) {
    1539                 :            :         case LTYPE_LOGIN:
    1540                 :            :                 /* create our struct lastlog */
    1541                 :            :                 memset(&last, '\0', sizeof(last));
    1542                 :          0 :                 line_stripname(last.ll_line, li->line, sizeof(last.ll_line));
    1543                 :          0 :                 strlcpy(last.ll_host, li->hostname,
    1544                 :            :                     MIN_SIZEOF(last.ll_host, li->hostname));
    1545                 :          0 :                 last.ll_time = li->tv_sec;
    1546                 :            :         
    1547         [ #  # ]:          0 :                 if (!lastlog_openseek(li, &fd, O_RDWR|O_CREAT))
    1548                 :            :                         return (0);
    1549                 :            :         
    1550                 :            :                 /* write the entry */
    1551         [ #  # ]:          0 :                 if (atomicio(vwrite, fd, &last, sizeof(last)) != sizeof(last)) {
    1552                 :          0 :                         close(fd);
    1553                 :          0 :                         logit("%s: Error writing to %s: %s", __func__,
    1554                 :          0 :                             LASTLOG_FILE, strerror(errno));
    1555                 :          0 :                         return (0);
    1556                 :            :                 }
    1557                 :            :         
    1558                 :          0 :                 close(fd);
    1559                 :          0 :                 return (1);
    1560                 :            :         default:
    1561                 :          0 :                 logit("%s: Invalid type field", __func__);
    1562                 :          0 :                 return (0);
    1563                 :            :         }
    1564                 :            : }
    1565                 :            : #endif /* LASTLOG_WRITE_PUTUTXLINE */
    1566                 :            : 
    1567                 :            : #ifdef HAVE_GETLASTLOGXBYNAME
    1568                 :            : int
    1569                 :            : lastlog_get_entry(struct logininfo *li)
    1570                 :            : {
    1571                 :            :         struct lastlogx l, *ll;
    1572                 :            : 
    1573                 :            :         if ((ll = getlastlogxbyname(li->username, &l)) == NULL) {
    1574                 :            :                 memset(&l, '\0', sizeof(l));
    1575                 :            :                 ll = &l;
    1576                 :            :         }
    1577                 :            :         line_fullname(li->line, ll->ll_line, sizeof(li->line));
    1578                 :            :         strlcpy(li->hostname, ll->ll_host,
    1579                 :            :                 MIN_SIZEOF(li->hostname, ll->ll_host));
    1580                 :            :         li->tv_sec = ll->ll_tv.tv_sec;
    1581                 :            :         li->tv_usec = ll->ll_tv.tv_usec;
    1582                 :            :         return (1);
    1583                 :            : }
    1584                 :            : #else /* HAVE_GETLASTLOGXBYNAME */
    1585                 :            : int
    1586                 :          0 : lastlog_get_entry(struct logininfo *li)
    1587                 :            : {
    1588                 :            :         struct lastlog last;
    1589                 :            :         int fd, ret;
    1590                 :            : 
    1591         [ #  # ]:          0 :         if (!lastlog_openseek(li, &fd, O_RDONLY))
    1592                 :            :                 return (0);
    1593                 :            : 
    1594                 :          0 :         ret = atomicio(read, fd, &last, sizeof(last));
    1595                 :          0 :         close(fd);
    1596                 :            : 
    1597   [ #  #  #  # ]:          0 :         switch (ret) {
    1598                 :            :         case 0:
    1599                 :            :                 memset(&last, '\0', sizeof(last));
    1600                 :            :                 /* FALLTHRU */
    1601                 :            :         case sizeof(last):
    1602                 :          0 :                 line_fullname(li->line, last.ll_line, sizeof(li->line));
    1603                 :          0 :                 strlcpy(li->hostname, last.ll_host,
    1604                 :            :                     MIN_SIZEOF(li->hostname, last.ll_host));
    1605                 :          0 :                 li->tv_sec = last.ll_time;
    1606                 :          0 :                 return (1);
    1607                 :            :         case -1:
    1608                 :          0 :                 error("%s: Error reading from %s: %s", __func__,
    1609                 :          0 :                     LASTLOG_FILE, strerror(errno));
    1610                 :          0 :                 return (0);
    1611                 :            :         default:
    1612                 :          0 :                 error("%s: Error reading from %s: Expecting %d, got %d",
    1613                 :            :                     __func__, LASTLOG_FILE, (int)sizeof(last), ret);
    1614                 :          0 :                 return (0);
    1615                 :            :         }
    1616                 :            : 
    1617                 :            :         /* NOTREACHED */
    1618                 :            :         return (0);
    1619                 :            : }
    1620                 :            : #endif /* HAVE_GETLASTLOGXBYNAME */
    1621                 :            : #endif /* USE_LASTLOG */
    1622                 :            : 
    1623                 :            : #if defined(USE_UTMPX) && defined(HAVE_SETUTXDB) && \
    1624                 :            :     defined(UTXDB_LASTLOGIN) && defined(HAVE_GETUTXUSER)
    1625                 :            : int
    1626                 :            : utmpx_get_entry(struct logininfo *li)
    1627                 :            : {
    1628                 :            :         struct utmpx *utx;
    1629                 :            : 
    1630                 :            :         if (setutxdb(UTXDB_LASTLOGIN, NULL) != 0)
    1631                 :            :                 return (0);
    1632                 :            :         utx = getutxuser(li->username);
    1633                 :            :         if (utx == NULL) {
    1634                 :            :                 endutxent();
    1635                 :            :                 return (0);
    1636                 :            :         }
    1637                 :            : 
    1638                 :            :         line_fullname(li->line, utx->ut_line,
    1639                 :            :             MIN_SIZEOF(li->line, utx->ut_line));
    1640                 :            :         strlcpy(li->hostname, utx->ut_host,
    1641                 :            :             MIN_SIZEOF(li->hostname, utx->ut_host));
    1642                 :            :         li->tv_sec = utx->ut_tv.tv_sec;
    1643                 :            :         li->tv_usec = utx->ut_tv.tv_usec;
    1644                 :            :         endutxent();
    1645                 :            :         return (1);
    1646                 :            : }
    1647                 :            : #endif /* USE_UTMPX && HAVE_SETUTXDB && UTXDB_LASTLOGIN && HAVE_GETUTXUSER */
    1648                 :            : 
    1649                 :            : #ifdef USE_BTMP
    1650                 :            :   /*
    1651                 :            :    * Logs failed login attempts in _PATH_BTMP if that exists.
    1652                 :            :    * The most common login failure is to give password instead of username.
    1653                 :            :    * So the _PATH_BTMP file checked for the correct permission, so that
    1654                 :            :    * only root can read it.
    1655                 :            :    */
    1656                 :            : 
    1657                 :            : void
    1658                 :          0 : record_failed_login(const char *username, const char *hostname,
    1659                 :            :     const char *ttyn)
    1660                 :            : {
    1661                 :            :         int fd;
    1662                 :            :         struct utmp ut;
    1663                 :            :         struct sockaddr_storage from;
    1664                 :          0 :         socklen_t fromlen = sizeof(from);
    1665                 :            :         struct sockaddr_in *a4;
    1666                 :            :         struct sockaddr_in6 *a6;
    1667                 :            :         time_t t;
    1668                 :            :         struct stat fst;
    1669                 :            : 
    1670         [ #  # ]:          0 :         if (geteuid() != 0)
    1671                 :          0 :                 return;
    1672         [ #  # ]:          0 :         if ((fd = open(_PATH_BTMP, O_WRONLY | O_APPEND)) < 0) {
    1673                 :          0 :                 debug("Unable to open the btmp file %s: %s", _PATH_BTMP,
    1674                 :          0 :                     strerror(errno));
    1675                 :          0 :                 return;
    1676                 :            :         }
    1677         [ #  # ]:          0 :         if (fstat(fd, &fst) < 0) {
    1678                 :          0 :                 logit("%s: fstat of %s failed: %s", __func__, _PATH_BTMP,
    1679                 :          0 :                     strerror(errno));
    1680                 :          0 :                 goto out;
    1681                 :            :         }
    1682         [ #  # ]:          0 :         if((fst.st_mode & (S_IXGRP | S_IRWXO)) || (fst.st_uid != 0)){
    1683                 :          0 :                 logit("Excess permission or bad ownership on file %s",
    1684                 :            :                     _PATH_BTMP);
    1685                 :          0 :                 goto out;
    1686                 :            :         }
    1687                 :            : 
    1688                 :            :         memset(&ut, 0, sizeof(ut));
    1689                 :            :         /* strncpy because we don't necessarily want nul termination */
    1690                 :            :         strncpy(ut.ut_user, username, sizeof(ut.ut_user));
    1691                 :          0 :         strlcpy(ut.ut_line, "ssh:notty", sizeof(ut.ut_line));
    1692                 :            : 
    1693                 :          0 :         time(&t);
    1694                 :          0 :         ut.ut_time = t;     /* ut_time is not always a time_t */
    1695                 :          0 :         ut.ut_type = LOGIN_PROCESS;
    1696                 :          0 :         ut.ut_pid = getpid();
    1697                 :            : 
    1698                 :            :         /* strncpy because we don't necessarily want nul termination */
    1699                 :            :         strncpy(ut.ut_host, hostname, sizeof(ut.ut_host));
    1700                 :            : 
    1701   [ #  #  #  # ]:          0 :         if (packet_connection_is_on_socket() &&
    1702                 :          0 :             getpeername(packet_get_connection_in(),
    1703                 :            :             (struct sockaddr *)&from, &fromlen) == 0) {
    1704                 :          0 :                 ipv64_normalise_mapped(&from, &fromlen);
    1705         [ #  # ]:          0 :                 if (from.ss_family == AF_INET) {
    1706                 :          0 :                         a4 = (struct sockaddr_in *)&from;
    1707                 :          0 :                         memcpy(&ut.ut_addr, &(a4->sin_addr),
    1708                 :            :                             MIN_SIZEOF(ut.ut_addr, a4->sin_addr));
    1709                 :            :                 }
    1710                 :            : #ifdef HAVE_ADDR_V6_IN_UTMP
    1711         [ #  # ]:          0 :                 if (from.ss_family == AF_INET6) {
    1712                 :          0 :                         a6 = (struct sockaddr_in6 *)&from;
    1713                 :          0 :                         memcpy(&ut.ut_addr_v6, &(a6->sin6_addr),
    1714                 :            :                             MIN_SIZEOF(ut.ut_addr_v6, a6->sin6_addr));
    1715                 :            :                 }
    1716                 :            : #endif
    1717                 :            :         }
    1718                 :            : 
    1719         [ #  # ]:          0 :         if (atomicio(vwrite, fd, &ut, sizeof(ut)) != sizeof(ut))
    1720                 :          0 :                 error("Failed to write to %s: %s", _PATH_BTMP,
    1721                 :          0 :                     strerror(errno));
    1722                 :            : 
    1723                 :            : out:
    1724                 :          0 :         close(fd);
    1725                 :            : }
    1726                 :            : #endif  /* USE_BTMP */

Generated by: LCOV version 1.9