2007-10-07 17:14:02 +05:30
|
|
|
/*
|
|
|
|
* Copyright 1991 - 1994, Julianne Frances Haugh
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. Neither the name of Julianne F. Haugh nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
2007-10-07 17:14:59 +05:30
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
|
2007-10-07 17:14:02 +05:30
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
2007-11-11 05:16:11 +05:30
|
|
|
#ident "$Id$"
|
2007-10-07 17:17:01 +05:30
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
#include <ctype.h>
|
2007-10-07 17:17:01 +05:30
|
|
|
#include <errno.h>
|
2007-10-07 17:14:02 +05:30
|
|
|
#include <fcntl.h>
|
2007-10-07 17:17:11 +05:30
|
|
|
#include <getopt.h>
|
2007-10-07 17:17:01 +05:30
|
|
|
#include <grp.h>
|
|
|
|
#include <lastlog.h>
|
|
|
|
#include <pwd.h>
|
2007-10-07 17:14:38 +05:30
|
|
|
#ifdef USE_PAM
|
2007-10-07 17:17:11 +05:30
|
|
|
#include "pam_defs.h"
|
2007-10-07 17:14:59 +05:30
|
|
|
#endif /* USE_PAM */
|
2007-10-07 17:17:01 +05:30
|
|
|
#include <stdio.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <time.h>
|
2007-10-07 17:14:02 +05:30
|
|
|
#include "chkname.h"
|
2007-10-07 17:17:01 +05:30
|
|
|
#include "defines.h"
|
2007-10-07 17:14:02 +05:30
|
|
|
#include "faillog.h"
|
|
|
|
#include "getdef.h"
|
2007-10-07 17:16:34 +05:30
|
|
|
#include "groupio.h"
|
|
|
|
#include "nscd.h"
|
2007-10-07 17:17:01 +05:30
|
|
|
#include "prototypes.h"
|
|
|
|
#include "pwauth.h"
|
2007-10-07 17:16:34 +05:30
|
|
|
#include "pwio.h"
|
|
|
|
#ifdef SHADOWGRP
|
|
|
|
#include "sgroupio.h"
|
|
|
|
#endif
|
|
|
|
#include "shadowio.h"
|
2007-10-07 17:14:02 +05:30
|
|
|
/*
|
|
|
|
* exit status values
|
|
|
|
* for E_GRP_UPDATE and E_NOSPACE (not used yet), other update requests
|
|
|
|
* will be implemented (as documented in the Solaris 2.x man page).
|
|
|
|
*/
|
|
|
|
#define E_SUCCESS 0 /* success */
|
|
|
|
#define E_PW_UPDATE 1 /* can't update password file */
|
|
|
|
#define E_USAGE 2 /* invalid command syntax */
|
|
|
|
#define E_BAD_ARG 3 /* invalid argument to option */
|
2007-10-07 17:16:25 +05:30
|
|
|
#define E_UID_IN_USE 4 /* UID already in use (and no -o) */
|
2007-10-07 17:17:57 +05:30
|
|
|
/* #define E_BAD_PWFILE 5 passwd file contains errors */
|
2007-10-07 17:14:02 +05:30
|
|
|
#define E_NOTFOUND 6 /* specified user/group doesn't exist */
|
|
|
|
#define E_USER_BUSY 8 /* user to modify is logged in */
|
|
|
|
#define E_NAME_IN_USE 9 /* username already in use */
|
|
|
|
#define E_GRP_UPDATE 10 /* can't update group file */
|
2007-10-07 17:17:57 +05:30
|
|
|
/* #define E_NOSPACE 11 insufficient space to move home dir */
|
2007-10-07 17:14:02 +05:30
|
|
|
#define E_HOMEDIR 12 /* unable to complete home dir move */
|
|
|
|
#define VALID(s) (strcspn (s, ":\n") == strlen (s))
|
2007-10-07 17:17:01 +05:30
|
|
|
/*
|
|
|
|
* Global variables
|
|
|
|
*/
|
2007-10-07 17:14:02 +05:30
|
|
|
static char *user_name;
|
|
|
|
static char *user_newname;
|
|
|
|
static char *user_pass;
|
|
|
|
static uid_t user_id;
|
|
|
|
static uid_t user_newid;
|
|
|
|
static gid_t user_gid;
|
|
|
|
static gid_t user_newgid;
|
|
|
|
static char *user_comment;
|
2008-01-24 02:49:08 +05:30
|
|
|
static char *user_newcomment;
|
2007-10-07 17:14:02 +05:30
|
|
|
static char *user_home;
|
|
|
|
static char *user_newhome;
|
|
|
|
static char *user_shell;
|
2008-01-24 02:49:08 +05:30
|
|
|
static char *user_newshell;
|
2007-10-07 17:14:02 +05:30
|
|
|
static long user_expire;
|
2008-01-24 02:49:08 +05:30
|
|
|
static long user_newexpire;
|
2007-10-07 17:14:02 +05:30
|
|
|
static long user_inactive;
|
2008-01-24 02:49:08 +05:30
|
|
|
static long user_newinactive;
|
2007-10-07 17:14:51 +05:30
|
|
|
static long sys_ngroups;
|
2007-10-07 17:14:59 +05:30
|
|
|
static char **user_groups; /* NULL-terminated list */
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
static char *Prog;
|
|
|
|
|
|
|
|
static int
|
2007-11-17 17:12:47 +05:30
|
|
|
aflg = 0, /* append to existing secondary group set */
|
2007-10-07 17:16:07 +05:30
|
|
|
cflg = 0, /* new comment (GECOS) field */
|
2007-10-07 17:16:34 +05:30
|
|
|
dflg = 0, /* new home directory */
|
2007-10-07 17:16:07 +05:30
|
|
|
eflg = 0, /* days since 1970-01-01 when account becomes expired */
|
2007-10-07 17:16:34 +05:30
|
|
|
fflg = 0, /* days until account with expired password is locked */
|
|
|
|
gflg = 0, /* new primary group ID */
|
|
|
|
Gflg = 0, /* new secondary group set */
|
2007-10-07 17:16:07 +05:30
|
|
|
Lflg = 0, /* lock the password */
|
2007-10-07 17:16:34 +05:30
|
|
|
lflg = 0, /* new user name */
|
|
|
|
mflg = 0, /* create user's home directory if it doesn't exist */
|
|
|
|
oflg = 0, /* permit non-unique user ID to be specified with -u */
|
2007-10-07 17:16:07 +05:30
|
|
|
pflg = 0, /* new encrypted password */
|
2007-10-07 17:16:34 +05:30
|
|
|
sflg = 0, /* new shell program */
|
|
|
|
uflg = 0, /* specify new user ID */
|
|
|
|
Uflg = 0; /* unlock the password */
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
static int is_shadow_pwd;
|
2007-10-07 17:16:25 +05:30
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
#ifdef SHADOWGRP
|
|
|
|
static int is_shadow_grp;
|
|
|
|
#endif
|
|
|
|
|
2007-11-17 17:12:47 +05:30
|
|
|
static int pw_locked = 0;
|
|
|
|
static int spw_locked = 0;
|
|
|
|
static int gr_locked = 0;
|
|
|
|
#ifdef SHADOWGRP
|
|
|
|
static int sgr_locked = 0;
|
|
|
|
#endif
|
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
/* local function prototypes */
|
2007-10-07 17:14:59 +05:30
|
|
|
static int get_groups (char *);
|
|
|
|
static void usage (void);
|
|
|
|
static void new_pwent (struct passwd *);
|
|
|
|
|
|
|
|
static void new_spent (struct spwd *);
|
|
|
|
static void fail_exit (int);
|
2007-11-17 17:12:47 +05:30
|
|
|
static void update_group (void);
|
2007-10-07 17:14:59 +05:30
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
#ifdef SHADOWGRP
|
2007-11-17 17:12:47 +05:30
|
|
|
static void update_gshadow (void);
|
2007-10-07 17:14:02 +05:30
|
|
|
#endif
|
2007-11-17 17:12:47 +05:30
|
|
|
static void grp_update (void);
|
2007-10-07 17:14:59 +05:30
|
|
|
|
|
|
|
static long get_number (const char *);
|
|
|
|
static uid_t get_id (const char *);
|
|
|
|
static void process_flags (int, char **);
|
|
|
|
static void close_files (void);
|
|
|
|
static void open_files (void);
|
|
|
|
static void usr_update (void);
|
|
|
|
static void move_home (void);
|
|
|
|
static void update_files (void);
|
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
#ifndef NO_MOVE_MAILBOX
|
2007-10-07 17:14:59 +05:30
|
|
|
static void move_mailbox (void);
|
2007-10-07 17:14:02 +05:30
|
|
|
#endif
|
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
/*
|
|
|
|
* Had to move this over from useradd.c since we have groups named
|
2007-10-07 17:14:02 +05:30
|
|
|
* "56k-family"... ergh.
|
2007-10-07 17:14:59 +05:30
|
|
|
* --Pac.
|
|
|
|
*/
|
2007-10-07 17:17:57 +05:30
|
|
|
static struct group *getgr_nam_gid (const char *grname)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
2007-10-07 17:17:57 +05:30
|
|
|
long val;
|
|
|
|
char *errptr;
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2007-10-07 17:17:57 +05:30
|
|
|
val = strtol (grname, &errptr, 10);
|
2007-10-07 20:06:51 +05:30
|
|
|
if (*grname != '\0' && *errptr == '\0' && errno != ERANGE && val >= 0)
|
* lib/prototypes.h, configure.in, libmisc/Makefile.am,
libmisc/xgetXXbyYY.c, libmisc/xgetpwnam.c, libmisc/xgetpwuid.c,
libmisc/xgetgrnam.c, libmisc/xgetgrgid.c, libmisc/xgetspnam.c:
Added functions xgetpwnam(), xgetpwuid(), xgetgrnam(),
xgetgrgid(), and xgetspnam(). They allocate memory for the
returned structure and are more robust to successive calls. They
are implemented with the libc's getxxyyy_r() functions if
available.
* libmisc/limits.c, libmisc/entry.c, libmisc/chowntty.c,
libmisc/addgrps.c, libmisc/myname.c, libmisc/rlogin.c,
libmisc/pwdcheck.c, src/newgrp.c, src/login_nopam.c,
src/userdel.c, src/lastlog.c, src/grpck.c, src/gpasswd.c,
src/newusers.c, src/chpasswd.c, src/chfn.c, src/groupmems.c,
src/usermod.c, src/expiry.c, src/groupdel.c, src/chgpasswd.c,
src/su.c, src/useradd.c, src/groupmod.c, src/passwd.c, src/pwck.c,
src/groupadd.c, src/chage.c, src/login.c, src/suauth.c,
src/faillog.c, src/groups.c, src/chsh.c, src/id.c: Review all the
usage of one of the getpwnam(), getpwuid(), getgrnam(),
getgrgid(), and getspnam() functions. It was noticed on
http://bugs.debian.org/341230 that chfn and chsh use a passwd
structure after calling a pam function, which result in using
information from the passwd structure requested by pam, not the
original one. It is much easier to use the new xget... functions
to avoid these issues. I've checked which call to the original
get... functions could be left (reducing the scope of the
structure if possible), and I've left comments to ease future
reviews (e.g. /* local, no need for xgetpwnam */).
Note: the getpwent/getgrent calls should probably be checked also.
* src/groupdel.c, src/expiry.c: Fix typos in comments.
* src/groupmod.c: Re-indent.
* libmisc/Makefile.am, lib/groupmem.c, lib/groupio.c, lib/pwmem.c,
lib/pwio.c, lib/shadowmem.c, lib/shadowio.c: Move the __<xx>_dup
functions (used by the xget... functions) from the <xx>io.c files
to the new <xx>mem.c files. This avoid linking some utils against
the SELinux library.
2007-11-19 04:45:26 +05:30
|
|
|
return xgetgrgid (val);
|
|
|
|
return xgetgrnam (grname);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get_groups - convert a list of group names to an array of group IDs
|
|
|
|
*
|
|
|
|
* get_groups() takes a comma-separated list of group names and
|
2007-10-07 17:14:59 +05:30
|
|
|
* converts it to a NULL-terminated array. Any unknown group names are
|
|
|
|
* reported as errors.
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
static int get_groups (char *list)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
|
|
|
char *cp;
|
|
|
|
const struct group *grp;
|
|
|
|
int errors = 0;
|
|
|
|
int ngroups = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize the list to be empty
|
|
|
|
*/
|
|
|
|
user_groups[0] = (char *) 0;
|
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
if (!*list)
|
2007-10-07 17:14:02 +05:30
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
2007-10-07 17:14:59 +05:30
|
|
|
* So long as there is some data to be converted, strip off each
|
|
|
|
* name and look it up. A mix of numerical and string values for
|
|
|
|
* group identifiers is permitted.
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
|
|
|
do {
|
|
|
|
/*
|
|
|
|
* Strip off a single name from the list
|
|
|
|
*/
|
|
|
|
if ((cp = strchr (list, ',')))
|
|
|
|
*cp++ = '\0';
|
|
|
|
|
|
|
|
/*
|
2007-10-07 17:14:59 +05:30
|
|
|
* Names starting with digits are treated as numerical GID
|
|
|
|
* values, otherwise the string is looked up as is.
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
grp = getgr_nam_gid (list);
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
/*
|
|
|
|
* There must be a match, either by GID value or by
|
|
|
|
* string name.
|
|
|
|
*/
|
|
|
|
if (!grp) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr, _("%s: unknown group %s\n"),
|
|
|
|
Prog, list);
|
2007-10-07 17:14:02 +05:30
|
|
|
errors++;
|
|
|
|
}
|
|
|
|
list = cp;
|
|
|
|
|
|
|
|
/*
|
2007-10-07 17:14:59 +05:30
|
|
|
* If the group doesn't exist, don't dump core. Instead,
|
|
|
|
* try the next one. --marekm
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
if (!grp)
|
2007-10-07 17:14:02 +05:30
|
|
|
continue;
|
|
|
|
|
|
|
|
#ifdef USE_NIS
|
|
|
|
/*
|
2007-10-07 17:14:59 +05:30
|
|
|
* Don't add this group if they are an NIS group. Tell the
|
|
|
|
* user to go to the server for this group.
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
|
|
|
if (__isgrNIS ()) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr,
|
2007-10-07 17:17:33 +05:30
|
|
|
_("%s: group '%s' is a NIS group.\n"),
|
2007-10-07 17:14:59 +05:30
|
|
|
Prog, grp->gr_name);
|
2007-10-07 17:14:02 +05:30
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-10-07 17:14:51 +05:30
|
|
|
if (ngroups == sys_ngroups) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_
|
|
|
|
("%s: too many groups specified (max %d).\n"),
|
|
|
|
Prog, ngroups);
|
2007-10-07 17:14:02 +05:30
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add the group name to the user's list of groups.
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
user_groups[ngroups++] = xstrdup (grp->gr_name);
|
2007-10-07 17:14:02 +05:30
|
|
|
} while (list);
|
|
|
|
|
|
|
|
user_groups[ngroups] = (char *) 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Any errors in finding group names are fatal
|
|
|
|
*/
|
|
|
|
if (errors)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* usage - display usage message and exit
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
static void usage (void)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
2008-01-25 02:12:12 +05:30
|
|
|
fputs (_("Usage: usermod [options] LOGIN\n"
|
2007-10-07 17:17:11 +05:30
|
|
|
"\n"
|
|
|
|
"Options:\n"
|
2007-11-25 04:11:24 +05:30
|
|
|
" -c, --comment COMMENT new value of the GECOS field\n"
|
|
|
|
" -d, --home HOME_DIR new home directory for the user account\n"
|
|
|
|
" -e, --expiredate EXPIRE_DATE set account expiration date to EXPIRE_DATE\n"
|
|
|
|
" -f, --inactive INACTIVE set password inactive after expiration\n"
|
|
|
|
" to INACTIVE\n"
|
|
|
|
" -g, --gid GROUP force use GROUP as new primary group\n"
|
|
|
|
" -G, --groups GROUPS new list of supplementary GROUPS\n"
|
|
|
|
" -a, --append append the user to the supplemental GROUPS\n"
|
|
|
|
" mentioned by the -G option without removing\n"
|
|
|
|
" him/her from other groups\n"
|
|
|
|
" -h, --help display this help message and exit\n"
|
|
|
|
" -l, --login NEW_LOGIN new value of the login name\n"
|
|
|
|
" -L, --lock lock the user account\n"
|
|
|
|
" -m, --move-home move contents of the home directory to the\n"
|
|
|
|
" new location (use only with -d)\n"
|
|
|
|
" -o, --non-unique allow using duplicate (non-unique) UID\n"
|
|
|
|
" -p, --password PASSWORD use encrypted password for the new password\n"
|
|
|
|
" -s, --shell SHELL new login shell for the user account\n"
|
|
|
|
" -u, --uid UID new UID for the user account\n"
|
|
|
|
" -U, --unlock unlock the user account\n"
|
2008-01-25 02:12:12 +05:30
|
|
|
"\n"), stderr);
|
2007-10-07 17:14:59 +05:30
|
|
|
exit (E_USAGE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
/*
|
|
|
|
* update encrypted password string (for both shadow and non-shadow
|
|
|
|
* passwords)
|
|
|
|
*/
|
2008-01-06 18:20:22 +05:30
|
|
|
static char *new_pw_passwd (char *pw_pass)
|
2007-10-07 17:14:32 +05:30
|
|
|
{
|
|
|
|
if (Lflg && pw_pass[0] != '!') {
|
2007-10-07 17:14:59 +05:30
|
|
|
char *buf = xmalloc (strlen (pw_pass) + 2);
|
2007-10-07 17:14:32 +05:30
|
|
|
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "updating passwd",
|
|
|
|
user_newname, user_newid, 0);
|
|
|
|
#endif
|
2008-01-24 02:49:08 +05:30
|
|
|
SYSLOG ((LOG_INFO, "lock user `%s' password", user_newname));
|
2007-10-07 17:14:59 +05:30
|
|
|
strcpy (buf, "!");
|
|
|
|
strcat (buf, pw_pass);
|
2007-10-07 17:14:32 +05:30
|
|
|
pw_pass = buf;
|
|
|
|
} else if (Uflg && pw_pass[0] == '!') {
|
|
|
|
char *s;
|
|
|
|
|
2007-11-18 03:32:22 +05:30
|
|
|
if (pw_pass[1] == '\0') {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: unlocking the user would result in a passwordless account.\n"
|
|
|
|
"You should set a password with usermod -p to unlock this user account.\n"),
|
|
|
|
Prog);
|
|
|
|
return pw_pass;
|
|
|
|
}
|
|
|
|
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "updating password",
|
|
|
|
user_newname, user_newid, 0);
|
|
|
|
#endif
|
2008-01-24 02:49:08 +05:30
|
|
|
SYSLOG ((LOG_INFO, "unlock user `%s' password", user_newname));
|
2007-10-07 17:14:32 +05:30
|
|
|
s = pw_pass;
|
|
|
|
while (*s) {
|
|
|
|
*s = *(s + 1);
|
|
|
|
s++;
|
|
|
|
}
|
|
|
|
} else if (pflg) {
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing password",
|
|
|
|
user_newname, user_newid, 1);
|
|
|
|
#endif
|
2008-01-24 02:49:08 +05:30
|
|
|
SYSLOG ((LOG_INFO, "change user `%s' password", user_newname));
|
2007-10-07 17:14:59 +05:30
|
|
|
pw_pass = xstrdup (user_pass);
|
2007-10-07 17:14:32 +05:30
|
|
|
}
|
|
|
|
return pw_pass;
|
|
|
|
}
|
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
/*
|
|
|
|
* new_pwent - initialize the values in a password file entry
|
|
|
|
*
|
2007-10-07 17:14:59 +05:30
|
|
|
* new_pwent() takes all of the values that have been entered and fills
|
|
|
|
* in a (struct passwd) with them.
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
static void new_pwent (struct passwd *pwent)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
|
|
|
if (lflg) {
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing name",
|
|
|
|
user_newname, user_newid, 1);
|
|
|
|
#endif
|
2007-10-07 17:14:59 +05:30
|
|
|
SYSLOG ((LOG_INFO, "change user name `%s' to `%s'",
|
|
|
|
pwent->pw_name, user_newname));
|
2007-10-07 17:14:02 +05:30
|
|
|
pwent->pw_name = xstrdup (user_newname);
|
|
|
|
}
|
|
|
|
if (!is_shadow_pwd)
|
2007-10-07 17:14:59 +05:30
|
|
|
pwent->pw_passwd =
|
2008-01-06 18:20:22 +05:30
|
|
|
new_pw_passwd (pwent->pw_passwd);
|
2007-10-07 17:14:32 +05:30
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
if (uflg) {
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing uid",
|
|
|
|
user_newname, user_newid, 1);
|
|
|
|
#endif
|
2007-10-07 17:14:59 +05:30
|
|
|
SYSLOG ((LOG_INFO,
|
|
|
|
"change user `%s' UID from `%d' to `%d'",
|
|
|
|
pwent->pw_name, pwent->pw_uid, user_newid));
|
2007-10-07 17:14:02 +05:30
|
|
|
pwent->pw_uid = user_newid;
|
|
|
|
}
|
|
|
|
if (gflg) {
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
|
|
|
"changing primary group", user_newname,
|
|
|
|
user_newid, 1);
|
|
|
|
#endif
|
2007-10-07 17:14:59 +05:30
|
|
|
SYSLOG ((LOG_INFO,
|
|
|
|
"change user `%s' GID from `%d' to `%d'",
|
|
|
|
pwent->pw_name, pwent->pw_gid, user_newgid));
|
2007-10-07 17:14:02 +05:30
|
|
|
pwent->pw_gid = user_newgid;
|
|
|
|
}
|
2007-10-07 17:17:01 +05:30
|
|
|
if (cflg) {
|
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing comment",
|
|
|
|
user_newname, user_newid, 1);
|
|
|
|
#endif
|
2008-01-24 02:49:08 +05:30
|
|
|
pwent->pw_gecos = user_newcomment;
|
2007-10-07 17:17:01 +05:30
|
|
|
}
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
if (dflg) {
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
|
|
|
"changing home directory", user_newname,
|
|
|
|
user_newid, 1);
|
|
|
|
#endif
|
2007-10-07 17:14:59 +05:30
|
|
|
SYSLOG ((LOG_INFO,
|
|
|
|
"change user `%s' home from `%s' to `%s'",
|
|
|
|
pwent->pw_name, pwent->pw_dir, user_newhome));
|
2007-10-07 17:14:02 +05:30
|
|
|
pwent->pw_dir = user_newhome;
|
|
|
|
}
|
|
|
|
if (sflg) {
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing user shell",
|
|
|
|
user_newname, user_newid, 1);
|
2008-01-24 02:49:08 +05:30
|
|
|
#endif
|
2007-10-07 17:17:01 +05:30
|
|
|
SYSLOG ((LOG_INFO, "change user `%s' shell from `%s' to `%s'",
|
|
|
|
pwent->pw_name, pwent->pw_shell, user_newshell));
|
|
|
|
pwent->pw_shell = user_newshell;
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* new_spent - initialize the values in a shadow password file entry
|
|
|
|
*
|
2007-10-07 17:14:59 +05:30
|
|
|
* new_spent() takes all of the values that have been entered and fills
|
|
|
|
* in a (struct spwd) with them.
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
static void new_spent (struct spwd *spent)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
|
|
|
if (lflg)
|
|
|
|
spent->sp_namp = xstrdup (user_newname);
|
|
|
|
|
|
|
|
if (fflg) {
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
|
|
|
"changing inactive days", user_newname,
|
|
|
|
user_newid, 1);
|
2008-01-24 02:49:08 +05:30
|
|
|
#endif
|
2007-10-07 17:17:01 +05:30
|
|
|
SYSLOG ((LOG_INFO,
|
|
|
|
"change user `%s' inactive from `%ld' to `%ld'",
|
|
|
|
spent->sp_namp, spent->sp_inact, user_newinactive));
|
|
|
|
spent->sp_inact = user_newinactive;
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
if (eflg) {
|
|
|
|
/* XXX - dates might be better than numbers of days. --marekm */
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
if (audit_fd >= 0) {
|
|
|
|
time_t exp_t;
|
|
|
|
struct tm *exp_tm;
|
|
|
|
char new_exp[16], old_exp[16];
|
|
|
|
|
|
|
|
if (user_newexpire == -1)
|
|
|
|
new_exp[0] = '\0';
|
|
|
|
else {
|
|
|
|
exp_t = user_newexpire * DAY;
|
|
|
|
exp_tm = gmtime (&exp_t);
|
|
|
|
#ifdef HAVE_STRFTIME
|
|
|
|
strftime (new_exp, sizeof (new_exp), "%Y-%m-%d",
|
|
|
|
exp_tm);
|
|
|
|
#else
|
|
|
|
memset (new_exp, 0, sizeof (new_exp));
|
|
|
|
snprintf (new_exp, sizeof (new_exp) - 1,
|
|
|
|
"%04i-%02i-%02i",
|
|
|
|
exp_tm->tm_year + 1900,
|
|
|
|
exp_tm->tm_mon + 1, exp_tm->tm_mday);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
if (user_expire == -1)
|
|
|
|
old_exp[0] = '\0';
|
|
|
|
else {
|
|
|
|
exp_t = user_expire * DAY;
|
|
|
|
exp_tm = gmtime (&exp_t);
|
|
|
|
#ifdef HAVE_STRFTIME
|
|
|
|
strftime (old_exp, sizeof (old_exp), "%Y-%m-%d",
|
|
|
|
exp_tm);
|
|
|
|
#else
|
|
|
|
memset (old_exp, 0, sizeof (old_exp));
|
|
|
|
snprintf (old_exp, sizeof (old_exp) - 1,
|
|
|
|
"%04i-%02i-%02i",
|
|
|
|
exp_tm->tm_year + 1900,
|
|
|
|
exp_tm->tm_mon + 1, exp_tm->tm_mday);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
|
|
|
"changing expiration date", user_newname,
|
|
|
|
user_newid, 1);
|
|
|
|
}
|
2008-01-24 02:49:08 +05:30
|
|
|
#endif
|
2007-10-07 17:17:01 +05:30
|
|
|
SYSLOG ((LOG_INFO,
|
|
|
|
"change user `%s' expiration from `%ld' to `%ld'",
|
|
|
|
spent->sp_namp, spent->sp_expire, user_newexpire));
|
|
|
|
spent->sp_expire = user_newexpire;
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2008-01-06 18:20:22 +05:30
|
|
|
spent->sp_pwdp = new_pw_passwd (spent->sp_pwdp);
|
2007-10-07 17:16:52 +05:30
|
|
|
if (pflg)
|
|
|
|
spent->sp_lstchg = time ((time_t *) 0) / SCALE;
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fail_exit - exit with an error code after unlocking files
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
static void fail_exit (int code)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
2007-11-17 17:12:47 +05:30
|
|
|
if (gr_locked)
|
|
|
|
gr_unlock ();
|
2007-10-07 17:14:02 +05:30
|
|
|
#ifdef SHADOWGRP
|
2007-11-17 17:12:47 +05:30
|
|
|
if (sgr_locked)
|
2007-10-07 17:14:02 +05:30
|
|
|
sgr_unlock ();
|
|
|
|
#endif
|
2007-11-17 17:12:47 +05:30
|
|
|
if (spw_locked)
|
2007-10-07 17:14:02 +05:30
|
|
|
spw_unlock ();
|
2007-11-17 17:12:47 +05:30
|
|
|
if (pw_locked)
|
|
|
|
pw_unlock ();
|
|
|
|
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "modifying account",
|
|
|
|
user_name, -1, 0);
|
|
|
|
#endif
|
2007-10-07 17:14:59 +05:30
|
|
|
exit (code);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-11-17 17:12:47 +05:30
|
|
|
static void update_group (void)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
|
|
|
int is_member;
|
|
|
|
int was_member;
|
|
|
|
int changed;
|
|
|
|
const struct group *grp;
|
|
|
|
struct group *ngrp;
|
|
|
|
|
|
|
|
changed = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Scan through the entire group file looking for the groups that
|
|
|
|
* the user is a member of.
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
while ((grp = gr_next ())) {
|
2007-10-07 17:14:02 +05:30
|
|
|
/*
|
|
|
|
* See if the user specified this group as one of their
|
|
|
|
* concurrent groups.
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
was_member = is_on_list (grp->gr_mem, user_name);
|
|
|
|
is_member = Gflg && is_on_list (user_groups, grp->gr_name);
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
if (!was_member && !is_member)
|
|
|
|
continue;
|
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
ngrp = __gr_dup (grp);
|
2007-10-07 17:14:02 +05:30
|
|
|
if (!ngrp) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr,
|
2007-11-17 05:09:42 +05:30
|
|
|
_("%s: Out of memory. Cannot update the group database.\n"),
|
2007-10-07 17:14:59 +05:30
|
|
|
Prog);
|
2007-11-17 17:12:47 +05:30
|
|
|
fail_exit (E_GRP_UPDATE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
if (was_member && (!Gflg || is_member)) {
|
|
|
|
if (lflg) {
|
2007-10-07 17:14:59 +05:30
|
|
|
ngrp->gr_mem = del_list (ngrp->gr_mem,
|
|
|
|
user_name);
|
|
|
|
ngrp->gr_mem = add_list (ngrp->gr_mem,
|
|
|
|
user_newname);
|
2007-10-07 17:14:02 +05:30
|
|
|
changed = 1;
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
|
|
|
"changing group member",
|
|
|
|
user_newname, -1, 1);
|
|
|
|
#endif
|
2007-10-07 17:14:59 +05:30
|
|
|
SYSLOG ((LOG_INFO,
|
|
|
|
"change `%s' to `%s' in group `%s'",
|
|
|
|
user_name, user_newname,
|
|
|
|
ngrp->gr_name));
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2007-10-07 17:16:34 +05:30
|
|
|
} else if (was_member && !aflg && Gflg && !is_member) {
|
2007-10-07 17:14:02 +05:30
|
|
|
ngrp->gr_mem = del_list (ngrp->gr_mem, user_name);
|
|
|
|
changed = 1;
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
|
|
|
"removing group member", user_name, -1,
|
|
|
|
1);
|
|
|
|
#endif
|
2007-10-07 17:14:59 +05:30
|
|
|
SYSLOG ((LOG_INFO, "delete `%s' from group `%s'",
|
|
|
|
user_name, ngrp->gr_name));
|
2007-10-07 17:14:02 +05:30
|
|
|
} else if (!was_member && Gflg && is_member) {
|
2008-01-24 02:49:08 +05:30
|
|
|
ngrp->gr_mem = add_list (ngrp->gr_mem, user_newname);
|
2007-10-07 17:14:02 +05:30
|
|
|
changed = 1;
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
|
|
|
"adding user to group", user_name, -1, 1);
|
|
|
|
#endif
|
2007-10-07 17:14:59 +05:30
|
|
|
SYSLOG ((LOG_INFO, "add `%s' to group `%s'",
|
2008-01-24 02:49:08 +05:30
|
|
|
user_newname, ngrp->gr_name));
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
if (!changed)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
changed = 0;
|
2007-10-07 17:14:59 +05:30
|
|
|
if (!gr_update (ngrp)) {
|
|
|
|
fprintf (stderr,
|
2007-10-07 17:16:07 +05:30
|
|
|
_("%s: error adding new group entry\n"), Prog);
|
2007-11-17 17:12:47 +05:30
|
|
|
SYSLOG ((LOG_ERR, "error adding new group entry"));
|
|
|
|
fail_exit (E_GRP_UPDATE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef SHADOWGRP
|
2007-11-17 17:12:47 +05:30
|
|
|
static void update_gshadow (void)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
|
|
|
int is_member;
|
|
|
|
int was_member;
|
|
|
|
int was_admin;
|
|
|
|
int changed;
|
|
|
|
const struct sgrp *sgrp;
|
|
|
|
struct sgrp *nsgrp;
|
|
|
|
|
|
|
|
changed = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Scan through the entire shadow group file looking for the groups
|
|
|
|
* that the user is a member of.
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
while ((sgrp = sgr_next ())) {
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
/*
|
|
|
|
* See if the user was a member of this group
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
was_member = is_on_list (sgrp->sg_mem, user_name);
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
/*
|
|
|
|
* See if the user was an administrator of this group
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
was_admin = is_on_list (sgrp->sg_adm, user_name);
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
/*
|
|
|
|
* See if the user specified this group as one of their
|
|
|
|
* concurrent groups.
|
|
|
|
*/
|
2007-10-07 17:16:07 +05:30
|
|
|
is_member = Gflg && is_on_list (user_groups, sgrp->sg_name);
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
if (!was_member && !was_admin && !is_member)
|
|
|
|
continue;
|
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
nsgrp = __sgr_dup (sgrp);
|
2007-10-07 17:14:02 +05:30
|
|
|
if (!nsgrp) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr,
|
2007-11-17 05:09:42 +05:30
|
|
|
_("%s: Out of memory. Cannot update the shadow group database.\n"),
|
2007-10-07 17:14:59 +05:30
|
|
|
Prog);
|
2007-11-17 17:12:47 +05:30
|
|
|
fail_exit (E_GRP_UPDATE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
if (was_admin && lflg) {
|
2007-10-07 17:16:07 +05:30
|
|
|
nsgrp->sg_adm = del_list (nsgrp->sg_adm, user_name);
|
|
|
|
nsgrp->sg_adm = add_list (nsgrp->sg_adm, user_newname);
|
2007-10-07 17:14:02 +05:30
|
|
|
changed = 1;
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
|
|
|
"changing admin name in shadow group",
|
|
|
|
user_name, -1, 1);
|
|
|
|
#endif
|
2007-10-07 17:14:59 +05:30
|
|
|
SYSLOG ((LOG_INFO,
|
|
|
|
"change admin `%s' to `%s' in shadow group `%s'",
|
|
|
|
user_name, user_newname, nsgrp->sg_name));
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
if (was_member && (!Gflg || is_member)) {
|
|
|
|
if (lflg) {
|
|
|
|
nsgrp->sg_mem = del_list (nsgrp->sg_mem,
|
2007-10-07 17:14:59 +05:30
|
|
|
user_name);
|
2007-10-07 17:14:02 +05:30
|
|
|
nsgrp->sg_mem = add_list (nsgrp->sg_mem,
|
2007-10-07 17:14:59 +05:30
|
|
|
user_newname);
|
2007-10-07 17:14:02 +05:30
|
|
|
changed = 1;
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
|
|
|
"changing member in shadow group",
|
|
|
|
user_name, -1, 1);
|
|
|
|
#endif
|
2007-10-07 17:14:59 +05:30
|
|
|
SYSLOG ((LOG_INFO,
|
|
|
|
"change `%s' to `%s' in shadow group `%s'",
|
|
|
|
user_name, user_newname,
|
|
|
|
nsgrp->sg_name));
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2007-10-07 17:16:34 +05:30
|
|
|
} else if (was_member && !aflg && Gflg && !is_member) {
|
2007-10-07 17:16:07 +05:30
|
|
|
nsgrp->sg_mem = del_list (nsgrp->sg_mem, user_name);
|
2007-10-07 17:14:02 +05:30
|
|
|
changed = 1;
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
|
|
|
"removing user from shadow group",
|
|
|
|
user_name, -1, 1);
|
|
|
|
#endif
|
2007-10-07 17:14:59 +05:30
|
|
|
SYSLOG ((LOG_INFO,
|
|
|
|
"delete `%s' from shadow group `%s'",
|
|
|
|
user_name, nsgrp->sg_name));
|
2007-10-07 17:14:02 +05:30
|
|
|
} else if (!was_member && Gflg && is_member) {
|
2008-01-24 02:49:08 +05:30
|
|
|
nsgrp->sg_mem = add_list (nsgrp->sg_mem, user_newname);
|
2007-10-07 17:14:02 +05:30
|
|
|
changed = 1;
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
|
|
|
"adding user to shadow group",
|
|
|
|
user_newname, -1, 1);
|
|
|
|
#endif
|
2007-10-07 17:14:59 +05:30
|
|
|
SYSLOG ((LOG_INFO, "add `%s' to shadow group `%s'",
|
2008-01-24 02:49:08 +05:30
|
|
|
user_newname, nsgrp->sg_name));
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
if (!changed)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
changed = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Update the group entry to reflect the changes.
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
if (!sgr_update (nsgrp)) {
|
|
|
|
fprintf (stderr,
|
2007-11-17 17:12:47 +05:30
|
|
|
_("%s: error adding new shadow group entry\n"), Prog);
|
2007-10-07 17:16:07 +05:30
|
|
|
SYSLOG ((LOG_ERR, "error adding shadow group entry"));
|
2007-11-17 17:12:47 +05:30
|
|
|
fail_exit (E_GRP_UPDATE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-10-07 17:14:59 +05:30
|
|
|
#endif /* SHADOWGRP */
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
/*
|
|
|
|
* grp_update - add user to secondary group set
|
|
|
|
*
|
2007-10-07 17:14:59 +05:30
|
|
|
* grp_update() takes the secondary group set given in user_groups and
|
|
|
|
* adds the user to each group given by that set.
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
2007-11-17 17:12:47 +05:30
|
|
|
static void grp_update (void)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
2007-11-17 17:12:47 +05:30
|
|
|
update_group ();
|
2007-10-07 17:14:02 +05:30
|
|
|
#ifdef SHADOWGRP
|
2007-11-17 17:12:47 +05:30
|
|
|
if (is_shadow_grp)
|
|
|
|
update_gshadow ();
|
2007-10-07 17:14:02 +05:30
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2007-10-07 17:17:57 +05:30
|
|
|
static long get_number (const char *numstr)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
|
|
|
long val;
|
2007-10-07 17:17:57 +05:30
|
|
|
char *errptr;
|
2007-10-07 17:14:59 +05:30
|
|
|
|
2007-10-07 17:17:57 +05:30
|
|
|
val = strtol (numstr, &errptr, 10);
|
|
|
|
if (*errptr || errno == ERANGE) {
|
|
|
|
fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog,
|
|
|
|
numstr);
|
|
|
|
exit (E_BAD_ARG);
|
|
|
|
}
|
|
|
|
return val;
|
2007-10-07 17:14:59 +05:30
|
|
|
}
|
|
|
|
|
2007-10-07 17:17:57 +05:30
|
|
|
static uid_t get_id (const char *uidstr)
|
2007-10-07 17:14:59 +05:30
|
|
|
{
|
2007-10-07 17:17:57 +05:30
|
|
|
long val;
|
|
|
|
char *errptr;
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2007-10-07 17:17:57 +05:30
|
|
|
val = strtol (uidstr, &errptr, 10);
|
|
|
|
if (*errptr || errno == ERANGE || val < 0) {
|
|
|
|
fprintf (stderr, _("%s: invalid numeric argument '%s'\n"), Prog,
|
|
|
|
uidstr);
|
|
|
|
exit (E_BAD_ARG);
|
|
|
|
}
|
|
|
|
return val;
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* process_flags - perform command line argument setting
|
|
|
|
*
|
2007-10-07 17:14:59 +05:30
|
|
|
* process_flags() interprets the command line arguments and sets the
|
|
|
|
* values that the user will be created with accordingly. The values
|
|
|
|
* are checked for sanity.
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
static void process_flags (int argc, char **argv)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
|
|
|
const struct group *grp;
|
2007-10-07 17:14:59 +05:30
|
|
|
|
|
|
|
int anyflag = 0;
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
if (argc == 1 || argv[argc - 1][0] == '-')
|
|
|
|
usage ();
|
|
|
|
|
* lib/prototypes.h, configure.in, libmisc/Makefile.am,
libmisc/xgetXXbyYY.c, libmisc/xgetpwnam.c, libmisc/xgetpwuid.c,
libmisc/xgetgrnam.c, libmisc/xgetgrgid.c, libmisc/xgetspnam.c:
Added functions xgetpwnam(), xgetpwuid(), xgetgrnam(),
xgetgrgid(), and xgetspnam(). They allocate memory for the
returned structure and are more robust to successive calls. They
are implemented with the libc's getxxyyy_r() functions if
available.
* libmisc/limits.c, libmisc/entry.c, libmisc/chowntty.c,
libmisc/addgrps.c, libmisc/myname.c, libmisc/rlogin.c,
libmisc/pwdcheck.c, src/newgrp.c, src/login_nopam.c,
src/userdel.c, src/lastlog.c, src/grpck.c, src/gpasswd.c,
src/newusers.c, src/chpasswd.c, src/chfn.c, src/groupmems.c,
src/usermod.c, src/expiry.c, src/groupdel.c, src/chgpasswd.c,
src/su.c, src/useradd.c, src/groupmod.c, src/passwd.c, src/pwck.c,
src/groupadd.c, src/chage.c, src/login.c, src/suauth.c,
src/faillog.c, src/groups.c, src/chsh.c, src/id.c: Review all the
usage of one of the getpwnam(), getpwuid(), getgrnam(),
getgrgid(), and getspnam() functions. It was noticed on
http://bugs.debian.org/341230 that chfn and chsh use a passwd
structure after calling a pam function, which result in using
information from the passwd structure requested by pam, not the
original one. It is much easier to use the new xget... functions
to avoid these issues. I've checked which call to the original
get... functions could be left (reducing the scope of the
structure if possible), and I've left comments to ease future
reviews (e.g. /* local, no need for xgetpwnam */).
Note: the getpwent/getgrent calls should probably be checked also.
* src/groupdel.c, src/expiry.c: Fix typos in comments.
* src/groupmod.c: Re-indent.
* libmisc/Makefile.am, lib/groupmem.c, lib/groupio.c, lib/pwmem.c,
lib/pwio.c, lib/shadowmem.c, lib/shadowio.c: Move the __<xx>_dup
functions (used by the xget... functions) from the <xx>io.c files
to the new <xx>mem.c files. This avoid linking some utils against
the SELinux library.
2007-11-19 04:45:26 +05:30
|
|
|
{
|
|
|
|
const struct passwd *pwd;
|
|
|
|
/* local, no need for xgetpwnam */
|
|
|
|
if (!(pwd = getpwnam (argv[argc - 1]))) {
|
|
|
|
fprintf (stderr, _("%s: user %s does not exist\n"),
|
|
|
|
Prog, argv[argc - 1]);
|
|
|
|
exit (E_NOTFOUND);
|
|
|
|
}
|
2007-10-07 17:17:01 +05:30
|
|
|
|
* lib/prototypes.h, configure.in, libmisc/Makefile.am,
libmisc/xgetXXbyYY.c, libmisc/xgetpwnam.c, libmisc/xgetpwuid.c,
libmisc/xgetgrnam.c, libmisc/xgetgrgid.c, libmisc/xgetspnam.c:
Added functions xgetpwnam(), xgetpwuid(), xgetgrnam(),
xgetgrgid(), and xgetspnam(). They allocate memory for the
returned structure and are more robust to successive calls. They
are implemented with the libc's getxxyyy_r() functions if
available.
* libmisc/limits.c, libmisc/entry.c, libmisc/chowntty.c,
libmisc/addgrps.c, libmisc/myname.c, libmisc/rlogin.c,
libmisc/pwdcheck.c, src/newgrp.c, src/login_nopam.c,
src/userdel.c, src/lastlog.c, src/grpck.c, src/gpasswd.c,
src/newusers.c, src/chpasswd.c, src/chfn.c, src/groupmems.c,
src/usermod.c, src/expiry.c, src/groupdel.c, src/chgpasswd.c,
src/su.c, src/useradd.c, src/groupmod.c, src/passwd.c, src/pwck.c,
src/groupadd.c, src/chage.c, src/login.c, src/suauth.c,
src/faillog.c, src/groups.c, src/chsh.c, src/id.c: Review all the
usage of one of the getpwnam(), getpwuid(), getgrnam(),
getgrgid(), and getspnam() functions. It was noticed on
http://bugs.debian.org/341230 that chfn and chsh use a passwd
structure after calling a pam function, which result in using
information from the passwd structure requested by pam, not the
original one. It is much easier to use the new xget... functions
to avoid these issues. I've checked which call to the original
get... functions could be left (reducing the scope of the
structure if possible), and I've left comments to ease future
reviews (e.g. /* local, no need for xgetpwnam */).
Note: the getpwent/getgrent calls should probably be checked also.
* src/groupdel.c, src/expiry.c: Fix typos in comments.
* src/groupmod.c: Re-indent.
* libmisc/Makefile.am, lib/groupmem.c, lib/groupio.c, lib/pwmem.c,
lib/pwio.c, lib/shadowmem.c, lib/shadowio.c: Move the __<xx>_dup
functions (used by the xget... functions) from the <xx>io.c files
to the new <xx>mem.c files. This avoid linking some utils against
the SELinux library.
2007-11-19 04:45:26 +05:30
|
|
|
user_name = argv[argc - 1];
|
|
|
|
user_id = pwd->pw_uid;
|
|
|
|
user_gid = pwd->pw_gid;
|
|
|
|
user_comment = xstrdup (pwd->pw_gecos);
|
|
|
|
user_home = xstrdup (pwd->pw_dir);
|
|
|
|
user_shell = xstrdup (pwd->pw_shell);
|
|
|
|
}
|
2007-10-07 17:17:01 +05:30
|
|
|
user_newname = user_name;
|
|
|
|
user_newid = user_id;
|
|
|
|
user_newgid = user_gid;
|
|
|
|
user_newcomment = user_comment;
|
|
|
|
user_newhome = user_home;
|
|
|
|
user_newshell = user_shell;
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
#ifdef USE_NIS
|
|
|
|
/*
|
|
|
|
* Now make sure it isn't an NIS user.
|
|
|
|
*/
|
|
|
|
if (__ispwNIS ()) {
|
2007-10-07 17:14:59 +05:30
|
|
|
char *nis_domain;
|
|
|
|
char *nis_master;
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr, _("%s: user %s is a NIS user\n"),
|
|
|
|
Prog, user_name);
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
if (!yp_get_default_domain (&nis_domain) &&
|
2007-10-07 17:16:07 +05:30
|
|
|
!yp_master (nis_domain, "passwd.byname", &nis_master)) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr, _("%s: %s is the NIS master\n"),
|
|
|
|
Prog, nis_master);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2007-10-07 17:14:59 +05:30
|
|
|
exit (E_NOTFOUND);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
* lib/prototypes.h, configure.in, libmisc/Makefile.am,
libmisc/xgetXXbyYY.c, libmisc/xgetpwnam.c, libmisc/xgetpwuid.c,
libmisc/xgetgrnam.c, libmisc/xgetgrgid.c, libmisc/xgetspnam.c:
Added functions xgetpwnam(), xgetpwuid(), xgetgrnam(),
xgetgrgid(), and xgetspnam(). They allocate memory for the
returned structure and are more robust to successive calls. They
are implemented with the libc's getxxyyy_r() functions if
available.
* libmisc/limits.c, libmisc/entry.c, libmisc/chowntty.c,
libmisc/addgrps.c, libmisc/myname.c, libmisc/rlogin.c,
libmisc/pwdcheck.c, src/newgrp.c, src/login_nopam.c,
src/userdel.c, src/lastlog.c, src/grpck.c, src/gpasswd.c,
src/newusers.c, src/chpasswd.c, src/chfn.c, src/groupmems.c,
src/usermod.c, src/expiry.c, src/groupdel.c, src/chgpasswd.c,
src/su.c, src/useradd.c, src/groupmod.c, src/passwd.c, src/pwck.c,
src/groupadd.c, src/chage.c, src/login.c, src/suauth.c,
src/faillog.c, src/groups.c, src/chsh.c, src/id.c: Review all the
usage of one of the getpwnam(), getpwuid(), getgrnam(),
getgrgid(), and getspnam() functions. It was noticed on
http://bugs.debian.org/341230 that chfn and chsh use a passwd
structure after calling a pam function, which result in using
information from the passwd structure requested by pam, not the
original one. It is much easier to use the new xget... functions
to avoid these issues. I've checked which call to the original
get... functions could be left (reducing the scope of the
structure if possible), and I've left comments to ease future
reviews (e.g. /* local, no need for xgetpwnam */).
Note: the getpwent/getgrent calls should probably be checked also.
* src/groupdel.c, src/expiry.c: Fix typos in comments.
* src/groupmod.c: Re-indent.
* libmisc/Makefile.am, lib/groupmem.c, lib/groupio.c, lib/pwmem.c,
lib/pwio.c, lib/shadowmem.c, lib/shadowio.c: Move the __<xx>_dup
functions (used by the xget... functions) from the <xx>io.c files
to the new <xx>mem.c files. This avoid linking some utils against
the SELinux library.
2007-11-19 04:45:26 +05:30
|
|
|
{
|
|
|
|
const struct spwd *spwd = NULL;
|
|
|
|
/* local, no need for xgetspnam */
|
|
|
|
if (is_shadow_pwd && (spwd = getspnam (user_name))) {
|
|
|
|
user_expire = spwd->sp_expire;
|
|
|
|
user_inactive = spwd->sp_inact;
|
|
|
|
user_newexpire = user_expire;
|
|
|
|
user_newinactive = user_inactive;
|
|
|
|
}
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2007-10-07 17:16:25 +05:30
|
|
|
|
2007-10-07 17:17:11 +05:30
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Parse the command line options.
|
|
|
|
*/
|
|
|
|
int c;
|
|
|
|
static struct option long_options[] = {
|
2007-10-07 20:06:51 +05:30
|
|
|
{"append", no_argument, NULL, 'a'},
|
2007-10-07 17:17:11 +05:30
|
|
|
{"comment", required_argument, NULL, 'c'},
|
|
|
|
{"home", required_argument, NULL, 'd'},
|
|
|
|
{"expiredate", required_argument, NULL, 'e'},
|
|
|
|
{"inactive", required_argument, NULL, 'f'},
|
|
|
|
{"gid", required_argument, NULL, 'g'},
|
|
|
|
{"groups", required_argument, NULL, 'G'},
|
|
|
|
{"help", no_argument, NULL, 'h'},
|
|
|
|
{"login", required_argument, NULL, 'l'},
|
|
|
|
{"lock", no_argument, NULL, 'L'},
|
|
|
|
{"move-home", no_argument, NULL, 'm'},
|
|
|
|
{"non-unique", no_argument, NULL, 'o'},
|
|
|
|
{"password", required_argument, NULL, 'p'},
|
|
|
|
{"shell", required_argument, NULL, 's'},
|
|
|
|
{"uid", required_argument, NULL, 'u'},
|
|
|
|
{"unlock", no_argument, NULL, 'U'},
|
|
|
|
{NULL, 0, NULL, '\0'}
|
|
|
|
};
|
|
|
|
while ((c =
|
2007-10-07 17:17:57 +05:30
|
|
|
getopt_long (argc, argv, "ac:d:e:f:g:G:hl:Lmop:s:u:U",
|
2007-10-07 17:17:11 +05:30
|
|
|
long_options, NULL)) != -1) {
|
|
|
|
switch (c) {
|
|
|
|
case 'a':
|
|
|
|
aflg++;
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
if (!VALID (optarg)) {
|
|
|
|
fprintf (stderr,
|
2007-10-07 17:17:33 +05:30
|
|
|
_("%s: invalid field '%s'\n"),
|
2007-10-07 17:17:11 +05:30
|
|
|
Prog, optarg);
|
|
|
|
exit (E_BAD_ARG);
|
|
|
|
}
|
|
|
|
user_newcomment = optarg;
|
|
|
|
cflg++;
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
if (!VALID (optarg)) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr,
|
2007-10-07 17:17:33 +05:30
|
|
|
_("%s: invalid field '%s'\n"),
|
2007-10-07 17:14:59 +05:30
|
|
|
Prog, optarg);
|
|
|
|
exit (E_BAD_ARG);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2007-10-07 17:17:11 +05:30
|
|
|
dflg++;
|
|
|
|
user_newhome = optarg;
|
|
|
|
break;
|
|
|
|
case 'e':
|
|
|
|
if (*optarg) {
|
|
|
|
user_newexpire = strtoday (optarg);
|
|
|
|
if (user_newexpire == -1) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_
|
2007-10-07 17:17:33 +05:30
|
|
|
("%s: invalid date '%s'\n"),
|
2007-10-07 17:17:11 +05:30
|
|
|
Prog, optarg);
|
|
|
|
exit (E_BAD_ARG);
|
|
|
|
}
|
|
|
|
user_newexpire *= DAY / SCALE;
|
|
|
|
} else
|
|
|
|
user_newexpire = -1;
|
|
|
|
eflg++;
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
user_newinactive = get_number (optarg);
|
|
|
|
fflg++;
|
|
|
|
break;
|
|
|
|
case 'g':
|
|
|
|
grp = getgr_nam_gid (optarg);
|
|
|
|
if (!grp) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: unknown group %s\n"),
|
|
|
|
Prog, optarg);
|
|
|
|
exit (E_NOTFOUND);
|
|
|
|
}
|
|
|
|
user_newgid = grp->gr_gid;
|
|
|
|
gflg++;
|
|
|
|
break;
|
|
|
|
case 'G':
|
|
|
|
if (get_groups (optarg))
|
|
|
|
exit (E_NOTFOUND);
|
|
|
|
Gflg++;
|
|
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
if (!check_user_name (optarg)) {
|
|
|
|
fprintf (stderr,
|
2007-10-07 17:17:33 +05:30
|
|
|
_("%s: invalid field '%s'\n"),
|
2007-10-07 17:17:11 +05:30
|
|
|
Prog, optarg);
|
|
|
|
exit (E_BAD_ARG);
|
|
|
|
}
|
2008-01-24 03:20:27 +05:30
|
|
|
lflg++;
|
2007-10-07 17:17:11 +05:30
|
|
|
user_newname = optarg;
|
|
|
|
break;
|
|
|
|
case 'L':
|
|
|
|
Lflg++;
|
|
|
|
break;
|
|
|
|
case 'm':
|
|
|
|
mflg++;
|
|
|
|
break;
|
|
|
|
case 'o':
|
|
|
|
oflg++;
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
user_pass = optarg;
|
|
|
|
pflg++;
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
if (!VALID (optarg)) {
|
|
|
|
fprintf (stderr,
|
2007-10-07 17:17:33 +05:30
|
|
|
_("%s: invalid field '%s'\n"),
|
2007-10-07 17:17:11 +05:30
|
|
|
Prog, optarg);
|
|
|
|
exit (E_BAD_ARG);
|
|
|
|
}
|
|
|
|
user_newshell = optarg;
|
|
|
|
sflg++;
|
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
user_newid = get_id (optarg);
|
|
|
|
uflg++;
|
|
|
|
break;
|
|
|
|
case 'U':
|
|
|
|
Uflg++;
|
|
|
|
break;
|
|
|
|
default:
|
2007-10-07 17:14:32 +05:30
|
|
|
usage ();
|
2007-10-07 17:17:11 +05:30
|
|
|
}
|
|
|
|
anyflag++;
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
}
|
2007-10-07 17:17:11 +05:30
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
if (anyflag == 0) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr, _("%s: no flags given\n"), Prog);
|
|
|
|
exit (E_USAGE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2008-01-24 03:20:27 +05:30
|
|
|
|
|
|
|
if (user_newid == user_id) {
|
|
|
|
uflg = 0;
|
|
|
|
}
|
|
|
|
if (user_newgid == user_gid) {
|
|
|
|
gflg = 0;
|
|
|
|
}
|
|
|
|
if (strcmp (user_newshell, user_shell) == 0) {
|
|
|
|
sflg = 0;
|
|
|
|
}
|
|
|
|
if (strcmp (user_newname, user_name) == 0) {
|
|
|
|
lflg = 0;
|
|
|
|
}
|
|
|
|
if (user_newinactive == user_inactive) {
|
|
|
|
fflg = 0;
|
|
|
|
}
|
|
|
|
if (user_newexpire == user_expire) {
|
|
|
|
eflg = 0;
|
|
|
|
}
|
|
|
|
if (strcmp (user_newhome, user_home) == 0) {
|
|
|
|
dflg = 0;
|
|
|
|
}
|
|
|
|
if (strcmp (user_newcomment, user_comment) == 0) {
|
|
|
|
cflg = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Uflg + uflg + sflg + pflg + oflg + mflg + Lflg + lflg + Gflg +
|
|
|
|
gflg + fflg + eflg + dflg + cflg == 0) {
|
|
|
|
fprintf (stderr, _("%s: no changes\n"), Prog);
|
|
|
|
exit (E_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
if (!is_shadow_pwd && (eflg || fflg)) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_
|
|
|
|
("%s: shadow passwords required for -e and -f\n"),
|
|
|
|
Prog);
|
|
|
|
exit (E_USAGE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
if (optind != argc - 1)
|
|
|
|
usage ();
|
|
|
|
|
2007-10-07 17:16:34 +05:30
|
|
|
if (aflg && (!Gflg)) {
|
|
|
|
fprintf (stderr,
|
2007-11-17 20:19:39 +05:30
|
|
|
_("%s: %s flag is ONLY allowed with the %s flag\n"),
|
|
|
|
Prog, "-a", "-G");
|
2007-10-07 17:16:34 +05:30
|
|
|
usage ();
|
|
|
|
exit (E_USAGE);
|
|
|
|
}
|
|
|
|
|
2007-11-17 20:03:26 +05:30
|
|
|
if ((Lflg && (pflg || Uflg)) || (pflg && Uflg)) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: the -L, -p, and -U flags are exclusive\n"),
|
|
|
|
Prog);
|
|
|
|
usage ();
|
|
|
|
exit (E_USAGE);
|
|
|
|
}
|
|
|
|
|
2007-11-17 20:10:54 +05:30
|
|
|
if (oflg && !uflg) {
|
|
|
|
fprintf (stderr,
|
2007-11-17 20:19:39 +05:30
|
|
|
_("%s: %s flag is ONLY allowed with the %s flag\n"),
|
|
|
|
Prog, "-o", "-u");
|
2007-11-17 20:10:54 +05:30
|
|
|
usage ();
|
|
|
|
exit (E_USAGE);
|
|
|
|
}
|
|
|
|
|
2007-11-17 19:51:05 +05:30
|
|
|
if (mflg && !dflg) {
|
|
|
|
fprintf (stderr,
|
2007-11-17 20:19:39 +05:30
|
|
|
_("%s: %s flag is ONLY allowed with the %s flag\n"),
|
|
|
|
Prog, "-m", "-d");
|
2007-11-17 19:51:05 +05:30
|
|
|
usage ();
|
|
|
|
exit (E_USAGE);
|
|
|
|
}
|
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
if (dflg && strcmp (user_home, user_newhome) == 0)
|
|
|
|
dflg = mflg = 0;
|
|
|
|
|
|
|
|
if (uflg && user_id == user_newid)
|
|
|
|
uflg = oflg = 0;
|
|
|
|
|
* lib/prototypes.h, configure.in, libmisc/Makefile.am,
libmisc/xgetXXbyYY.c, libmisc/xgetpwnam.c, libmisc/xgetpwuid.c,
libmisc/xgetgrnam.c, libmisc/xgetgrgid.c, libmisc/xgetspnam.c:
Added functions xgetpwnam(), xgetpwuid(), xgetgrnam(),
xgetgrgid(), and xgetspnam(). They allocate memory for the
returned structure and are more robust to successive calls. They
are implemented with the libc's getxxyyy_r() functions if
available.
* libmisc/limits.c, libmisc/entry.c, libmisc/chowntty.c,
libmisc/addgrps.c, libmisc/myname.c, libmisc/rlogin.c,
libmisc/pwdcheck.c, src/newgrp.c, src/login_nopam.c,
src/userdel.c, src/lastlog.c, src/grpck.c, src/gpasswd.c,
src/newusers.c, src/chpasswd.c, src/chfn.c, src/groupmems.c,
src/usermod.c, src/expiry.c, src/groupdel.c, src/chgpasswd.c,
src/su.c, src/useradd.c, src/groupmod.c, src/passwd.c, src/pwck.c,
src/groupadd.c, src/chage.c, src/login.c, src/suauth.c,
src/faillog.c, src/groups.c, src/chsh.c, src/id.c: Review all the
usage of one of the getpwnam(), getpwuid(), getgrnam(),
getgrgid(), and getspnam() functions. It was noticed on
http://bugs.debian.org/341230 that chfn and chsh use a passwd
structure after calling a pam function, which result in using
information from the passwd structure requested by pam, not the
original one. It is much easier to use the new xget... functions
to avoid these issues. I've checked which call to the original
get... functions could be left (reducing the scope of the
structure if possible), and I've left comments to ease future
reviews (e.g. /* local, no need for xgetpwnam */).
Note: the getpwent/getgrent calls should probably be checked also.
* src/groupdel.c, src/expiry.c: Fix typos in comments.
* src/groupmod.c: Re-indent.
* libmisc/Makefile.am, lib/groupmem.c, lib/groupio.c, lib/pwmem.c,
lib/pwio.c, lib/shadowmem.c, lib/shadowio.c: Move the __<xx>_dup
functions (used by the xget... functions) from the <xx>io.c files
to the new <xx>mem.c files. This avoid linking some utils against
the SELinux library.
2007-11-19 04:45:26 +05:30
|
|
|
/* local, no need for xgetpwnam */
|
2007-10-07 17:14:02 +05:30
|
|
|
if (lflg && getpwnam (user_newname)) {
|
2007-10-07 17:16:07 +05:30
|
|
|
fprintf (stderr, _("%s: user %s exists\n"), Prog, user_newname);
|
2007-10-07 17:14:59 +05:30
|
|
|
exit (E_NAME_IN_USE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
* lib/prototypes.h, configure.in, libmisc/Makefile.am,
libmisc/xgetXXbyYY.c, libmisc/xgetpwnam.c, libmisc/xgetpwuid.c,
libmisc/xgetgrnam.c, libmisc/xgetgrgid.c, libmisc/xgetspnam.c:
Added functions xgetpwnam(), xgetpwuid(), xgetgrnam(),
xgetgrgid(), and xgetspnam(). They allocate memory for the
returned structure and are more robust to successive calls. They
are implemented with the libc's getxxyyy_r() functions if
available.
* libmisc/limits.c, libmisc/entry.c, libmisc/chowntty.c,
libmisc/addgrps.c, libmisc/myname.c, libmisc/rlogin.c,
libmisc/pwdcheck.c, src/newgrp.c, src/login_nopam.c,
src/userdel.c, src/lastlog.c, src/grpck.c, src/gpasswd.c,
src/newusers.c, src/chpasswd.c, src/chfn.c, src/groupmems.c,
src/usermod.c, src/expiry.c, src/groupdel.c, src/chgpasswd.c,
src/su.c, src/useradd.c, src/groupmod.c, src/passwd.c, src/pwck.c,
src/groupadd.c, src/chage.c, src/login.c, src/suauth.c,
src/faillog.c, src/groups.c, src/chsh.c, src/id.c: Review all the
usage of one of the getpwnam(), getpwuid(), getgrnam(),
getgrgid(), and getspnam() functions. It was noticed on
http://bugs.debian.org/341230 that chfn and chsh use a passwd
structure after calling a pam function, which result in using
information from the passwd structure requested by pam, not the
original one. It is much easier to use the new xget... functions
to avoid these issues. I've checked which call to the original
get... functions could be left (reducing the scope of the
structure if possible), and I've left comments to ease future
reviews (e.g. /* local, no need for xgetpwnam */).
Note: the getpwent/getgrent calls should probably be checked also.
* src/groupdel.c, src/expiry.c: Fix typos in comments.
* src/groupmod.c: Re-indent.
* libmisc/Makefile.am, lib/groupmem.c, lib/groupio.c, lib/pwmem.c,
lib/pwio.c, lib/shadowmem.c, lib/shadowio.c: Move the __<xx>_dup
functions (used by the xget... functions) from the <xx>io.c files
to the new <xx>mem.c files. This avoid linking some utils against
the SELinux library.
2007-11-19 04:45:26 +05:30
|
|
|
/* local, no need for xgetpwuid */
|
2007-10-07 17:14:59 +05:30
|
|
|
if (uflg && !oflg && getpwuid (user_newid)) {
|
|
|
|
fprintf (stderr, _("%s: uid %lu is not unique\n"),
|
|
|
|
Prog, (unsigned long) user_newid);
|
|
|
|
exit (E_UID_IN_USE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* close_files - close all of the files that were opened
|
|
|
|
*
|
2007-10-07 17:14:59 +05:30
|
|
|
* close_files() closes all of the files that were opened for this new
|
|
|
|
* user. This causes any modified entries to be written out.
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
static void close_files (void)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
2007-10-07 17:14:59 +05:30
|
|
|
if (!pw_close ()) {
|
2007-10-07 17:16:07 +05:30
|
|
|
fprintf (stderr, _("%s: cannot rewrite password file\n"), Prog);
|
2007-10-07 17:14:59 +05:30
|
|
|
fail_exit (E_PW_UPDATE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2007-10-07 17:14:59 +05:30
|
|
|
if (is_shadow_pwd && !spw_close ()) {
|
|
|
|
fprintf (stderr,
|
2007-10-07 17:16:07 +05:30
|
|
|
_("%s: cannot rewrite shadow password file\n"), Prog);
|
2007-10-07 17:14:59 +05:30
|
|
|
fail_exit (E_PW_UPDATE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2007-11-17 17:12:47 +05:30
|
|
|
|
|
|
|
if (Gflg || lflg) {
|
|
|
|
if (!gr_close ()) {
|
|
|
|
fprintf (stderr, _("%s: cannot rewrite group file\n"),
|
|
|
|
Prog);
|
|
|
|
fail_exit (E_GRP_UPDATE);
|
|
|
|
}
|
|
|
|
#ifdef SHADOWGRP
|
|
|
|
if (is_shadow_grp && !sgr_close ()) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: cannot rewrite shadow group file\n"),
|
|
|
|
Prog);
|
|
|
|
fail_exit (E_GRP_UPDATE);
|
|
|
|
}
|
|
|
|
if (is_shadow_grp)
|
|
|
|
sgr_unlock ();
|
|
|
|
#endif
|
|
|
|
gr_unlock ();
|
|
|
|
}
|
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
if (is_shadow_pwd)
|
|
|
|
spw_unlock ();
|
2007-11-17 17:12:47 +05:30
|
|
|
pw_unlock ();
|
|
|
|
|
|
|
|
pw_locked = 0;
|
|
|
|
spw_locked = 0;
|
|
|
|
gr_locked = 0;
|
|
|
|
sgr_locked = 0;
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
/*
|
|
|
|
* Close the DBM and/or flat files
|
|
|
|
*/
|
|
|
|
endpwent ();
|
|
|
|
endspent ();
|
|
|
|
endgrent ();
|
|
|
|
#ifdef SHADOWGRP
|
|
|
|
endsgent ();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* open_files - lock and open the password files
|
|
|
|
*
|
|
|
|
* open_files() opens the two password files.
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
static void open_files (void)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
2007-10-07 17:14:59 +05:30
|
|
|
if (!pw_lock ()) {
|
2007-10-07 17:16:07 +05:30
|
|
|
fprintf (stderr, _("%s: unable to lock password file\n"), Prog);
|
2007-11-17 17:12:47 +05:30
|
|
|
fail_exit (E_PW_UPDATE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2007-11-17 17:12:47 +05:30
|
|
|
pw_locked = 1;
|
2007-10-07 17:14:59 +05:30
|
|
|
if (!pw_open (O_RDWR)) {
|
2007-10-07 17:16:07 +05:30
|
|
|
fprintf (stderr, _("%s: unable to open password file\n"), Prog);
|
2007-10-07 17:14:59 +05:30
|
|
|
fail_exit (E_PW_UPDATE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2007-10-07 17:14:59 +05:30
|
|
|
if (is_shadow_pwd && !spw_lock ()) {
|
|
|
|
fprintf (stderr,
|
2007-10-07 17:16:07 +05:30
|
|
|
_("%s: cannot lock shadow password file\n"), Prog);
|
2007-10-07 17:14:59 +05:30
|
|
|
fail_exit (E_PW_UPDATE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2007-11-17 17:12:47 +05:30
|
|
|
spw_locked = 1;
|
2007-10-07 17:14:59 +05:30
|
|
|
if (is_shadow_pwd && !spw_open (O_RDWR)) {
|
|
|
|
fprintf (stderr,
|
2007-10-07 17:16:07 +05:30
|
|
|
_("%s: cannot open shadow password file\n"), Prog);
|
2007-10-07 17:14:59 +05:30
|
|
|
fail_exit (E_PW_UPDATE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2007-11-17 17:12:47 +05:30
|
|
|
|
|
|
|
if (Gflg || lflg) {
|
|
|
|
/*
|
|
|
|
* Lock and open the group file. This will load all of the
|
|
|
|
* group entries.
|
|
|
|
*/
|
|
|
|
if (!gr_lock ()) {
|
|
|
|
fprintf (stderr, _("%s: error locking group file\n"),
|
|
|
|
Prog);
|
|
|
|
fail_exit (E_GRP_UPDATE);
|
|
|
|
}
|
|
|
|
gr_locked = 1;
|
|
|
|
if (!gr_open (O_RDWR)) {
|
|
|
|
fprintf (stderr, _("%s: error opening group file\n"),
|
|
|
|
Prog);
|
|
|
|
fail_exit (E_GRP_UPDATE);
|
|
|
|
}
|
|
|
|
#ifdef SHADOWGRP
|
|
|
|
if (is_shadow_grp && !sgr_lock ()) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: error locking shadow group file\n"),
|
|
|
|
Prog);
|
|
|
|
fail_exit (E_GRP_UPDATE);
|
|
|
|
}
|
|
|
|
sgr_locked = 1;
|
|
|
|
if (is_shadow_grp && !sgr_open (O_RDWR)) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: error opening shadow group file\n"),
|
|
|
|
Prog);
|
|
|
|
fail_exit (E_GRP_UPDATE);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* usr_update - create the user entries
|
|
|
|
*
|
2007-10-07 17:14:59 +05:30
|
|
|
* usr_update() creates the password file entries for this user and
|
|
|
|
* will update the group entries if required.
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
static void usr_update (void)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
|
|
|
struct passwd pwent;
|
|
|
|
const struct passwd *pwd;
|
2007-10-07 17:14:59 +05:30
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
struct spwd spent;
|
|
|
|
const struct spwd *spwd = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Locate the entry in /etc/passwd, which MUST exist.
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
pwd = pw_locate (user_name);
|
2007-10-07 17:14:02 +05:30
|
|
|
if (!pwd) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr, _("%s: %s not found in /etc/passwd\n"),
|
|
|
|
Prog, user_name);
|
|
|
|
fail_exit (E_NOTFOUND);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
pwent = *pwd;
|
|
|
|
new_pwent (&pwent);
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2007-10-07 17:14:59 +05:30
|
|
|
* Locate the entry in /etc/shadow. It doesn't have to exist, and
|
|
|
|
* won't be created if it doesn't.
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
if (is_shadow_pwd && (spwd = spw_locate (user_name))) {
|
2007-10-07 17:14:02 +05:30
|
|
|
spent = *spwd;
|
|
|
|
new_spent (&spent);
|
|
|
|
}
|
|
|
|
|
2007-10-07 17:15:23 +05:30
|
|
|
if (lflg || uflg || gflg || cflg || dflg || sflg || pflg
|
2007-10-07 17:14:59 +05:30
|
|
|
|| Lflg || Uflg) {
|
|
|
|
if (!pw_update (&pwent)) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: error changing password entry\n"),
|
|
|
|
Prog);
|
|
|
|
fail_exit (E_PW_UPDATE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2007-10-07 17:14:59 +05:30
|
|
|
if (lflg && !pw_remove (user_name)) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: error removing password entry\n"),
|
|
|
|
Prog);
|
|
|
|
fail_exit (E_PW_UPDATE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
}
|
2007-10-07 17:15:23 +05:30
|
|
|
if (spwd && (lflg || eflg || fflg || pflg || Lflg || Uflg)) {
|
2007-10-07 17:14:59 +05:30
|
|
|
if (!spw_update (&spent)) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_
|
|
|
|
("%s: error adding new shadow password entry\n"),
|
|
|
|
Prog);
|
|
|
|
fail_exit (E_PW_UPDATE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2007-10-07 17:14:59 +05:30
|
|
|
if (lflg && !spw_remove (user_name)) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_
|
|
|
|
("%s: error removing shadow password entry\n"),
|
|
|
|
Prog);
|
|
|
|
fail_exit (E_PW_UPDATE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* move_home - move the user's home directory
|
|
|
|
*
|
2007-10-07 17:14:59 +05:30
|
|
|
* move_home() moves the user's home directory to a new location. The
|
|
|
|
* files will be copied if the directory cannot simply be renamed.
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
static void move_home (void)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
2007-10-07 17:14:59 +05:30
|
|
|
struct stat sb;
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
if (mflg && stat (user_home, &sb) == 0) {
|
|
|
|
/*
|
|
|
|
* Don't try to move it if it is not a directory
|
|
|
|
* (but /dev/null for example). --marekm
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
if (!S_ISDIR (sb.st_mode))
|
2007-10-07 17:14:02 +05:30
|
|
|
return;
|
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
if (access (user_newhome, F_OK) == 0) {
|
|
|
|
fprintf (stderr, _("%s: directory %s exists\n"),
|
|
|
|
Prog, user_newhome);
|
|
|
|
fail_exit (E_HOMEDIR);
|
2007-10-07 17:14:02 +05:30
|
|
|
} else if (rename (user_home, user_newhome)) {
|
|
|
|
if (errno == EXDEV) {
|
2007-10-07 17:16:07 +05:30
|
|
|
if (mkdir (user_newhome, sb.st_mode & 0777)) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_
|
|
|
|
("%s: can't create %s\n"),
|
|
|
|
Prog, user_newhome);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2007-10-07 17:16:07 +05:30
|
|
|
if (chown (user_newhome, sb.st_uid, sb.st_gid)) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: can't chown %s\n"),
|
|
|
|
Prog, user_newhome);
|
2007-10-07 17:14:02 +05:30
|
|
|
rmdir (user_newhome);
|
2007-10-07 17:14:59 +05:30
|
|
|
fail_exit (E_HOMEDIR);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
if (copy_tree (user_home, user_newhome,
|
2008-01-01 20:01:00 +05:30
|
|
|
uflg ? (long int)user_newid : -1,
|
|
|
|
gflg ? (long int)user_newgid : -1) == 0) {
|
2007-10-07 17:16:25 +05:30
|
|
|
if (remove_tree (user_home) != 0 ||
|
|
|
|
rmdir (user_home) != 0)
|
|
|
|
fprintf (stderr,
|
|
|
|
_
|
|
|
|
("%s: warning: failed to completely remove old home directory %s"),
|
|
|
|
Prog, user_home);
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK,
|
|
|
|
Prog,
|
|
|
|
"moving home directory",
|
|
|
|
user_newname, user_newid,
|
|
|
|
1);
|
|
|
|
#endif
|
2007-10-07 17:14:02 +05:30
|
|
|
return;
|
2007-10-07 17:16:25 +05:30
|
|
|
}
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
(void) remove_tree (user_newhome);
|
|
|
|
(void) rmdir (user_newhome);
|
|
|
|
}
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_
|
|
|
|
("%s: cannot rename directory %s to %s\n"),
|
|
|
|
Prog, user_home, user_newhome);
|
|
|
|
fail_exit (E_HOMEDIR);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
|
|
|
"moving home directory", user_newname, user_newid,
|
|
|
|
1);
|
|
|
|
#endif
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2007-10-07 17:17:01 +05:30
|
|
|
if (uflg || gflg) {
|
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
|
|
|
"changing home directory owner", user_newname,
|
|
|
|
user_newid, 1);
|
|
|
|
#endif
|
2007-10-07 17:14:59 +05:30
|
|
|
chown (dflg ? user_newhome : user_home,
|
|
|
|
uflg ? user_newid : user_id,
|
|
|
|
gflg ? user_newgid : user_gid);
|
2007-10-07 17:17:01 +05:30
|
|
|
}
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* update_files - update the lastlog and faillog files
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
static void update_files (void)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
2007-10-07 17:14:59 +05:30
|
|
|
struct lastlog ll;
|
|
|
|
struct faillog fl;
|
|
|
|
int fd;
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
/*
|
2007-10-07 17:14:59 +05:30
|
|
|
* Relocate the "lastlog" entries for the user. The old entry is
|
|
|
|
* left alone in case the UID was shared. It doesn't hurt anything
|
|
|
|
* to just leave it be.
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
if ((fd = open (LASTLOG_FILE, O_RDWR)) != -1) {
|
|
|
|
lseek (fd, (off_t) user_id * sizeof ll, SEEK_SET);
|
|
|
|
if (read (fd, (char *) &ll, sizeof ll) == sizeof ll) {
|
2007-10-07 17:16:07 +05:30
|
|
|
lseek (fd, (off_t) user_newid * sizeof ll, SEEK_SET);
|
2007-10-07 17:14:59 +05:30
|
|
|
write (fd, (char *) &ll, sizeof ll);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2007-10-07 17:14:59 +05:30
|
|
|
close (fd);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Relocate the "faillog" entries in the same manner.
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
if ((fd = open (FAILLOG_FILE, O_RDWR)) != -1) {
|
|
|
|
lseek (fd, (off_t) user_id * sizeof fl, SEEK_SET);
|
|
|
|
if (read (fd, (char *) &fl, sizeof fl) == sizeof fl) {
|
2007-10-07 17:16:07 +05:30
|
|
|
lseek (fd, (off_t) user_newid * sizeof fl, SEEK_SET);
|
2007-10-07 17:14:59 +05:30
|
|
|
write (fd, (char *) &fl, sizeof fl);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2007-10-07 17:14:59 +05:30
|
|
|
close (fd);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef NO_MOVE_MAILBOX
|
|
|
|
/*
|
|
|
|
* This is the new and improved code to carefully chown/rename the user's
|
2007-10-07 17:14:59 +05:30
|
|
|
* mailbox. Maybe I am too paranoid but the mail spool dir sometimes
|
2007-10-07 17:14:02 +05:30
|
|
|
* happens to be mode 1777 (this makes mail user agents work without
|
|
|
|
* being setgid mail, but is NOT recommended; they all should be fixed
|
|
|
|
* to use movemail). --marekm
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
static void move_mailbox (void)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
|
|
|
const char *maildir;
|
|
|
|
char mailfile[1024], newmailfile[1024];
|
|
|
|
int fd;
|
|
|
|
struct stat st;
|
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
maildir = getdef_str ("MAIL_DIR");
|
2007-10-07 17:14:02 +05:30
|
|
|
#ifdef MAIL_SPOOL_DIR
|
2007-10-07 17:14:59 +05:30
|
|
|
if (!maildir && !getdef_str ("MAIL_FILE"))
|
2007-10-07 17:14:02 +05:30
|
|
|
maildir = MAIL_SPOOL_DIR;
|
|
|
|
#endif
|
|
|
|
if (!maildir)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* O_NONBLOCK is to make sure open won't hang on mandatory locks.
|
|
|
|
* We do fstat/fchown to make sure there are no races (someone
|
|
|
|
* replacing /var/spool/mail/luser with a hard link to /etc/passwd
|
|
|
|
* between stat and chown). --marekm
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
snprintf (mailfile, sizeof mailfile, "%s/%s", maildir, user_name);
|
|
|
|
fd = open (mailfile, O_RDONLY | O_NONBLOCK, 0);
|
2007-10-07 17:14:02 +05:30
|
|
|
if (fd < 0) {
|
|
|
|
/* no need for warnings if the mailbox doesn't exist */
|
|
|
|
if (errno != ENOENT)
|
2007-10-07 17:14:59 +05:30
|
|
|
perror (mailfile);
|
2007-10-07 17:14:02 +05:30
|
|
|
return;
|
|
|
|
}
|
2007-10-07 17:14:59 +05:30
|
|
|
if (fstat (fd, &st) < 0) {
|
|
|
|
perror ("fstat");
|
|
|
|
close (fd);
|
2007-10-07 17:14:02 +05:30
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (st.st_uid != user_id) {
|
|
|
|
/* better leave it alone */
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr, _("%s: warning: %s not owned by %s\n"),
|
|
|
|
Prog, mailfile, user_name);
|
|
|
|
close (fd);
|
2007-10-07 17:14:02 +05:30
|
|
|
return;
|
|
|
|
}
|
2007-10-07 17:17:01 +05:30
|
|
|
if (uflg) {
|
|
|
|
if (fchown (fd, user_newid, (gid_t) - 1) < 0) {
|
|
|
|
perror (_("failed to change mailbox owner"));
|
|
|
|
}
|
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
else {
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
|
|
|
"changing mail file owner", user_newname,
|
|
|
|
user_newid, 1);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
close (fd);
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
if (lflg) {
|
2007-10-07 17:14:59 +05:30
|
|
|
snprintf (newmailfile, sizeof newmailfile, "%s/%s",
|
|
|
|
maildir, user_newname);
|
2007-10-07 17:17:01 +05:30
|
|
|
if (link (mailfile, newmailfile) || unlink (mailfile)) {
|
2007-10-07 17:14:59 +05:30
|
|
|
perror (_("failed to rename mailbox"));
|
2007-10-07 17:17:01 +05:30
|
|
|
}
|
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
else {
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
|
|
|
"changing mail file name", user_newname,
|
|
|
|
user_newid, 1);
|
|
|
|
}
|
|
|
|
#endif
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* main - usermod command
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
int main (int argc, char **argv)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
2007-10-07 17:14:38 +05:30
|
|
|
#ifdef USE_PAM
|
|
|
|
pam_handle_t *pamh = NULL;
|
|
|
|
int retval;
|
|
|
|
#endif
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_help_open ();
|
|
|
|
#endif
|
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
/*
|
|
|
|
* Get my name so that I can use it to report errors.
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
Prog = Basename (argv[0]);
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
setlocale (LC_ALL, "");
|
|
|
|
bindtextdomain (PACKAGE, LOCALEDIR);
|
|
|
|
textdomain (PACKAGE);
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2007-10-07 17:15:40 +05:30
|
|
|
sys_ngroups = sysconf (_SC_NGROUPS_MAX);
|
|
|
|
user_groups = malloc ((1 + sys_ngroups) * sizeof (char *));
|
|
|
|
user_groups[0] = (char *) 0;
|
|
|
|
|
2007-10-07 17:16:07 +05:30
|
|
|
OPENLOG ("usermod");
|
2007-10-07 17:15:40 +05:30
|
|
|
|
|
|
|
is_shadow_pwd = spw_file_present ();
|
|
|
|
#ifdef SHADOWGRP
|
|
|
|
is_shadow_grp = sgr_file_present ();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
process_flags (argc, argv);
|
|
|
|
|
2007-10-07 17:14:38 +05:30
|
|
|
#ifdef USE_PAM
|
|
|
|
retval = PAM_SUCCESS;
|
|
|
|
|
* lib/prototypes.h, configure.in, libmisc/Makefile.am,
libmisc/xgetXXbyYY.c, libmisc/xgetpwnam.c, libmisc/xgetpwuid.c,
libmisc/xgetgrnam.c, libmisc/xgetgrgid.c, libmisc/xgetspnam.c:
Added functions xgetpwnam(), xgetpwuid(), xgetgrnam(),
xgetgrgid(), and xgetspnam(). They allocate memory for the
returned structure and are more robust to successive calls. They
are implemented with the libc's getxxyyy_r() functions if
available.
* libmisc/limits.c, libmisc/entry.c, libmisc/chowntty.c,
libmisc/addgrps.c, libmisc/myname.c, libmisc/rlogin.c,
libmisc/pwdcheck.c, src/newgrp.c, src/login_nopam.c,
src/userdel.c, src/lastlog.c, src/grpck.c, src/gpasswd.c,
src/newusers.c, src/chpasswd.c, src/chfn.c, src/groupmems.c,
src/usermod.c, src/expiry.c, src/groupdel.c, src/chgpasswd.c,
src/su.c, src/useradd.c, src/groupmod.c, src/passwd.c, src/pwck.c,
src/groupadd.c, src/chage.c, src/login.c, src/suauth.c,
src/faillog.c, src/groups.c, src/chsh.c, src/id.c: Review all the
usage of one of the getpwnam(), getpwuid(), getgrnam(),
getgrgid(), and getspnam() functions. It was noticed on
http://bugs.debian.org/341230 that chfn and chsh use a passwd
structure after calling a pam function, which result in using
information from the passwd structure requested by pam, not the
original one. It is much easier to use the new xget... functions
to avoid these issues. I've checked which call to the original
get... functions could be left (reducing the scope of the
structure if possible), and I've left comments to ease future
reviews (e.g. /* local, no need for xgetpwnam */).
Note: the getpwent/getgrent calls should probably be checked also.
* src/groupdel.c, src/expiry.c: Fix typos in comments.
* src/groupmod.c: Re-indent.
* libmisc/Makefile.am, lib/groupmem.c, lib/groupio.c, lib/pwmem.c,
lib/pwio.c, lib/shadowmem.c, lib/shadowio.c: Move the __<xx>_dup
functions (used by the xget... functions) from the <xx>io.c files
to the new <xx>mem.c files. This avoid linking some utils against
the SELinux library.
2007-11-19 04:45:26 +05:30
|
|
|
{
|
|
|
|
struct passwd *pampw;
|
|
|
|
pampw = getpwuid (getuid ()); /* local, no need for xgetpwuid */
|
|
|
|
if (pampw == NULL) {
|
|
|
|
retval = PAM_USER_UNKNOWN;
|
|
|
|
}
|
2007-10-07 17:14:38 +05:30
|
|
|
|
* lib/prototypes.h, configure.in, libmisc/Makefile.am,
libmisc/xgetXXbyYY.c, libmisc/xgetpwnam.c, libmisc/xgetpwuid.c,
libmisc/xgetgrnam.c, libmisc/xgetgrgid.c, libmisc/xgetspnam.c:
Added functions xgetpwnam(), xgetpwuid(), xgetgrnam(),
xgetgrgid(), and xgetspnam(). They allocate memory for the
returned structure and are more robust to successive calls. They
are implemented with the libc's getxxyyy_r() functions if
available.
* libmisc/limits.c, libmisc/entry.c, libmisc/chowntty.c,
libmisc/addgrps.c, libmisc/myname.c, libmisc/rlogin.c,
libmisc/pwdcheck.c, src/newgrp.c, src/login_nopam.c,
src/userdel.c, src/lastlog.c, src/grpck.c, src/gpasswd.c,
src/newusers.c, src/chpasswd.c, src/chfn.c, src/groupmems.c,
src/usermod.c, src/expiry.c, src/groupdel.c, src/chgpasswd.c,
src/su.c, src/useradd.c, src/groupmod.c, src/passwd.c, src/pwck.c,
src/groupadd.c, src/chage.c, src/login.c, src/suauth.c,
src/faillog.c, src/groups.c, src/chsh.c, src/id.c: Review all the
usage of one of the getpwnam(), getpwuid(), getgrnam(),
getgrgid(), and getspnam() functions. It was noticed on
http://bugs.debian.org/341230 that chfn and chsh use a passwd
structure after calling a pam function, which result in using
information from the passwd structure requested by pam, not the
original one. It is much easier to use the new xget... functions
to avoid these issues. I've checked which call to the original
get... functions could be left (reducing the scope of the
structure if possible), and I've left comments to ease future
reviews (e.g. /* local, no need for xgetpwnam */).
Note: the getpwent/getgrent calls should probably be checked also.
* src/groupdel.c, src/expiry.c: Fix typos in comments.
* src/groupmod.c: Re-indent.
* libmisc/Makefile.am, lib/groupmem.c, lib/groupio.c, lib/pwmem.c,
lib/pwio.c, lib/shadowmem.c, lib/shadowio.c: Move the __<xx>_dup
functions (used by the xget... functions) from the <xx>io.c files
to the new <xx>mem.c files. This avoid linking some utils against
the SELinux library.
2007-11-19 04:45:26 +05:30
|
|
|
if (retval == PAM_SUCCESS) {
|
|
|
|
retval = pam_start ("usermod", pampw->pw_name,
|
|
|
|
&conv, &pamh);
|
|
|
|
}
|
2007-10-07 17:14:38 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
if (retval == PAM_SUCCESS) {
|
2007-10-07 17:14:59 +05:30
|
|
|
retval = pam_authenticate (pamh, 0);
|
2007-10-07 17:14:38 +05:30
|
|
|
if (retval != PAM_SUCCESS) {
|
2007-10-07 17:14:59 +05:30
|
|
|
pam_end (pamh, retval);
|
2007-10-07 17:14:38 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (retval == PAM_SUCCESS) {
|
2007-10-07 17:14:59 +05:30
|
|
|
retval = pam_acct_mgmt (pamh, 0);
|
2007-10-07 17:14:38 +05:30
|
|
|
if (retval != PAM_SUCCESS) {
|
2007-10-07 17:14:59 +05:30
|
|
|
pam_end (pamh, retval);
|
2007-10-07 17:14:38 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (retval != PAM_SUCCESS) {
|
2007-10-07 17:16:07 +05:30
|
|
|
fprintf (stderr, _("%s: PAM authentication failed\n"), Prog);
|
2007-10-07 17:14:38 +05:30
|
|
|
exit (1);
|
|
|
|
}
|
2007-10-07 17:15:40 +05:30
|
|
|
#endif /* USE_PAM */
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
/*
|
|
|
|
* Do the hard stuff - open the files, change the user entries,
|
|
|
|
* change the home directory, then close and update the files.
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
open_files ();
|
|
|
|
usr_update ();
|
2007-10-07 17:14:02 +05:30
|
|
|
if (Gflg || lflg)
|
2007-11-17 17:12:47 +05:30
|
|
|
grp_update ();
|
|
|
|
close_files ();
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2007-11-17 04:59:41 +05:30
|
|
|
nscd_flush_cache ("passwd");
|
|
|
|
nscd_flush_cache ("group");
|
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
if (mflg)
|
2007-10-07 17:14:59 +05:30
|
|
|
move_home ();
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
#ifndef NO_MOVE_MAILBOX
|
|
|
|
if (lflg || uflg)
|
2007-10-07 17:14:59 +05:30
|
|
|
move_mailbox ();
|
2007-10-07 17:14:02 +05:30
|
|
|
#endif
|
|
|
|
|
|
|
|
if (uflg) {
|
2007-10-07 17:14:59 +05:30
|
|
|
update_files ();
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
/*
|
2007-10-07 17:14:59 +05:30
|
|
|
* Change the UID on all of the files owned by `user_id' to
|
|
|
|
* `user_newid' in the user's home directory.
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
chown_tree (dflg ? user_newhome : user_home,
|
|
|
|
user_id, user_newid,
|
|
|
|
user_gid, gflg ? user_newgid : user_gid);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
2007-10-07 17:14:38 +05:30
|
|
|
#ifdef USE_PAM
|
|
|
|
if (retval == PAM_SUCCESS)
|
2007-10-07 17:14:59 +05:30
|
|
|
pam_end (pamh, PAM_SUCCESS);
|
|
|
|
#endif /* USE_PAM */
|
2007-10-07 17:14:38 +05:30
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
exit (E_SUCCESS);
|
2007-10-07 17:15:23 +05:30
|
|
|
/* NOT REACHED */
|
|
|
|
}
|