Since these functions are only used internally, we can make sure they are being used correctly, and assert() helps in catching remaining issues. Usage of each changed function has been reviewed: For xgetpwnam: - chsh(1) only calls it if a username has been set - login(1) only calls it if username has been set and is not empty - su(1) always initializes new_user to "root" - unshare(1) calls get_user with optarg, so always set as well For xgetgrnam: - unshare(1) calls get_group with optarg For xgetpwuid: - chsh(1) passes a stack allocated struct for struct passwd Signed-off-by: Érico Nogueira <erico.erc@gmail.com>
158 lines
3.2 KiB
C
158 lines
3.2 KiB
C
/*
|
|
* No copyright is claimed. This code is in the public domain; do with
|
|
* it what you wish.
|
|
*/
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
|
|
#include "c.h"
|
|
#include "pwdutils.h"
|
|
#include "xalloc.h"
|
|
|
|
/* Returns allocated passwd and allocated pwdbuf to store passwd strings
|
|
* fields. In case of error returns NULL and set errno, for unknown user set
|
|
* errno to EINVAL
|
|
*/
|
|
struct passwd *xgetpwnam(const char *username, char **pwdbuf)
|
|
{
|
|
struct passwd *pwd = NULL, *res = NULL;
|
|
int rc;
|
|
|
|
assert(pwdbuf);
|
|
assert(username);
|
|
|
|
*pwdbuf = xmalloc(UL_GETPW_BUFSIZ);
|
|
pwd = xcalloc(1, sizeof(struct passwd));
|
|
|
|
errno = 0;
|
|
rc = getpwnam_r(username, pwd, *pwdbuf, UL_GETPW_BUFSIZ, &res);
|
|
if (rc != 0) {
|
|
errno = rc;
|
|
goto failed;
|
|
}
|
|
if (!res) {
|
|
errno = EINVAL;
|
|
goto failed;
|
|
}
|
|
return pwd;
|
|
failed:
|
|
free(pwd);
|
|
free(*pwdbuf);
|
|
return NULL;
|
|
}
|
|
|
|
/* Returns allocated group and allocated grpbuf to store group strings
|
|
* fields. In case of error returns NULL and set errno, for unknown group set
|
|
* errno to EINVAL
|
|
*/
|
|
struct group *xgetgrnam(const char *groupname, char **grpbuf)
|
|
{
|
|
struct group *grp = NULL, *res = NULL;
|
|
int rc;
|
|
|
|
assert(grpbuf);
|
|
assert(groupname);
|
|
|
|
*grpbuf = xmalloc(UL_GETPW_BUFSIZ);
|
|
grp = xcalloc(1, sizeof(struct group));
|
|
|
|
errno = 0;
|
|
rc = getgrnam_r(groupname, grp, *grpbuf, UL_GETPW_BUFSIZ, &res);
|
|
if (rc != 0) {
|
|
errno = rc;
|
|
goto failed;
|
|
}
|
|
if (!res) {
|
|
errno = EINVAL;
|
|
goto failed;
|
|
}
|
|
return grp;
|
|
failed:
|
|
free(grp);
|
|
free(*grpbuf);
|
|
return NULL;
|
|
}
|
|
|
|
struct passwd *xgetpwuid(uid_t uid, char **pwdbuf)
|
|
{
|
|
struct passwd *pwd = NULL, *res = NULL;
|
|
int rc;
|
|
|
|
assert(pwdbuf);
|
|
|
|
*pwdbuf = xmalloc(UL_GETPW_BUFSIZ);
|
|
pwd = xcalloc(1, sizeof(struct passwd));
|
|
|
|
errno = 0;
|
|
rc = getpwuid_r(uid, pwd, *pwdbuf, UL_GETPW_BUFSIZ, &res);
|
|
if (rc != 0) {
|
|
errno = rc;
|
|
goto failed;
|
|
}
|
|
if (!res) {
|
|
errno = EINVAL;
|
|
goto failed;
|
|
}
|
|
return pwd;
|
|
failed:
|
|
free(pwd);
|
|
free(*pwdbuf);
|
|
return NULL;
|
|
}
|
|
|
|
char *xgetlogin(void)
|
|
{
|
|
struct passwd *pw = NULL;
|
|
uid_t ruid;
|
|
|
|
/* GNU Hurd implementation has an extension where a process can exist in a
|
|
* non-conforming environment, and thus be outside the realms of POSIX
|
|
* process identifiers; on this platform, getuid() fails with a status of
|
|
* (uid_t)(-1) and sets errno if a program is run from a non-conforming
|
|
* environment.
|
|
*
|
|
* http://austingroupbugs.net/view.php?id=511
|
|
*
|
|
* The same implementation is useful for other systems, since getlogin(3)
|
|
* shouldn't be used as actual identification.
|
|
*/
|
|
errno = 0;
|
|
ruid = getuid();
|
|
|
|
if (errno == 0)
|
|
pw = getpwuid(ruid);
|
|
if (pw && pw->pw_name && *pw->pw_name)
|
|
return xstrdup(pw->pw_name);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef TEST_PROGRAM
|
|
int main(int argc, char *argv[])
|
|
{
|
|
char *buf = NULL;
|
|
struct passwd *pwd = NULL;
|
|
|
|
if (argc != 2) {
|
|
fprintf(stderr, "usage: %s <username>\n", argv[0]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
pwd = xgetpwnam(argv[1], &buf);
|
|
if (!pwd)
|
|
err(EXIT_FAILURE, "failed to get %s pwd entry", argv[1]);
|
|
|
|
printf("Username: %s\n", pwd->pw_name);
|
|
printf("UID: %d\n", pwd->pw_uid);
|
|
printf("HOME: %s\n", pwd->pw_dir);
|
|
printf("GECO: %s\n", pwd->pw_gecos);
|
|
|
|
free(pwd);
|
|
free(buf);
|
|
|
|
printf("Current: %s\n", (buf = xgetlogin()));
|
|
free(buf);
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
#endif /* TEST_PROGRAM */
|