1/* Copyright (C) 2010-2024 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 return -1;
63
64 struct passwd pwd;
65 struct passwd *tpwd;
66 int result = 0;
67 int res;
68 struct scratch_buffer tmpbuf;
69 scratch_buffer_init (buffer: &tmpbuf);
70
71 while ((res = __getpwuid_r (uid: uid, resultbuf: &pwd,
72 buffer: tmpbuf.data, buflen: tmpbuf.length, result: &tpwd)) == ERANGE)
73 {
74 if (!scratch_buffer_grow (buffer: &tmpbuf))
75 {
76 result = ENOMEM;
77 goto out;
78 }
79 }
80
81 if (res != 0 || tpwd == NULL)
82 {
83 result = -1;
84 goto out;
85 }
86
87 size_t needed = strlen (pwd.pw_name) + 1;
88 if (needed > namesize)
89 {
90 __set_errno (ERANGE);
91 result = ERANGE;
92 goto out;
93 }
94
95 memcpy (name, pwd.pw_name, needed);
96
97 out:
98 scratch_buffer_free (buffer: &tmpbuf);
99 return result;
100}
101
102
103/* Return at most NAME_LEN characters of the login name of the user in NAME.
104 If it cannot be determined or some other error occurred, return the error
105 code. Otherwise return 0. */
106
107int
108__getlogin_r (char *name, size_t namesize)
109{
110 int res = __getlogin_r_loginuid (name, namesize);
111 if (res >= 0)
112 return res;
113
114 return getlogin_r_fd0 (name, name_len: namesize);
115}
116libc_hidden_def (__getlogin_r)
117weak_alias (__getlogin_r, getlogin_r)
118libc_hidden_weak (getlogin_r)
119

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