user-util: add new wrappers for reading/writing {passwd,shadow,gshadow} database files (#8521)
The API povided by the glibc is too error-prone as one has to deal directly with errno in order to detect if errors occured. Suggested by Zbigniew.
This commit is contained in:
parent
ed47df8967
commit
100d5f6ee6
|
@ -734,3 +734,123 @@ bool synthesize_nobody(void) {
|
||||||
return cache;
|
return cache;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int putpwent_sane(const struct passwd *pw, FILE *stream) {
|
||||||
|
assert(pw);
|
||||||
|
assert(stream);
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
if (putpwent(pw, stream) != 0)
|
||||||
|
return errno > 0 ? -errno : -EIO;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int putspent_sane(const struct spwd *sp, FILE *stream) {
|
||||||
|
assert(sp);
|
||||||
|
assert(stream);
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
if (putspent(sp, stream) != 0)
|
||||||
|
return errno > 0 ? -errno : -EIO;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int putgrent_sane(const struct group *gr, FILE *stream) {
|
||||||
|
assert(gr);
|
||||||
|
assert(stream);
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
if (putgrent(gr, stream) != 0)
|
||||||
|
return errno > 0 ? -errno : -EIO;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GSHADOW
|
||||||
|
int putsgent_sane(const struct sgrp *sg, FILE *stream) {
|
||||||
|
assert(sg);
|
||||||
|
assert(stream);
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
if (putsgent(sg, stream) != 0)
|
||||||
|
return errno > 0 ? -errno : -EIO;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int fgetpwent_sane(FILE *stream, struct passwd **pw) {
|
||||||
|
struct passwd *p;
|
||||||
|
|
||||||
|
assert(pw);
|
||||||
|
assert(stream);
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
p = fgetpwent(stream);
|
||||||
|
if (p == NULL) {
|
||||||
|
if (errno == ENOENT)
|
||||||
|
return false;
|
||||||
|
return errno > 0 ? -errno : -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pw = p;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fgetspent_sane(FILE *stream, struct spwd **sp) {
|
||||||
|
struct spwd *s;
|
||||||
|
|
||||||
|
assert(sp);
|
||||||
|
assert(stream);
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
s = fgetspent(stream);
|
||||||
|
if (s == NULL) {
|
||||||
|
if (errno == ENOENT)
|
||||||
|
return false;
|
||||||
|
return errno > 0 ? -errno : -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
*sp = s;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fgetgrent_sane(FILE *stream, struct group **gr) {
|
||||||
|
struct group *g;
|
||||||
|
|
||||||
|
assert(gr);
|
||||||
|
assert(stream);
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
g = fgetgrent(stream);
|
||||||
|
if (g == NULL) {
|
||||||
|
if (errno == ENOENT)
|
||||||
|
return false;
|
||||||
|
return errno > 0 ? -errno : -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
*gr = g;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ENABLE_GSHADOW
|
||||||
|
int fgetsgent_sane(FILE *stream, struct sgrp **sg) {
|
||||||
|
struct sgrp *s;
|
||||||
|
|
||||||
|
assert(sg);
|
||||||
|
assert(stream);
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
s = fgetsgent(stream);
|
||||||
|
if (s == NULL) {
|
||||||
|
if (errno == ENOENT)
|
||||||
|
return false;
|
||||||
|
return errno > 0 ? -errno : -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
*sg = s;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -20,6 +20,10 @@
|
||||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||||
***/
|
***/
|
||||||
|
|
||||||
|
#include <grp.h>
|
||||||
|
#include <gshadow.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <shadow.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
@ -110,3 +114,14 @@ static inline bool valid_shell(const char *p) {
|
||||||
int maybe_setgroups(size_t size, const gid_t *list);
|
int maybe_setgroups(size_t size, const gid_t *list);
|
||||||
|
|
||||||
bool synthesize_nobody(void);
|
bool synthesize_nobody(void);
|
||||||
|
|
||||||
|
int fgetpwent_sane(FILE *stream, struct passwd **pw);
|
||||||
|
int fgetspent_sane(FILE *stream, struct spwd **sp);
|
||||||
|
int fgetgrent_sane(FILE *stream, struct group **gr);
|
||||||
|
int putpwent_sane(const struct passwd *pw, FILE *stream);
|
||||||
|
int putspent_sane(const struct spwd *sp, FILE *stream);
|
||||||
|
int putgrent_sane(const struct group *gr, FILE *stream);
|
||||||
|
#ifdef ENABLE_GSHADOW
|
||||||
|
int fgetsgent_sane(FILE *stream, struct sgrp **sg);
|
||||||
|
int putsgent_sane(const struct sgrp *sg, FILE *stream);
|
||||||
|
#endif
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <shadow.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#ifdef HAVE_CRYPT_H
|
#ifdef HAVE_CRYPT_H
|
||||||
|
@ -586,6 +585,8 @@ static int prompt_root_password(void) {
|
||||||
|
|
||||||
static int write_root_shadow(const char *path, const struct spwd *p) {
|
static int write_root_shadow(const char *path, const struct spwd *p) {
|
||||||
_cleanup_fclose_ FILE *f = NULL;
|
_cleanup_fclose_ FILE *f = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(path);
|
assert(path);
|
||||||
assert(p);
|
assert(p);
|
||||||
|
|
||||||
|
@ -594,9 +595,9 @@ static int write_root_shadow(const char *path, const struct spwd *p) {
|
||||||
if (!f)
|
if (!f)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
errno = 0;
|
r = putspent_sane(p, f);
|
||||||
if (putspent(p, f) != 0)
|
if (r < 0)
|
||||||
return errno > 0 ? -errno : -EIO;
|
return r;
|
||||||
|
|
||||||
return fflush_sync_and_check(f);
|
return fflush_sync_and_check(f);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,10 +19,6 @@
|
||||||
***/
|
***/
|
||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <grp.h>
|
|
||||||
#include <gshadow.h>
|
|
||||||
#include <pwd.h>
|
|
||||||
#include <shadow.h>
|
|
||||||
#include <utmp.h>
|
#include <utmp.h>
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
|
@ -113,8 +109,7 @@ static int load_user_database(void) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
errno = 0;
|
while ((r = fgetpwent_sane(f, &pw)) > 0) {
|
||||||
while ((pw = fgetpwent(f))) {
|
|
||||||
char *n;
|
char *n;
|
||||||
int k, q;
|
int k, q;
|
||||||
|
|
||||||
|
@ -137,13 +132,8 @@ static int load_user_database(void) {
|
||||||
|
|
||||||
if (q < 0 && k < 0)
|
if (q < 0 && k < 0)
|
||||||
free(n);
|
free(n);
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
}
|
}
|
||||||
if (!IN_SET(errno, 0, ENOENT))
|
return r;
|
||||||
return -errno;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int load_group_database(void) {
|
static int load_group_database(void) {
|
||||||
|
@ -287,6 +277,7 @@ static int putgrent_with_members(const struct group *gr, FILE *group) {
|
||||||
|
|
||||||
if (added) {
|
if (added) {
|
||||||
struct group t;
|
struct group t;
|
||||||
|
int r;
|
||||||
|
|
||||||
strv_uniq(l);
|
strv_uniq(l);
|
||||||
strv_sort(l);
|
strv_sort(l);
|
||||||
|
@ -294,19 +285,12 @@ static int putgrent_with_members(const struct group *gr, FILE *group) {
|
||||||
t = *gr;
|
t = *gr;
|
||||||
t.gr_mem = l;
|
t.gr_mem = l;
|
||||||
|
|
||||||
errno = 0;
|
r = putgrent_sane(&t, group);
|
||||||
if (putgrent(&t, group) != 0)
|
return r < 0 ? r : 1;
|
||||||
return errno > 0 ? -errno : -EIO;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = 0;
|
return putgrent_sane(gr, group);
|
||||||
if (putgrent(gr, group) != 0)
|
|
||||||
return errno > 0 ? -errno : -EIO;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLE_GSHADOW
|
#if ENABLE_GSHADOW
|
||||||
|
@ -338,6 +322,7 @@ static int putsgent_with_members(const struct sgrp *sg, FILE *gshadow) {
|
||||||
|
|
||||||
if (added) {
|
if (added) {
|
||||||
struct sgrp t;
|
struct sgrp t;
|
||||||
|
int r;
|
||||||
|
|
||||||
strv_uniq(l);
|
strv_uniq(l);
|
||||||
strv_sort(l);
|
strv_sort(l);
|
||||||
|
@ -345,19 +330,12 @@ static int putsgent_with_members(const struct sgrp *sg, FILE *gshadow) {
|
||||||
t = *sg;
|
t = *sg;
|
||||||
t.sg_mem = l;
|
t.sg_mem = l;
|
||||||
|
|
||||||
errno = 0;
|
r = putsgent_sane(&t, gshadow);
|
||||||
if (putsgent(&t, gshadow) != 0)
|
return r < 0 ? r : 1;
|
||||||
return errno > 0 ? -errno : -EIO;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = 0;
|
return putsgent_sane(sg, gshadow);
|
||||||
if (putsgent(sg, gshadow) != 0)
|
|
||||||
return errno > 0 ? -errno : -EIO;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -415,8 +393,7 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
errno = 0;
|
while ((r = fgetpwent_sane(original, &pw)) > 0) {
|
||||||
while ((pw = fgetpwent(original))) {
|
|
||||||
|
|
||||||
i = ordered_hashmap_get(users, pw->pw_name);
|
i = ordered_hashmap_get(users, pw->pw_name);
|
||||||
if (i && i->todo_user) {
|
if (i && i->todo_user) {
|
||||||
|
@ -429,19 +406,16 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char
|
||||||
return -EEXIST;
|
return -EEXIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
|
|
||||||
/* Make sure we keep the NIS entries (if any) at the end. */
|
/* Make sure we keep the NIS entries (if any) at the end. */
|
||||||
if (IN_SET(pw->pw_name[0], '+', '-'))
|
if (IN_SET(pw->pw_name[0], '+', '-'))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (putpwent(pw, passwd) < 0)
|
r = putpwent_sane(pw, passwd);
|
||||||
return errno ? -errno : -EIO;
|
if (r < 0)
|
||||||
|
return r;
|
||||||
errno = 0;
|
|
||||||
}
|
}
|
||||||
if (!IN_SET(errno, 0, ENOENT))
|
if (r < 0)
|
||||||
return -errno;
|
return r;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
|
@ -468,23 +442,23 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char
|
||||||
.pw_shell = i->shell ?: (char*) default_shell(i->uid),
|
.pw_shell = i->shell ?: (char*) default_shell(i->uid),
|
||||||
};
|
};
|
||||||
|
|
||||||
errno = 0;
|
r = putpwent_sane(&n, passwd);
|
||||||
if (putpwent(&n, passwd) != 0)
|
if (r < 0)
|
||||||
return errno ? -errno : -EIO;
|
return r;
|
||||||
}
|
}
|
||||||
errno = 0;
|
|
||||||
|
|
||||||
/* Append the remaining NIS entries if any */
|
/* Append the remaining NIS entries if any */
|
||||||
while (pw) {
|
while (pw) {
|
||||||
errno = 0;
|
r = putpwent_sane(pw, passwd);
|
||||||
if (putpwent(pw, passwd) < 0)
|
if (r < 0)
|
||||||
return errno ? -errno : -EIO;
|
return r;
|
||||||
|
|
||||||
errno = 0;
|
r = fgetpwent_sane(original, &pw);
|
||||||
pw = fgetpwent(original);
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (!IN_SET(errno, 0, ENOENT))
|
|
||||||
return -errno;
|
|
||||||
|
|
||||||
r = fflush_and_check(passwd);
|
r = fflush_and_check(passwd);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -522,8 +496,7 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
errno = 0;
|
while ((r = fgetspent_sane(original, &sp)) > 0) {
|
||||||
while ((sp = fgetspent(original))) {
|
|
||||||
|
|
||||||
i = ordered_hashmap_get(users, sp->sp_namp);
|
i = ordered_hashmap_get(users, sp->sp_namp);
|
||||||
if (i && i->todo_user) {
|
if (i && i->todo_user) {
|
||||||
|
@ -536,19 +509,16 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char
|
||||||
ordered_hashmap_remove(todo_uids, UID_TO_PTR(i->uid));
|
ordered_hashmap_remove(todo_uids, UID_TO_PTR(i->uid));
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
|
|
||||||
/* Make sure we keep the NIS entries (if any) at the end. */
|
/* Make sure we keep the NIS entries (if any) at the end. */
|
||||||
if (IN_SET(sp->sp_namp[0], '+', '-'))
|
if (IN_SET(sp->sp_namp[0], '+', '-'))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (putspent(sp, shadow) < 0)
|
r = putspent_sane(sp, shadow);
|
||||||
return errno ? -errno : -EIO;
|
if (r < 0)
|
||||||
|
return r;
|
||||||
errno = 0;
|
|
||||||
}
|
}
|
||||||
if (!IN_SET(errno, 0, ENOENT))
|
if (r < 0)
|
||||||
return -errno;
|
return r;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
|
@ -570,20 +540,22 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char
|
||||||
.sp_flag = (unsigned long) -1, /* this appears to be what everybody does ... */
|
.sp_flag = (unsigned long) -1, /* this appears to be what everybody does ... */
|
||||||
};
|
};
|
||||||
|
|
||||||
errno = 0;
|
r = putspent_sane(&n, shadow);
|
||||||
if (putspent(&n, shadow) != 0)
|
if (r < 0)
|
||||||
return errno ? -errno : -EIO;
|
return r;
|
||||||
}
|
}
|
||||||
errno = 0;
|
|
||||||
|
|
||||||
/* Append the remaining NIS entries if any */
|
/* Append the remaining NIS entries if any */
|
||||||
while (sp) {
|
while (sp) {
|
||||||
errno = 0;
|
r = putspent_sane(sp, shadow);
|
||||||
if (putspent(sp, shadow) < 0)
|
if (r < 0)
|
||||||
return errno ? -errno : -EIO;
|
return r;
|
||||||
|
|
||||||
errno = 0;
|
r = fgetspent_sane(original, &sp);
|
||||||
sp = fgetspent(original);
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (!IN_SET(errno, 0, ENOENT))
|
if (!IN_SET(errno, 0, ENOENT))
|
||||||
return -errno;
|
return -errno;
|
||||||
|
@ -622,8 +594,7 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char **
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
errno = 0;
|
while ((r = fgetgrent_sane(original, &gr)) > 0) {
|
||||||
while ((gr = fgetgrent(original))) {
|
|
||||||
/* Safety checks against name and GID collisions. Normally,
|
/* Safety checks against name and GID collisions. Normally,
|
||||||
* this should be unnecessary, but given that we look at the
|
* this should be unnecessary, but given that we look at the
|
||||||
* entries anyway here, let's make an extra verification
|
* entries anyway here, let's make an extra verification
|
||||||
|
@ -640,8 +611,6 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char **
|
||||||
return -EEXIST;
|
return -EEXIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
|
|
||||||
/* Make sure we keep the NIS entries (if any) at the end. */
|
/* Make sure we keep the NIS entries (if any) at the end. */
|
||||||
if (IN_SET(gr->gr_name[0], '+', '-'))
|
if (IN_SET(gr->gr_name[0], '+', '-'))
|
||||||
break;
|
break;
|
||||||
|
@ -651,11 +620,9 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char **
|
||||||
return r;
|
return r;
|
||||||
if (r > 0)
|
if (r > 0)
|
||||||
group_changed = true;
|
group_changed = true;
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
}
|
}
|
||||||
if (!IN_SET(errno, 0, ENOENT))
|
if (r < 0)
|
||||||
return -errno;
|
return r;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
|
@ -677,19 +644,19 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char **
|
||||||
|
|
||||||
group_changed = true;
|
group_changed = true;
|
||||||
}
|
}
|
||||||
errno = 0;
|
|
||||||
|
|
||||||
/* Append the remaining NIS entries if any */
|
/* Append the remaining NIS entries if any */
|
||||||
while (gr) {
|
while (gr) {
|
||||||
errno = 0;
|
r = putgrent_sane(gr, group);
|
||||||
if (putgrent(gr, group) != 0)
|
if (r < 0)
|
||||||
return errno > 0 ? -errno : -EIO;
|
return r;
|
||||||
|
|
||||||
errno = 0;
|
r = fgetgrent_sane(original, &gr);
|
||||||
gr = fgetgrent(original);
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (!IN_SET(errno, 0, ENOENT))
|
|
||||||
return -errno;
|
|
||||||
|
|
||||||
r = fflush_sync_and_check(group);
|
r = fflush_sync_and_check(group);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -728,8 +695,7 @@ static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, ch
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
errno = 0;
|
while ((r = fgetsgent_sane(original, &sg)) > 0) {
|
||||||
while ((sg = fgetsgent(original))) {
|
|
||||||
|
|
||||||
i = ordered_hashmap_get(groups, sg->sg_namp);
|
i = ordered_hashmap_get(groups, sg->sg_namp);
|
||||||
if (i && i->todo_group) {
|
if (i && i->todo_group) {
|
||||||
|
@ -742,11 +708,9 @@ static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, ch
|
||||||
return r;
|
return r;
|
||||||
if (r > 0)
|
if (r > 0)
|
||||||
group_changed = true;
|
group_changed = true;
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
}
|
}
|
||||||
if (!IN_SET(errno, 0, ENOENT))
|
if (r < 0)
|
||||||
return -errno;
|
return r;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
|
|
Loading…
Reference in a new issue