2 * Copyright (c) 2017 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 #include <Shlobj.h> // need to include definitions of constants
39 #define SECURITY_WIN32
42 #include <sys/types.h>
48 * Returns the user's SHELL.
50 ROKEN_LIB_FUNCTION
char * ROKEN_LIB_CALL
51 roken_get_shell(char *shell
, size_t shellsz
)
57 const char *username
= roken_get_username(user
, sizeof(user
));
60 if (sysconf(_SC_GETPW_R_SIZE_MAX
) > 0)
61 buflen
= sysconf(_SC_GETPW_R_SIZE_MAX
);
66 p
= secure_getenv("SHELL");
67 if (p
!= NULL
&& p
[0] != '\0') {
68 if (strlcpy(shell
, p
, shellsz
) < shellsz
)
74 #ifdef HAVE_GETPWNAM_R
80 if (getpwnam_r(username
, &pwd
, buf
, buflen
, &pwdp
) == 0 &&
81 pwdp
!= NULL
&& pwdp
->pw_shell
!= NULL
) {
82 if (strlcpy(shell
, pwdp
->pw_shell
, shellsz
) < shellsz
)
94 if (p
!= NULL
&& p
[0] != '\0') {
95 if (strlcpy(shell
, p
, shellsz
) < shellsz
)
106 * Returns the home directory.
108 ROKEN_LIB_FUNCTION
char * ROKEN_LIB_CALL
109 roken_get_homedir(char *home
, size_t homesz
)
114 if (homesz
< MAX_PATH
) {
119 if (SUCCEEDED(SHGetFolderPath(NULL
, CSIDL_PROFILE
, NULL
,
120 SHGFP_TYPE_CURRENT
, home
)))
123 if ((p
= getenv("HOMEDRIVE")) != NULL
&& p
[0] != '\0') {
124 if (strlcpy(home
, p
, homesz
) >= homesz
) {
128 if ((p
= getenv("HOMEPATH")) != NULL
) {
129 if (strlcat(home
, p
, homesz
) < homesz
)
136 /* Fallthru to return NULL */
139 const char *username
= roken_get_username(user
, sizeof(user
));
140 size_t buflen
= 2048;
142 if (sysconf(_SC_GETPW_R_SIZE_MAX
) > 0)
143 buflen
= sysconf(_SC_GETPW_R_SIZE_MAX
);
150 p
= secure_getenv("HOME");
151 if (p
!= NULL
&& p
[0] != '\0') {
152 if (strlcpy(home
, p
, homesz
) < homesz
)
158 #ifdef HAVE_GETPWNAM_R
164 if (getpwnam_r(username
, &pwd
, buf
, buflen
, &pwdp
) == 0 &&
165 pwdp
!= NULL
&& pwdp
->pw_dir
!= NULL
) {
166 if (strlcpy(home
, pwdp
->pw_dir
, homesz
) < homesz
)
179 * Returns the home directory on Unix, or the AppData directory on
182 ROKEN_LIB_FUNCTION
char * ROKEN_LIB_CALL
183 roken_get_appdatadir(char *appdata
, size_t appdatasz
)
190 return roken_get_homedir(appdata
, appdatasz
);
192 if (appdatasz
< MAX_PATH
) {
197 if (SUCCEEDED(SHGetFolderPath(NULL
, CSIDL_APPDATA
, NULL
,
198 SHGFP_TYPE_CURRENT
, appdata
)))
201 if ((p
= getenv("APPDATA")) != NULL
&& p
[0] != '\0') {
202 if (strlcpy(appdata
, p
, appdatasz
) < appdatasz
)
214 * Return a bare username. This is used for, e.g., constructing default
217 * On POSIX systems, if the caller is not set-uid-like, then this will return
218 * the value of the USER or LOGNAME environment variables (in that order of
219 * preference), else the username found by looking up the effective UID.
221 ROKEN_LIB_FUNCTION
char * ROKEN_LIB_CALL
222 roken_get_username(char *user
, size_t usersz
)
229 if (GetUserNameEx(NameSamCompatible
, user
, &sz
)) {
231 * There's no EXTENDED_NAME_FORMAT for "bare username". We we
234 p
= strchr(user
, '\\');
237 memmove(user
, p
, strlen(p
) + 1);
241 DWORD err
= GetLastError();
242 if (err
== ERROR_MORE_DATA
) {
246 /* %USERNAME% is generally bare */
247 p
= getenv("USERNAME");
248 if (p
!= NULL
&& p
[0] != '\0') {
249 if (strchr(p
, '\\') != NULL
)
250 p
= strchr(p
, '\\') + 1;
251 if (strlcpy(user
, p
, usersz
) < usersz
)
258 size_t buflen
= 2048;
260 p
= secure_getenv("USER");
261 if (p
== NULL
|| p
[0] == '\0')
262 p
= secure_getenv("LOGNAME");
263 if (p
!= NULL
&& p
[0] != '\0') {
264 if (strlcpy(user
, p
, usersz
) < usersz
)
270 #ifdef HAVE_GETPWUID_R
271 if (sysconf(_SC_GETPW_R_SIZE_MAX
) > 0)
272 buflen
= sysconf(_SC_GETPW_R_SIZE_MAX
);
279 if (getpwuid_r(getuid(), &pwd
, buf
, buflen
, &pwdp
) == 0 &&
280 pwdp
!= NULL
&& pwdp
->pw_name
!= NULL
) {
281 if (strlcpy(user
, pwdp
->pw_name
, usersz
) < usersz
)
294 * Return a bare username. This is used for, e.g., constructing default
297 * On POSIX systems this returns the name recorded in the system as currently
298 * logged in on the current terminal.
300 ROKEN_LIB_FUNCTION
char * ROKEN_LIB_CALL
301 roken_get_loginname(char *user
, size_t usersz
)
304 return roken_get_username(user
, usersz
);
306 #ifdef HAVE_GETLOGIN_R
307 if ((errno
= getlogin_r(user
, usersz
)) == 0)
313 if ((p
= getlogin()) != NULL
&& p
[0] != '\0') {
314 if (strlcpy(user
, p
, usersz
) < usersz
)