1 /* Copyright (C) 2010-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 <pwd.h>
19 #include <unistd.h>
20 #include <not-cancel.h>
21 #include <scratch_buffer.h>
22 
23 #define STATIC static
24 static int getlogin_r_fd0 (char *name, size_t namesize);
25 #define __getlogin_r getlogin_r_fd0
26 #include <sysdeps/unix/getlogin_r.c>
27 #undef __getlogin_r
28 
29 
30 /* Try to determine login name from /proc/self/loginuid and return 0
31    if successful.  If /proc/self/loginuid cannot be read return -1.
32    Otherwise return the error number.  */
33 
34 int
35 attribute_hidden
__getlogin_r_loginuid(char * name,size_t namesize)36 __getlogin_r_loginuid (char *name, size_t namesize)
37 {
38   int fd = __open_nocancel ("/proc/self/loginuid", O_RDONLY);
39   if (fd == -1)
40     return -1;
41 
42   /* We are reading a 32-bit number.  12 bytes are enough for the text
43      representation.  If not, something is wrong.  */
44   char uidbuf[12];
45   ssize_t n = TEMP_FAILURE_RETRY (__read_nocancel (fd, uidbuf,
46 						   sizeof (uidbuf)));
47   __close_nocancel_nostatus (fd);
48 
49   uid_t uid;
50   char *endp;
51   if (n <= 0
52       || n == sizeof (uidbuf)
53       || (uidbuf[n] = '\0',
54 	  uid = strtoul (uidbuf, &endp, 10),
55 	  endp == uidbuf || *endp != '\0'))
56     return -1;
57 
58   /* If there is no login uid, linux sets /proc/self/loginid to the sentinel
59      value of, (uid_t) -1, so check if that value is set and return early to
60      avoid making unneeded nss lookups. */
61   if (uid == (uid_t) -1)
62     {
63       __set_errno (ENXIO);
64       return ENXIO;
65     }
66 
67   struct passwd pwd;
68   struct passwd *tpwd;
69   int result = 0;
70   int res;
71   struct scratch_buffer tmpbuf;
72   scratch_buffer_init (&tmpbuf);
73 
74   while ((res =  __getpwuid_r (uid, &pwd,
75 			       tmpbuf.data, tmpbuf.length, &tpwd)) == ERANGE)
76     {
77       if (!scratch_buffer_grow (&tmpbuf))
78 	{
79 	  result = ENOMEM;
80 	  goto out;
81 	}
82     }
83 
84   if (res != 0 || tpwd == NULL)
85     {
86       result = -1;
87       goto out;
88     }
89 
90   size_t needed = strlen (pwd.pw_name) + 1;
91   if (needed > namesize)
92     {
93       __set_errno (ERANGE);
94       result = ERANGE;
95       goto out;
96     }
97 
98   memcpy (name, pwd.pw_name, needed);
99 
100  out:
101   scratch_buffer_free (&tmpbuf);
102   return result;
103 }
104 
105 
106 /* Return at most NAME_LEN characters of the login name of the user in NAME.
107    If it cannot be determined or some other error occurred, return the error
108    code.  Otherwise return 0.  */
109 
110 int
__getlogin_r(char * name,size_t namesize)111 __getlogin_r (char *name, size_t namesize)
112 {
113   int res = __getlogin_r_loginuid (name, namesize);
114   if (res >= 0)
115     return res;
116 
117   return getlogin_r_fd0 (name, namesize);
118 }
119 libc_hidden_def (__getlogin_r)
120 weak_alias (__getlogin_r, getlogin_r)
121 libc_hidden_weak (getlogin_r)
122