1/* Copyright (C) 2010-2022 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
24static 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
34int
35attribute_hidden
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 (buffer: &tmpbuf);
73
74 while ((res = __getpwuid_r (uid: uid, resultbuf: &pwd,
75 buffer: tmpbuf.data, buflen: tmpbuf.length, result: &tpwd)) == ERANGE)
76 {
77 if (!scratch_buffer_grow (buffer: &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 (buffer: &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
110int
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, name_len: namesize);
118}
119libc_hidden_def (__getlogin_r)
120weak_alias (__getlogin_r, getlogin_r)
121libc_hidden_weak (getlogin_r)
122

source code of glibc/sysdeps/unix/sysv/linux/getlogin_r.c