source: trunk/third/ssh/login.c @ 12646

Revision 12646, 14.6 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12645, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2
3login.c
4
5Author: Tatu Ylonen <ylo@cs.hut.fi>
6
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8                   All rights reserved
9
10Created: Fri Mar 24 14:51:08 1995 ylo
11
12This file performs some of the things login(1) normally does.  We cannot
13easily use something like login -p -h host -f user, because there are
14several different logins around, and it is hard to determined what kind of
15login the current system has.  Also, we want to be able to execute commands
16on a tty.
17
18*/
19
20/*
21 * $Id: login.c,v 1.1.1.3 1999-03-08 17:43:07 danw Exp $
22 * $Log: not supported by cvs2svn $
23 * Revision 1.10  1998/07/08 00:44:01  kivinen
24 *      Added better hpux TCB auth support. Added ut_syslen support.
25 *
26 * Revision 1.9  1998/04/30  01:52:43  kivinen
27 *      Moved copying of user name to utmp structure to be done only
28 *      in login.
29 *
30 * Revision 1.8  1998/04/17 00:38:38  kivinen
31 *      Fixed ttyslot code.
32 *
33 * Revision 1.7  1997/03/26 07:09:49  kivinen
34 *      Added HAVE_NO_TZ_IN_GETTIMEOFDAY support.
35 *
36 * Revision 1.6  1997/01/10 16:15:19  ttsalo
37 *     Merged ttyslot patch for SunOS/Solaris from Scott Schwartz
38 *
39 * Revision 1.5  1996/10/29 22:38:58  kivinen
40 *      log -> log_msg.
41 *
42 * Revision 1.4  1996/07/12 07:20:49  ttsalo
43 *      utmp fix for cray (handled like sgi)
44 *
45 * Revision 1.3  1996/06/27 12:44:08  ttsalo
46 *         FreeBSD with long hostnames in utmp fixed (again).
47 *
48 * Revision 1.2  1996/06/27 12:30:32  ttsalo
49 *      FreeBSD with long hostnames in utmp fixed.
50 *      Also small changes for SCO.
51 *
52 * Revision 1.1.1.1  1996/02/18 21:38:12  ylo
53 *      Imported ssh-1.2.13.
54 *
55 * Revision 1.7  1995/09/21  17:11:52  ylo
56 *      Added NULL second argument to gettimeofday.
57 *
58 * Revision 1.6  1995/09/09  21:26:43  ylo
59 * /m/shadows/u2/users/ylo/ssh/README
60 *
61 * Revision 1.5  1995/07/27  00:38:43  ylo
62 *      Use SSH_{WTMP,UTMP,LASTLOG} instead of hard-coded default
63 *      values if path not defined in header.
64 *
65 * Revision 1.4  1995/07/16  01:03:11  ylo
66 *      Clear host name field in record_logout.
67 *      Test DEAD_PROCESS instead of LOGIN_PROCESS in ifdef.
68 *
69 * Revision 1.3  1995/07/15  13:25:17  ylo
70 *      NEXTSTEP patches from Ray Spalding.
71 *
72 * Revision 1.2  1995/07/13  01:26:29  ylo
73 *      Removed "Last modified" header.
74 *      Added cvs log.
75 *
76 * $Endlog$
77 */
78
79#include "includes.h"
80#ifdef HAVE_UTMP_H
81#include <utmp.h>
82#ifdef HAVE_LASTLOG_H
83#include <lastlog.h> /* Some have the definitions in utmp.h. */
84#endif /* HAVE_LASTLOG_H */
85#endif /* HAVE_UTMP_H */
86#ifdef HAVE_UTMPX_H
87#include <utmpx.h>
88#ifndef SCO
89#ifdef MAJOR_IN_MKDEV
90#include <sys/mkdev.h>  /* for minor() */
91#endif /* MAJOR_IN_MKDEV */
92#ifdef MAJOR_IN_SYSMACROS
93#include <sys/sysmacros.h>      /* for minor() */
94#endif /* MAJOR_IN_SYSMACROS */
95#endif /* SCO */
96#endif /* HAVE_UTMPX_H */
97#ifdef HAVE_USERSEC_H
98#include <usersec.h>
99#endif /* HAVE_USERSEC_H */
100#ifdef HAVE_HPUX_TCB_AUTH
101#include <sys/types.h>
102#include <hpsecurity.h>
103#include <prot.h>
104#endif /* HAVE_HPUX_TCB_AUTH */
105#include "ssh.h"
106
107/* Returns the time when the user last logged in.  Returns 0 if the
108   information is not available.  This must be called before record_login.
109   The host the user logged in from will be returned in buf. */
110
111#ifdef LASTLOG_IS_DIR
112unsigned long get_last_login_time(uid_t uid, const char *name,
113                                  char *buf, unsigned int bufsize)
114{
115#if defined(HAVE_LASTLOG_H) || defined(HAVE_LASTLOG)
116  struct lastlog ll;
117  char lastlogfile[500];
118  int fd;
119
120#ifdef _PATH_LASTLOG
121  sprintf(lastlogfile, "%.200s/%.200s", _PATH_LASTLOG, name);
122#else
123#ifdef LASTLOG_FILE
124  sprintf(lastlogfile, "%.200s/%.200s", LASTLOG_FILE, name);
125#else
126  sprintf(lastlogfile, "%.200s/%.200s", SSH_LASTLOG, name);
127#endif
128#endif
129
130  strcpy(buf, "");
131
132  fd = open(lastlogfile, O_RDONLY);
133  if (fd < 0)
134    return 0;
135  if (read(fd, &ll, sizeof(ll)) != sizeof(ll))
136    {
137      close(fd);
138      return 0;
139    }
140  close(fd);
141  if (bufsize > sizeof(ll.ll_host) + 1)
142    bufsize = sizeof(ll.ll_host) + 1;
143  strncpy(buf, ll.ll_host, bufsize - 1);
144  buf[bufsize - 1] = 0;
145  return ll.ll_time;
146 
147#else /* HAVE_LASTLOG_H || HAVE_LASTLOG */
148
149  return 0;
150
151#endif /* HAVE_LASTLOG_H || HAVE_LASTLOG */
152}
153
154#else /* LASTLOG_IS_DIR */
155
156/* Returns the time when the user last logged in (or 0 if no previous login
157   is found).  The name of the host used last time is returned in buf. */
158
159unsigned long get_last_login_time(uid_t uid, const char *logname,
160                                  char *buf, unsigned int bufsize)
161{
162#if defined(HAVE_LASTLOG_H) || defined(HAVE_LASTLOG)
163
164  struct lastlog ll;
165  char *lastlog;
166  int fd;
167
168#ifdef _PATH_LASTLOG
169  lastlog = _PATH_LASTLOG;
170#else
171#ifdef LASTLOG_FILE
172  lastlog = LASTLOG_FILE;
173#else
174  lastlog = SSH_LASTLOG;
175#endif
176#endif
177
178  strcpy(buf, "");
179
180  fd = open(lastlog, O_RDONLY);
181  if (fd < 0)
182    return 0;
183  lseek(fd, (off_t)((long)uid * sizeof(ll)), 0);
184  if (read(fd, &ll, sizeof(ll)) != sizeof(ll))
185    {
186      close(fd);
187      return 0;
188    }
189  close(fd);
190  if (bufsize > sizeof(ll.ll_host) + 1)
191    bufsize = sizeof(ll.ll_host) + 1;
192  strncpy(buf, ll.ll_host, bufsize - 1);
193  buf[bufsize - 1] = 0;
194  return ll.ll_time;
195
196#else /* HAVE_LASTLOG_H || HAVE_LASTLOG */
197
198#ifdef HAVE_USERSEC_H
199
200  char *lasthost;
201  int lasttime;
202  if (setuserdb(S_READ) < 0)
203    return 0;
204  if (getuserattr((char *)logname, S_LASTTIME, &lasttime, SEC_INT) < 0)
205    {
206      enduserdb();
207      return 0;
208    }
209  if (getuserattr((char *)logname, S_LASTHOST, &lasthost, SEC_CHAR) < 0)
210    {
211      enduserdb();
212      return 0;
213    }
214  strncpy(buf, lasthost, bufsize);
215  buf[bufsize - 1] = 0;
216  if (enduserdb() < 0)
217    return 0;
218  return lasttime;
219
220#else /* HAVE_USERSEC_H */
221#ifdef HAVE_HPUX_TCB_AUTH
222  {
223    struct pr_passwd *pr;
224   
225    pr = getprpwnam(logname);
226    if (pr)
227      if (pr->uflg.fg_slogin)
228        return pr->ufld.fd_slogin;
229  }
230#endif /* HAVE_HPUX_TCB_AUTH */
231 
232  return 0;
233
234#endif /* HAVE_USERSEC_H */
235
236#endif /* HAVE_LASTLOG_H || HAVE_LASTLOG */
237}
238#endif /* LASTLOG_IS_DIR */
239
240/* Records that the user has logged in.  I these parts of operating systems
241   were more standardized. */
242
243void record_login(int pid, const char *ttyname, const char *user, uid_t uid,
244                  const char *host, struct sockaddr_in *addr)
245{
246  int fd;
247
248#if defined(HAVE_LASTLOG_H) || defined(HAVE_LASTLOG)
249  struct lastlog ll;
250  char *lastlog;
251#ifdef LASTLOG_IS_DIR
252  char lastlogfile[100];
253#endif /* LASTLOG_IS_DIR */
254#endif /* HAVE_LASTLOG_H || HAVE_LASTLOG */
255
256#if defined(HAVE_UTMP_H) && !defined(HAVE_UTMPX_H)
257  struct utmp u, u2;
258  off_t offset;
259  const char *utmp, *wtmp;
260
261  /* Construct an utmp/wtmp entry. */
262  memset(&u, 0, sizeof(u));
263#ifdef DEAD_PROCESS
264  if (strcmp(user, "") == 0)
265    u.ut_type = DEAD_PROCESS; /* logout */
266  else
267    u.ut_type = USER_PROCESS;
268#endif /* LOGIN_PROCESS */
269#ifdef HAVE_PID_IN_UTMP
270  u.ut_pid = pid;
271#endif /* PID_IN_UTMP */
272#ifdef HAVE_ID_IN_UTMP
273#if defined(__sgi) || defined(CRAY)
274    strncpy(u.ut_id, ttyname + 8, sizeof(u.ut_id)); /* /dev/ttyq99 -> q99 */
275#else /* __sgi */
276    if (sizeof(u.ut_id) > 4)
277      strncpy(u.ut_id, ttyname + 5, sizeof(u.ut_id));
278    else
279      strncpy(u.ut_id, ttyname + strlen(ttyname) - 2, sizeof(u.ut_id));
280#endif /* __sgi */
281#endif /* HAVE_ID_IN_UTMP */
282  strncpy(u.ut_line, ttyname + 5, sizeof(u.ut_line));
283  u.ut_time = time(NULL);
284#ifdef HAVE_NAME_IN_UTMP
285  strncpy(u.ut_name, user, sizeof(u.ut_name));
286#else /* HAVE_NAME_IN_UTMP */
287  strncpy(u.ut_user, user, sizeof(u.ut_user));
288#endif /* HAVE_NAME_IN_UTMP */
289#ifdef HAVE_HOST_IN_UTMP
290  strncpy(u.ut_host, host, sizeof(u.ut_host));
291#ifdef __FreeBSD__
292  if (strlen(host) > sizeof(u.ut_host)) {
293    strncpy(u.ut_host, get_remote_ipaddr(), sizeof(u.ut_host));
294  }
295#endif /* __FreeBSD__ */
296#endif /* HAVE_HOST_IN_UTMP */
297#ifdef HAVE_ADDR_IN_UTMP
298  if (addr)
299    memcpy(&u.ut_addr, &addr->sin_addr, sizeof(u.ut_addr));
300  else
301    memset(&u.ut_addr, 0, sizeof(u.ut_addr));
302#endif
303
304  /* Figure out the file names. */
305#ifdef _PATH_UTMP
306  utmp = _PATH_UTMP;
307  wtmp = _PATH_WTMP;
308#else
309#ifdef UTMP_FILE
310  utmp = UTMP_FILE;
311  wtmp = WTMP_FILE;
312#else
313  utmp = SSH_UTMP;
314  wtmp = SSH_WTMP;
315#endif
316#endif
317 
318#ifdef HAVE_LIBUTIL_LOGIN
319  login(&u);
320#else /* HAVE_LIBUTIL_LOGIN */
321  /* Append an entry to wtmp. */
322  fd = open(wtmp, O_WRONLY|O_APPEND);
323  if (fd >= 0)
324    {
325      if (write(fd, &u, sizeof(u)) != sizeof(u))
326        log_msg("Could not write %.100s: %.100s", wtmp, strerror(errno));
327      close(fd);
328    }
329
330  /* Replace the proper entry in utmp, as identified by ut_line.  Append a
331     new entry if the line could not be found. */
332  fd = open(utmp, O_RDWR);
333  if (fd >= 0)
334    {
335#ifdef HAVE_TTYSLOT
336      int n = ttyslot();
337#if defined(ultrix) || defined(NeXT)
338/*
339 * the problem is that Berkeley unix uses ttyslot() to determine where in
340 * the utmp file to write and it is correct at login time because the
341 * controlling tty is correct.  At logout time, I think a different process
342 * runs this code and may have a different (or no) controlling tty so
343 * we must search for the right record to clobber.  -- corey 5/7/97
344 */
345      if (n > 0 && *user) {
346#else
347      if (n > 0) {
348#endif
349        lseek(fd, (off_t)(n*sizeof(u)), 0);
350        if (write(fd, &u, sizeof(u)) != sizeof(u))
351          log_msg("Could not write to %.100s: %.100s",
352            utmp, strerror(errno));
353      } else
354#endif
355      while (1)
356        {
357          offset = lseek(fd, (off_t)0L, 1);
358          if (read(fd, &u2, sizeof(u2)) != sizeof(u2))
359            {
360              lseek(fd, offset, 0);
361              if (write(fd, &u, sizeof(u)) != sizeof(u))
362                log_msg("Could not append to %.100s: %.100s",
363                    utmp, strerror(errno));
364              break;
365            }
366#if defined(ultrix) || defined(NeXT)            /* corey */
367          if (strcmp(u2.ut_line, ttyname + 5) == 0 && *u2.ut_name)
368#else   /* ultrix || NeXT */
369          if (strncmp(u2.ut_line, ttyname + 5, sizeof(u2.ut_line)) == 0)
370#endif  /* ultrix || NeXT */
371            {
372              lseek(fd, offset, 0);
373              if (write(fd, &u, sizeof(u)) != sizeof(u))
374                log_msg("Could not write to %.100s: %.100s",
375                    utmp, strerror(errno));
376              break;
377            }
378        }
379      close(fd);
380    }
381#endif /* HAVE_LIBUTIL_LOGIN */
382#endif /* HAVE_UTMP_H && !HAVE_UTMPX_H */
383
384#ifdef HAVE_UTMPX_H
385  {
386    struct utmpx ux, *uxp;
387    memset(&ux, 0, sizeof(ux));
388    strncpy(ux.ut_line, ttyname + 5, sizeof(ux.ut_line));
389    if (strcmp(user, "") == 0) {
390        /* logout; find previous entry for pid and zonk it */
391        setutxent();
392        while ( (uxp = getutxent()) ) {
393                if (uxp->ut_pid != (pid_t)pid)
394                        continue;
395                ux = *uxp;
396                break;
397        }
398        endutxent();
399    }
400    else {
401        /* login: find appropriate slot for this tty */
402        uxp = getutxline(&ux);
403        if (uxp)
404          ux = *uxp;
405        strncpy(ux.ut_user, user, sizeof(ux.ut_user));
406    }
407#if defined(__sgi) || defined(SCO)
408    strncpy(ux.ut_id, ttyname + 8, sizeof(ux.ut_id)); /* /dev/ttyq99 -> q99 */
409#else /* __sgi */
410    if (sizeof(ux.ut_id) > 4)
411      strncpy(ux.ut_id, ttyname + 5, sizeof(ux.ut_id));
412    else {
413      struct stat st;
414      char buf[20];
415     
416      buf[0] = 0;
417      if (stat(ttyname, &st) == 0) {
418        /* allow for 1000 /dev/pts devices */
419        sprintf(buf, "P%03d", (int)minor(st.st_rdev));
420      }
421      strncpy(ux.ut_id, buf, sizeof(ux.ut_id));
422    }
423#endif /* __sgi */
424    ux.ut_pid = pid;
425    if (strcmp(user, "") == 0)
426      ux.ut_type = DEAD_PROCESS;
427    else
428      ux.ut_type = USER_PROCESS;
429#ifdef HAVE_NO_TZ_IN_GETTIMEOFDAY
430    gettimeofday(&ux.ut_tv);
431#else
432    gettimeofday(&ux.ut_tv, NULL);
433#endif
434    ux.ut_session = pid;
435    strncpy(ux.ut_host, host, sizeof(ux.ut_host));
436    ux.ut_host[sizeof(ux.ut_host) - 1] = 0;
437    ux.ut_syslen = strlen(ux.ut_host);
438#ifdef HAVE_SYSLEN_IN_UTMPX
439    ux.ut_syslen = strlen(ux.ut_host);
440#endif
441    ux.ut_exit.e_termination = 0;
442    ux.ut_exit.e_exit = 0;
443#ifdef HAVE_MAKEUTX
444    /*
445     * modutx/makeutx notify init(1) to clean up utmpx for this pid
446     * automatically if we don't manage to, for some odd reason
447     */
448    if (strcmp(user, "") == 0)
449        modutx(&ux);
450    else
451        makeutx(&ux);
452#else
453    pututxline(&ux);
454    updwtmpx(WTMPX_FILE, &ux);
455#endif
456    endutxent();
457  }
458#endif /* HAVE_UTMPX_H */
459
460#if defined(HAVE_LASTLOG_H) || defined(HAVE_LASTLOG)
461
462#ifdef _PATH_LASTLOG
463  lastlog = _PATH_LASTLOG;
464#else
465#ifdef LASTLOG_FILE
466  lastlog = LASTLOG_FILE;
467#else
468  lastlog = SSH_LASTLOG;
469#endif
470#endif
471
472  /* Update lastlog unless actually recording a logout. */
473  if (strcmp(user, "") != 0)
474    {
475      /* It is safer to bzero the lastlog structure first because some
476         systems might have some extra fields in it (e.g. SGI) */
477      memset(&ll, 0, sizeof(ll));
478
479      /* Update lastlog. */
480      ll.ll_time = time(NULL);
481      strncpy(ll.ll_line, ttyname + 5, sizeof(ll.ll_line));
482      strncpy(ll.ll_host, host, sizeof(ll.ll_host));
483#ifdef LASTLOG_IS_DIR
484      sprintf(lastlogfile, "%.100s/%.100s", lastlog, user);
485      fd = open(lastlogfile, O_WRONLY | O_CREAT, 0644);
486      if (fd >= 0)
487        {
488          if (write(fd, &ll, sizeof(ll)) != sizeof(ll))
489            log_msg("Could not write %.100s: %.100s",
490                lastlogfile, strerror(errno));
491          close(fd);
492        }
493      else
494        {
495          log_msg("Could not open %.100s: %.100s", lastlogfile, strerror(errno));
496        }
497#else /* LASTLOG_IS_DIR */
498      fd = open(lastlog, O_RDWR);
499      if (fd >= 0)
500        {
501          lseek(fd, (off_t)((long)uid * sizeof(ll)), 0);
502          if (write(fd, &ll, sizeof(ll)) != sizeof(ll))
503            log_msg("Could not write %.100s: %.100s", lastlog, strerror(errno));
504          close(fd);
505        }
506#endif /* LASTLOG_IS_DIR */
507    }
508#endif /* HAVE_LASTLOG_H || HAVE_LASTLOG */
509
510#ifdef HAVE_HPUX_TCB_AUTH
511  {
512    struct pr_passwd *pr;
513   
514    pr = getprpwnam(user);
515    if (pr)
516      {
517        pr->ufld.fd_slogin = time(NULL);
518        pr->uflg.fg_slogin = 1; pr->uflg.fg_suctty = 1;
519        pr->ufld.fd_nlogins = 0;
520        strncpy(pr->ufld.fd_suctty, ttyname + 5, sizeof(pr->ufld.fd_suctty));
521        if (putprpwnam(user, pr) == 0)
522          log_msg("putprpwnam failed for %.100s",user);
523      }
524  }
525#endif /* HAVE_HPUX_TCB_AUTH */
526
527#ifdef HAVE_USERSEC_H
528
529  if (strcmp(user, "") != 0)
530    {
531      int lasttime = time(NULL);
532      if (setuserdb(S_WRITE) < 0)
533        log_msg("setuserdb S_WRITE failed: %.100s", strerror(errno));
534      if (putuserattr((char *)user, S_LASTTIME, (void *)lasttime, SEC_INT) < 0)
535        log_msg("putuserattr S_LASTTIME failed: %.100s", strerror(errno));
536      if (putuserattr((char *)user, S_LASTTTY, (void *)(ttyname + 5),
537                      SEC_CHAR) < 0)
538        log_msg("putuserattr S_LASTTTY %.900s failed: %.100s",
539            ttyname, strerror(errno));
540      if (putuserattr((char *)user, S_LASTHOST, (void *)host, SEC_CHAR) < 0)
541        log_msg("putuserattr S_LASTHOST %.900s failed: %.100s",
542            host, strerror(errno));
543      if (putuserattr((char *)user, 0, NULL, SEC_COMMIT) < 0)
544        log_msg("putuserattr SEC_COMMIT failed: %.100s", strerror(errno));
545      if (enduserdb() < 0)
546        log_msg("enduserdb failed: %.100s", strerror(errno));
547    }
548#endif   
549}
550 
551/* Records that the user has logged out. */
552
553void record_logout(int pid, const char *ttyname)
554{
555#ifdef HAVE_LIBUTIL_LOGIN
556  const char *line = ttyname + 5; /* /dev/ttyq8 -> ttyq8 */
557  if (logout(line))
558    logwtmp(line, "", "");
559#else /* HAVE_LIBUTIL_LOGIN */
560  record_login(pid, ttyname, "", -1, "", NULL);
561#endif /* HAVE_LIBUTIL_LOGIN */ 
562}
Note: See TracBrowser for help on using the repository browser.