Imported Upstream version 4.2

This commit is contained in:
Christian Perrier
2014-03-01 19:59:36 +01:00
parent db1dc7288b
commit 65b471a2f2
706 changed files with 46966 additions and 139295 deletions
+315 -8
View File
@@ -32,7 +32,7 @@
#include <config.h>
#ident "$Id: usermod.c 3650 2011-11-21 22:02:15Z nekral-guest $"
#ident "$Id$"
#include <ctype.h>
#include <errno.h>
@@ -63,6 +63,9 @@
#include "sgroupio.h"
#endif
#include "shadowio.h"
#ifdef ENABLE_SUBIDS
#include "subordinateio.h"
#endif /* ENABLE_SUBIDS */
#ifdef WITH_TCB
#include "tcbfuncs.h"
#endif
@@ -86,7 +89,13 @@
/* #define E_NOSPACE 11 insufficient space to move home dir */
#define E_HOMEDIR 12 /* unable to complete home dir move */
#define E_SE_UPDATE 13 /* can't update SELinux user mapping */
#ifdef ENABLE_SUBIDS
#define E_SUB_UID_UPDATE 16 /* can't update the subordinate uid file */
#define E_SUB_GID_UPDATE 18 /* can't update the subordinate gid file */
#endif /* ENABLE_SUBIDS */
#define VALID(s) (strcspn (s, ":\n") == strlen (s))
/*
* Global variables
*/
@@ -132,6 +141,12 @@ static bool
#ifdef WITH_SELINUX
Zflg = false, /* new selinux user */
#endif
#ifdef ENABLE_SUBIDS
vflg = false, /* add subordinate uids */
Vflg = false, /* delete subordinate uids */
wflg = false, /* add subordinate gids */
Wflg = false, /* delete subordinate gids */
#endif /* ENABLE_SUBIDS */
uflg = false, /* specify new user ID */
Uflg = false; /* unlock the password */
@@ -141,12 +156,21 @@ static bool is_shadow_pwd;
static bool is_shadow_grp;
#endif
#ifdef ENABLE_SUBIDS
static bool is_sub_uid = false;
static bool is_sub_gid = false;
#endif /* ENABLE_SUBIDS */
static bool pw_locked = false;
static bool spw_locked = false;
static bool gr_locked = false;
#ifdef SHADOWGRP
static bool sgr_locked = false;
#endif
#ifdef ENABLE_SUBIDS
static bool sub_uid_locked = false;
static bool sub_gid_locked = false;
#endif /* ENABLE_SUBIDS */
/* local function prototypes */
@@ -302,6 +326,71 @@ static int get_groups (char *list)
return 0;
}
#ifdef ENABLE_SUBIDS
struct ulong_range
{
unsigned long first;
unsigned long last;
};
static struct ulong_range getulong_range(const char *str)
{
struct ulong_range result = { .first = ULONG_MAX, .last = 0 };
long long first, last;
char *pos;
errno = 0;
first = strtoll(str, &pos, 10);
if (('\0' == *str) || ('-' != *pos ) || (ERANGE == errno) ||
(first != (unsigned long int)first))
goto out;
errno = 0;
last = strtoll(pos + 1, &pos, 10);
if (('\0' != *pos ) || (ERANGE == errno) ||
(last != (unsigned long int)last))
goto out;
if (first > last)
goto out;
result.first = (unsigned long int)first;
result.last = (unsigned long int)last;
out:
return result;
}
struct ulong_range_list_entry {
struct ulong_range_list_entry *next;
struct ulong_range range;
};
static struct ulong_range_list_entry *add_sub_uids = NULL, *del_sub_uids = NULL;
static struct ulong_range_list_entry *add_sub_gids = NULL, *del_sub_gids = NULL;
static int prepend_range(const char *str, struct ulong_range_list_entry **head)
{
struct ulong_range range;
struct ulong_range_list_entry *entry;
range = getulong_range(str);
if (range.first > range.last)
return 0;
entry = malloc(sizeof(*entry));
if (!entry) {
fprintf (stderr,
_("%s: failed to allocate memory: %s\n"),
Prog, strerror (errno));
return 0;
}
entry->next = *head;
entry->range = range;
*head = entry;
return 1;
}
#endif /* ENABLE_SUBIDS */
/*
* usage - display usage message and exit
*/
@@ -334,6 +423,12 @@ static /*@noreturn@*/void usage (int status)
(void) fputs (_(" -s, --shell SHELL new login shell for the user account\n"), usageout);
(void) fputs (_(" -u, --uid UID new UID for the user account\n"), usageout);
(void) fputs (_(" -U, --unlock unlock the user account\n"), usageout);
#ifdef ENABLE_SUBIDS
(void) fputs (_(" -v, --add-subuids FIRST-LAST add range of subordinate uids\n"), usageout);
(void) fputs (_(" -V, --del-subuids FIRST-LAST remove range of subordinate uids\n"), usageout);
(void) fputs (_(" -w, --add-subgids FIRST-LAST add range of subordinate gids\n"), usageout);
(void) fputs (_(" -W, --del-subgids FIRST-LAST remove range of subordinate gids\n"), usageout);
#endif /* ENABLE_SUBIDS */
#ifdef WITH_SELINUX
(void) fputs (_(" -Z, --selinux-user SEUSER new SELinux user mapping for the user account\n"), usageout);
#endif /* WITH_SELINUX */
@@ -590,6 +685,22 @@ static /*@noreturn@*/void fail_exit (int code)
/* continue */
}
}
#ifdef ENABLE_SUBIDS
if (sub_uid_locked) {
if (sub_uid_unlock () == 0) {
fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_uid_dbname ());
SYSLOG ((LOG_ERR, "failed to unlock %s", sub_uid_dbname ()));
/* continue */
}
}
if (sub_gid_locked) {
if (sub_gid_unlock () == 0) {
fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_gid_dbname ());
SYSLOG ((LOG_ERR, "failed to unlock %s", sub_gid_dbname ()));
/* continue */
}
}
#endif /* ENABLE_SUBIDS */
#ifdef WITH_AUDIT
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
@@ -889,18 +1000,26 @@ static void process_flags (int argc, char **argv)
{"shell", required_argument, NULL, 's'},
{"uid", required_argument, NULL, 'u'},
{"unlock", no_argument, NULL, 'U'},
#ifdef ENABLE_SUBIDS
{"add-subuids", required_argument, NULL, 'v'},
{"del-subuids", required_argument, NULL, 'V'},
{"add-subgids", required_argument, NULL, 'w'},
{"del-subgids", required_argument, NULL, 'W'},
#endif /* ENABLE_SUBIDS */
#ifdef WITH_SELINUX
{"selinux-user", required_argument, NULL, 'Z'},
#endif /* WITH_SELINUX */
{NULL, 0, NULL, '\0'}
};
while ((c = getopt_long (argc, argv,
"ac:d:e:f:g:G:hl:Lmop:R:s:u:U"
#ifdef ENABLE_SUBIDS
"v:w:V:W:"
#endif /* ENABLE_SUBIDS */
#ifdef WITH_SELINUX
"ac:d:e:f:g:G:hl:Lmop:R:s:u:UZ:",
#else /* !WITH_SELINUX */
"ac:d:e:f:g:G:hl:Lmop:R:s:u:U",
#endif /* !WITH_SELINUX */
long_options, NULL)) != -1) {
"Z:"
#endif /* WITH_SELINUX */
, long_options, NULL)) != -1) {
switch (c) {
case 'a':
aflg = true;
@@ -1018,6 +1137,44 @@ static void process_flags (int argc, char **argv)
case 'U':
Uflg = true;
break;
#ifdef ENABLE_SUBIDS
case 'v':
if (prepend_range (optarg, &add_sub_uids) == 0) {
fprintf (stderr,
_("%s: invalid subordinate uid range '%s'\n"),
Prog, optarg);
exit(E_BAD_ARG);
}
vflg = true;
break;
case 'V':
if (prepend_range (optarg, &del_sub_uids) == 0) {
fprintf (stderr,
_("%s: invalid subordinate uid range '%s'\n"),
Prog, optarg);
exit(E_BAD_ARG);
}
Vflg = true;
break;
case 'w':
if (prepend_range (optarg, &add_sub_gids) == 0) {
fprintf (stderr,
_("%s: invalid subordinate gid range '%s'\n"),
Prog, optarg);
exit(E_BAD_ARG);
}
wflg = true;
break;
case 'W':
if (prepend_range (optarg, &del_sub_gids) == 0) {
fprintf (stderr,
_("%s: invalid subordinate gid range '%s'\n"),
Prog, optarg);
exit(E_BAD_ARG);
}
Wflg = true;
break;
#endif /* ENABLE_SUBIDS */
#ifdef WITH_SELINUX
case 'Z':
if (is_selinux_enabled () > 0) {
@@ -1170,6 +1327,9 @@ static void process_flags (int argc, char **argv)
if (!(Uflg || uflg || sflg || pflg || mflg || Lflg ||
lflg || Gflg || gflg || fflg || eflg || dflg || cflg
#ifdef ENABLE_SUBIDS
|| vflg || Vflg || wflg || Wflg
#endif /* ENABLE_SUBIDS */
#ifdef WITH_SELINUX
|| Zflg
#endif /* WITH_SELINUX */
@@ -1200,6 +1360,22 @@ static void process_flags (int argc, char **argv)
Prog, (unsigned long) user_newid);
exit (E_UID_IN_USE);
}
if ( (vflg || Vflg)
&& !is_sub_uid) {
fprintf (stderr,
_("%s: %s does not exist, you cannot use the flags %s or %s\n"),
Prog, sub_uid_dbname (), "-v", "-V");
exit (E_USAGE);
}
if ( (wflg || Wflg)
&& !is_sub_gid) {
fprintf (stderr,
_("%s: %s does not exist, you cannot use the flags %s or %s\n"),
Prog, sub_gid_dbname (), "-w", "-W");
exit (E_USAGE);
}
}
/*
@@ -1248,6 +1424,10 @@ static void close_files (void)
sgr_dbname ()));
fail_exit (E_GRP_UPDATE);
}
}
#endif
#ifdef SHADOWGRP
if (is_shadow_grp) {
if (sgr_unlock () == 0) {
fprintf (stderr,
_("%s: failed to unlock %s\n"),
@@ -1296,6 +1476,35 @@ static void close_files (void)
sgr_locked = false;
#endif
#ifdef ENABLE_SUBIDS
if (vflg || Vflg) {
if (sub_uid_close () == 0) {
fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, sub_uid_dbname ());
SYSLOG ((LOG_ERR, "failure while writing changes to %s", sub_uid_dbname ()));
fail_exit (E_SUB_UID_UPDATE);
}
if (sub_uid_unlock () == 0) {
fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_uid_dbname ());
SYSLOG ((LOG_ERR, "failed to unlock %s", sub_uid_dbname ()));
/* continue */
}
sub_uid_locked = false;
}
if (wflg || Wflg) {
if (sub_gid_close () == 0) {
fprintf (stderr, _("%s: failure while writing changes to %s\n"), Prog, sub_gid_dbname ());
SYSLOG ((LOG_ERR, "failure while writing changes to %s", sub_gid_dbname ()));
fail_exit (E_SUB_GID_UPDATE);
}
if (sub_gid_unlock () == 0) {
fprintf (stderr, _("%s: failed to unlock %s\n"), Prog, sub_gid_dbname ());
SYSLOG ((LOG_ERR, "failed to unlock %s", sub_gid_dbname ()));
/* continue */
}
sub_gid_locked = false;
}
#endif /* ENABLE_SUBIDS */
/*
* Close the DBM and/or flat files
*/
@@ -1375,6 +1584,38 @@ static void open_files (void)
}
#endif
}
#ifdef ENABLE_SUBIDS
if (vflg || Vflg) {
if (sub_uid_lock () == 0) {
fprintf (stderr,
_("%s: cannot lock %s; try again later.\n"),
Prog, sub_uid_dbname ());
fail_exit (E_SUB_UID_UPDATE);
}
sub_uid_locked = true;
if (sub_uid_open (O_RDWR) == 0) {
fprintf (stderr,
_("%s: cannot open %s\n"),
Prog, sub_uid_dbname ());
fail_exit (E_SUB_UID_UPDATE);
}
}
if (wflg || Wflg) {
if (sub_gid_lock () == 0) {
fprintf (stderr,
_("%s: cannot lock %s; try again later.\n"),
Prog, sub_gid_dbname ());
fail_exit (E_SUB_GID_UPDATE);
}
sub_gid_locked = true;
if (sub_gid_open (O_RDWR) == 0) {
fprintf (stderr,
_("%s: cannot open %s\n"),
Prog, sub_gid_dbname ());
fail_exit (E_SUB_GID_UPDATE);
}
}
#endif /* ENABLE_SUBIDS */
}
/*
@@ -1476,6 +1717,60 @@ static void usr_update (void)
fail_exit (E_PW_UPDATE);
}
}
#ifdef ENABLE_SUBIDS
if (Vflg) {
struct ulong_range_list_entry *ptr;
for (ptr = del_sub_uids; ptr != NULL; ptr = ptr->next) {
unsigned long count = ptr->range.last - ptr->range.first + 1;
if (sub_uid_remove(user_name, ptr->range.first, count) == 0) {
fprintf (stderr,
_("%s: failed to remove uid range %lu-%lu from '%s'\n"),
Prog, ptr->range.first, ptr->range.last,
sub_uid_dbname ());
fail_exit (E_SUB_UID_UPDATE);
}
}
}
if (vflg) {
struct ulong_range_list_entry *ptr;
for (ptr = add_sub_uids; ptr != NULL; ptr = ptr->next) {
unsigned long count = ptr->range.last - ptr->range.first + 1;
if (sub_uid_add(user_name, ptr->range.first, count) == 0) {
fprintf (stderr,
_("%s: failed to add uid range %lu-%lu from '%s'\n"),
Prog, ptr->range.first, ptr->range.last,
sub_uid_dbname ());
fail_exit (E_SUB_UID_UPDATE);
}
}
}
if (Wflg) {
struct ulong_range_list_entry *ptr;
for (ptr = del_sub_gids; ptr != NULL; ptr = ptr->next) {
unsigned long count = ptr->range.last - ptr->range.first + 1;
if (sub_gid_remove(user_name, ptr->range.first, count) == 0) {
fprintf (stderr,
_("%s: failed to remove gid range %lu-%lu from '%s'\n"),
Prog, ptr->range.first, ptr->range.last,
sub_gid_dbname ());
fail_exit (E_SUB_GID_UPDATE);
}
}
}
if (wflg) {
struct ulong_range_list_entry *ptr;
for (ptr = add_sub_gids; ptr != NULL; ptr = ptr->next) {
unsigned long count = ptr->range.last - ptr->range.first + 1;
if (sub_gid_add(user_name, ptr->range.first, count) == 0) {
fprintf (stderr,
_("%s: failed to add gid range %lu-%lu from '%s'\n"),
Prog, ptr->range.first, ptr->range.last,
sub_gid_dbname ());
fail_exit (E_SUB_GID_UPDATE);
}
}
}
#endif /* ENABLE_SUBIDS */
}
/*
@@ -1811,6 +2106,10 @@ int main (int argc, char **argv)
#ifdef SHADOWGRP
is_shadow_grp = sgr_file_present ();
#endif
#ifdef ENABLE_SUBIDS
is_sub_uid = sub_uid_file_present ();
is_sub_gid = sub_gid_file_present ();
#endif /* ENABLE_SUBIDS */
process_flags (argc, argv);
@@ -1818,7 +2117,11 @@ int main (int argc, char **argv)
* The home directory, the username and the user's UID should not
* be changed while the user is logged in.
*/
if ( (uflg || lflg || dflg)
if ( (uflg || lflg || dflg
#ifdef ENABLE_SUBIDS
|| Vflg || Wflg
#endif /* ENABLE_SUBIDS */
)
&& (user_busy (user_name, user_id) != 0)) {
exit (E_USER_BUSY);
}
@@ -1871,7 +2174,11 @@ int main (int argc, char **argv)
*/
open_files ();
if ( cflg || dflg || eflg || fflg || gflg || Lflg || lflg || pflg
|| sflg || uflg || Uflg) {
|| sflg || uflg || Uflg
#ifdef ENABLE_SUBIDS
|| vflg || Vflg || wflg || Wflg
#endif /* ENABLE_SUBIDS */
) {
usr_update ();
}
if (Gflg || lflg) {