1 /* Copyright (C) 1996-2021 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 #include <assert.h>
19 #include <errno.h>
20 #include <limits.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <stdlib.h>
24 #include <utmp.h>
25 #include <shlib-compat.h>
26 
27 /* Return the result of ttyname in the buffer pointed to by TTY, which should
28    be of length BUF_LEN.  If it is too long to fit in this buffer, a
29    sufficiently long buffer is allocated using malloc, and returned in TTY.
30    0 is returned upon success, -1 otherwise.  */
31 static int
tty_name(int fd,char ** tty,size_t buf_len)32 tty_name (int fd, char **tty, size_t buf_len)
33 {
34   int rv;			/* Return value.  0 = success.  */
35   char *buf = *tty;		/* Buffer for ttyname, initially the user's. */
36 
37   for (;;)
38     {
39       char *new_buf;
40 
41       if (buf_len)
42 	{
43 	  rv = __ttyname_r (fd, buf, buf_len);
44 
45 	  if (rv != 0 || memchr (buf, '\0', buf_len))
46 	    /* We either got an error, or we succeeded and the
47 	       returned name fit in the buffer.  */
48 	    break;
49 
50 	  /* Try again with a longer buffer.  */
51 	  buf_len += buf_len;	/* Double it */
52 	}
53       else
54 	/* No initial buffer; start out by mallocing one.  */
55 	buf_len = 128;		/* First time guess.  */
56 
57       if (buf != *tty)
58 	/* We've already malloced another buffer at least once.  */
59 	new_buf = realloc (buf, buf_len);
60       else
61 	new_buf = malloc (buf_len);
62       if (! new_buf)
63 	{
64 	  rv = -1;
65 	  __set_errno (ENOMEM);
66 	  break;
67 	}
68       buf = new_buf;
69     }
70 
71   if (rv == 0)
72     *tty = buf;		/* Return buffer to the user.  */
73   else if (buf != *tty)
74     free (buf);		/* Free what we malloced when returning an error.  */
75 
76   return rv;
77 }
78 
79 void
__login(const struct utmp * ut)80 __login (const struct utmp *ut)
81 {
82 #ifdef PATH_MAX
83   char _tty[PATH_MAX + UT_LINESIZE];
84 #else
85   char _tty[512 + UT_LINESIZE];
86 #endif
87   char *tty = _tty;
88   int found_tty;
89   const char *ttyp;
90   struct utmp copy = *ut;
91 
92   /* Fill in those fields we supply.  */
93   copy.ut_type = USER_PROCESS;
94   copy.ut_pid = getpid ();
95 
96   /* Seek tty.  */
97   found_tty = tty_name (STDIN_FILENO, &tty, sizeof (_tty));
98   if (found_tty < 0)
99     found_tty = tty_name (STDOUT_FILENO, &tty, sizeof (_tty));
100   if (found_tty < 0)
101     found_tty = tty_name (STDERR_FILENO, &tty, sizeof (_tty));
102 
103   if (found_tty >= 0)
104     {
105       /* We only want to insert the name of the tty without path.
106 	 But take care of name like /dev/pts/3.  */
107       if (strncmp (tty, "/dev/", 5) == 0)
108 	ttyp = tty + 5;		/* Skip the "/dev/".  */
109       else
110 	ttyp = basename (tty);
111 
112       /* Position to record for this tty.  */
113       strncpy (copy.ut_line, ttyp, UT_LINESIZE);
114 
115       /* Tell that we want to use the UTMP file.  */
116       if (__utmpname (_PATH_UTMP) == 0)
117 	{
118 	  /* Open UTMP file.  */
119 	  __setutent ();
120 
121 	  /* Write the entry.  */
122 	  __pututline (&copy);
123 
124 	  /* Close UTMP file.  */
125 	  __endutent ();
126 	}
127 
128       if (tty != _tty)
129 	free (tty);		/* Free buffer malloced by tty_name.  */
130     }
131   else
132     /* We provide a default value so that the output does not contain
133        an random bytes in this field.  */
134     strncpy (copy.ut_line, "???", UT_LINESIZE);
135 
136   /* Update the WTMP file.  Here we have to add a new entry.  */
137   __updwtmp (_PATH_WTMP, &copy);
138 }
139 versioned_symbol (libc, __login, login, GLIBC_2_34);
140 libc_hidden_ver (__login, login)
141 
142 #if OTHER_SHLIB_COMPAT (libutil, GLIBC_2_0, GLIBC_2_34)
143 compat_symbol (libutil, __login, login, GLIBC_2_0);
144 #endif
145