2007-10-07 17:14:02 +05:30
|
|
|
/*
|
2008-04-27 06:10:09 +05:30
|
|
|
* Copyright (c) 1991 - 1994, Julianne Frances Haugh
|
|
|
|
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
|
|
|
|
* Copyright (c) 2000 - 2006, Tomasz Kłoczko
|
|
|
|
* Copyright (c) 2007 - 2008, Nicolas François
|
2007-10-07 17:14:02 +05:30
|
|
|
* 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.
|
2008-04-27 06:10:09 +05:30
|
|
|
* 3. The name of the copyright holders or contributors may not be used to
|
|
|
|
* endorse or promote products derived from this software without
|
|
|
|
* specific prior written permission.
|
2007-10-07 17:14:02 +05:30
|
|
|
*
|
2008-04-27 06:10:09 +05:30
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
* HOLDERS OR CONTRIBUTORS BE LIABLE 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.
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
2007-11-11 05:16:11 +05:30
|
|
|
#ident "$Id$"
|
2007-10-07 17:17:01 +05:30
|
|
|
|
2007-12-26 18:48:27 +05:30
|
|
|
#include <assert.h>
|
2007-10-07 17:14:02 +05:30
|
|
|
#include <ctype.h>
|
2007-10-07 17:16:34 +05:30
|
|
|
#include <errno.h>
|
2007-10-07 17:14:02 +05:30
|
|
|
#include <fcntl.h>
|
2007-10-07 17:16:34 +05:30
|
|
|
#include <getopt.h>
|
|
|
|
#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:16:34 +05:30
|
|
|
#include <stdio.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <time.h>
|
|
|
|
#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"
|
2007-10-07 17:17:01 +05:30
|
|
|
#include "getdef.h"
|
|
|
|
#include "groupio.h"
|
2007-10-07 17:15:23 +05:30
|
|
|
#include "nscd.h"
|
2007-10-07 17:17:01 +05:30
|
|
|
#include "prototypes.h"
|
|
|
|
#include "pwauth.h"
|
|
|
|
#include "pwio.h"
|
|
|
|
#ifdef SHADOWGRP
|
|
|
|
#include "sgroupio.h"
|
|
|
|
#endif
|
|
|
|
#include "shadowio.h"
|
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
#ifndef SKEL_DIR
|
|
|
|
#define SKEL_DIR "/etc/skel"
|
|
|
|
#endif
|
|
|
|
#ifndef USER_DEFAULTS_FILE
|
|
|
|
#define USER_DEFAULTS_FILE "/etc/default/useradd"
|
|
|
|
#define NEW_USER_FILE "/etc/default/nuaddXXXXXX"
|
|
|
|
#endif
|
|
|
|
/*
|
|
|
|
* Needed for MkLinux DR1/2/2.1 - J.
|
|
|
|
*/
|
|
|
|
#ifndef LASTLOG_FILE
|
|
|
|
#define LASTLOG_FILE "/var/log/lastlog"
|
|
|
|
#endif
|
2007-10-07 17:17:01 +05:30
|
|
|
/*
|
|
|
|
* Global variables
|
|
|
|
*/
|
2007-10-07 17:14:02 +05:30
|
|
|
/*
|
|
|
|
* These defaults are used if there is no defaults file.
|
|
|
|
*/
|
|
|
|
static gid_t def_group = 100;
|
|
|
|
static const char *def_gname = "other";
|
|
|
|
static const char *def_home = "/home";
|
|
|
|
static const char *def_shell = "";
|
|
|
|
static const char *def_template = SKEL_DIR;
|
2007-10-07 17:15:40 +05:30
|
|
|
static const char *def_create_mail_spool = "no";
|
2007-10-07 17:14:59 +05:30
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
static long def_inactive = -1;
|
|
|
|
static const char *def_expire = "";
|
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
static char def_file[] = USER_DEFAULTS_FILE;
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
#define VALID(s) (strcspn (s, ":\n") == strlen (s))
|
|
|
|
|
|
|
|
static const char *user_name = "";
|
|
|
|
static const char *user_pass = "!";
|
|
|
|
static uid_t user_id;
|
|
|
|
static gid_t user_gid;
|
|
|
|
static const char *user_comment = "";
|
|
|
|
static const char *user_home = "";
|
|
|
|
static const char *user_shell = "";
|
2007-10-07 17:15:40 +05:30
|
|
|
static const char *create_mail_spool = "";
|
2007-10-07 17:14:59 +05:30
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
static long user_expire = -1;
|
2008-06-10 03:38:08 +05:30
|
|
|
static bool is_shadow_pwd;
|
2007-10-07 17:16:25 +05:30
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
#ifdef SHADOWGRP
|
2008-06-10 03:38:08 +05:30
|
|
|
static bool is_shadow_grp;
|
|
|
|
static bool gshadow_locked = false;
|
2007-10-07 17:14:02 +05:30
|
|
|
#endif
|
2008-06-10 03:38:08 +05:30
|
|
|
static bool passwd_locked = false;
|
|
|
|
static bool group_locked = false;
|
|
|
|
static bool shadow_locked = false;
|
2007-10-07 17:14:59 +05:30
|
|
|
static char **user_groups; /* NULL-terminated list */
|
2007-10-07 17:14:51 +05:30
|
|
|
static long sys_ngroups;
|
2008-06-10 03:38:08 +05:30
|
|
|
static bool do_grp_update = false; /* group files need to be updated */
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
static char *Prog;
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2008-06-10 03:38:08 +05:30
|
|
|
static bool
|
|
|
|
bflg = false, /* new default root of home directory */
|
|
|
|
cflg = false, /* comment (GECOS) field for new account */
|
|
|
|
dflg = false, /* home directory for new account */
|
|
|
|
Dflg = false, /* set/show new user default values */
|
|
|
|
eflg = false, /* days since 1970-01-01 when account is locked */
|
|
|
|
fflg = false, /* days until account with expired password is locked */
|
|
|
|
gflg = false, /* primary group ID for new account */
|
|
|
|
Gflg = false, /* secondary group set for new account */
|
|
|
|
kflg = false, /* specify a directory to fill new user directory */
|
|
|
|
lflg = false, /* do not add user to lastlog database file */
|
|
|
|
mflg = false, /* create user's home directory if it doesn't exist */
|
|
|
|
Nflg = false, /* do not create a group having the same name as the user, but add the user to def_group (or the group specified with -g) */
|
|
|
|
oflg = false, /* permit non-unique user ID to be specified with -u */
|
|
|
|
rflg = false, /* create a system account */
|
|
|
|
sflg = false, /* shell program for new account */
|
|
|
|
uflg = false, /* specify user ID for new account */
|
|
|
|
Uflg = false; /* create a group having the same name as the user */
|
|
|
|
|
|
|
|
static bool home_added = false;
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
/*
|
|
|
|
* exit status values
|
|
|
|
*/
|
|
|
|
#define E_SUCCESS 0 /* success */
|
|
|
|
#define E_PW_UPDATE 1 /* can't update password file */
|
2007-10-07 17:15:23 +05:30
|
|
|
#define E_USAGE 2 /* invalid command syntax */
|
2007-10-07 17:14:02 +05:30
|
|
|
#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:14:02 +05:30
|
|
|
#define E_NOTFOUND 6 /* specified group doesn't exist */
|
|
|
|
#define E_NAME_IN_USE 9 /* username already in use */
|
|
|
|
#define E_GRP_UPDATE 10 /* can't update group file */
|
|
|
|
#define E_HOMEDIR 12 /* can't create home directory */
|
2007-10-07 17:15:40 +05:30
|
|
|
#define E_MAIL_SPOOL 13 /* can't create mail spool */
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2007-10-07 17:15:23 +05:30
|
|
|
#define DGROUP "GROUP="
|
|
|
|
#define HOME "HOME="
|
|
|
|
#define SHELL "SHELL="
|
|
|
|
#define INACT "INACTIVE="
|
|
|
|
#define EXPIRE "EXPIRE="
|
|
|
|
#define SKEL "SKEL="
|
2007-10-07 17:15:40 +05:30
|
|
|
#define CREATE_MAIL_SPOOL "CREATE_MAIL_SPOOL="
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
/* local function prototypes */
|
2007-10-07 17:14:59 +05:30
|
|
|
static void fail_exit (int);
|
|
|
|
static struct group *getgr_nam_gid (const char *);
|
|
|
|
static long get_number (const char *);
|
|
|
|
static uid_t get_uid (const char *);
|
|
|
|
static void get_defaults (void);
|
|
|
|
static void show_defaults (void);
|
|
|
|
static int set_defaults (void);
|
|
|
|
static int get_groups (char *);
|
|
|
|
static void usage (void);
|
|
|
|
static void new_pwent (struct passwd *);
|
|
|
|
|
|
|
|
static long scale_age (long);
|
|
|
|
static void new_spent (struct spwd *);
|
|
|
|
static void grp_update (void);
|
|
|
|
|
|
|
|
static void process_flags (int argc, char **argv);
|
|
|
|
static void close_files (void);
|
|
|
|
static void open_files (void);
|
|
|
|
static void faillog_reset (uid_t);
|
|
|
|
static void lastlog_reset (uid_t);
|
|
|
|
static void usr_update (void);
|
|
|
|
static void create_home (void);
|
2007-10-07 17:15:40 +05:30
|
|
|
static void create_mail (void);
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
/*
|
|
|
|
* fail_exit - undo as much as possible
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
static void fail_exit (int code)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
|
|
|
if (home_added)
|
2007-10-07 17:14:59 +05:30
|
|
|
rmdir (user_home);
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2008-03-09 04:14:53 +05:30
|
|
|
if (shadow_locked) {
|
|
|
|
spw_unlock ();
|
|
|
|
}
|
|
|
|
if (passwd_locked) {
|
|
|
|
pw_unlock ();
|
|
|
|
}
|
|
|
|
if (group_locked) {
|
|
|
|
gr_unlock ();
|
|
|
|
}
|
|
|
|
#ifdef SHADOWGRP
|
|
|
|
if (gshadow_locked) {
|
|
|
|
sgr_unlock ();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
2008-06-14 02:36:04 +05:30
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
|
|
|
"adding user",
|
|
|
|
user_name, AUDIT_NO_ID, 0);
|
2007-10-07 17:17:01 +05:30
|
|
|
#endif
|
2007-10-07 17:16:07 +05:30
|
|
|
SYSLOG ((LOG_INFO, "failed adding user `%s', data deleted", user_name));
|
2007-10-07 17:14:59 +05:30
|
|
|
exit (code);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
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 gid;
|
|
|
|
char *errptr;
|
|
|
|
|
|
|
|
gid = strtol (grname, &errptr, 10);
|
2008-06-14 02:36:04 +05:30
|
|
|
if (*grname != '\0' && *errptr == '\0' && errno != ERANGE && gid >= 0) {
|
|
|
|
return xgetgrgid ((gid_t) gid);
|
|
|
|
}
|
* 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 xgetgrnam (grname);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
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:02 +05:30
|
|
|
|
2007-10-07 17:17:57 +05:30
|
|
|
val = strtol (numstr, &errptr, 10);
|
2008-06-10 03:38:08 +05:30
|
|
|
if (('\0' != *errptr) || (ERANGE == errno)) {
|
2007-10-07 17:17:57 +05:30
|
|
|
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_uid (const char *uidstr)
|
2007-10-07 17:14:59 +05:30
|
|
|
{
|
2007-10-07 17:17:57 +05:30
|
|
|
long val;
|
|
|
|
char *errptr;
|
|
|
|
|
|
|
|
val = strtol (uidstr, &errptr, 10);
|
2008-06-10 03:38:08 +05:30
|
|
|
if (('\0' != *errptr) || (ERANGE == errno) || (val < 0)) {
|
2007-10-07 17:17:57 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: invalid numeric argument '%s'\n"), Prog,
|
|
|
|
uidstr);
|
|
|
|
exit (E_BAD_ARG);
|
|
|
|
}
|
2008-06-14 02:36:04 +05:30
|
|
|
return (uid_t) val;
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
#define MATCH(x,y) (strncmp((x),(y),strlen(y)) == 0)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get_defaults - read the defaults file
|
|
|
|
*
|
2007-10-07 17:14:59 +05:30
|
|
|
* get_defaults() reads the defaults file for this command. It sets the
|
|
|
|
* various values from the file, or uses built-in default values if the
|
|
|
|
* file does not exist.
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
static void get_defaults (void)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
|
|
|
FILE *fp;
|
|
|
|
char buf[1024];
|
|
|
|
char *cp, *ep;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Open the defaults file for reading.
|
|
|
|
*/
|
|
|
|
|
2008-06-10 03:38:08 +05:30
|
|
|
fp = fopen (def_file, "r");
|
|
|
|
if (NULL == fp) {
|
2007-10-07 17:14:02 +05:30
|
|
|
return;
|
2008-06-10 03:38:08 +05:30
|
|
|
}
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
/*
|
2007-10-07 17:14:59 +05:30
|
|
|
* Read the file a line at a time. Only the lines that have relevant
|
|
|
|
* values are used, everything else can be ignored.
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
2008-06-14 02:36:04 +05:30
|
|
|
while (fgets (buf, (int) sizeof buf, fp) == buf) {
|
2008-06-10 03:38:08 +05:30
|
|
|
cp = strrchr (buf, '\n');
|
|
|
|
if (NULL != cp) {
|
2007-10-07 17:14:02 +05:30
|
|
|
*cp = '\0';
|
2008-06-10 03:38:08 +05:30
|
|
|
}
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2008-06-10 03:38:08 +05:30
|
|
|
cp = strchr (buf, '=');
|
|
|
|
if (NULL == cp) {
|
2007-10-07 17:14:02 +05:30
|
|
|
continue;
|
2008-06-10 03:38:08 +05:30
|
|
|
}
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
cp++;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Primary GROUP identifier
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
if (MATCH (buf, DGROUP)) {
|
2007-10-07 17:16:07 +05:30
|
|
|
unsigned int val = (unsigned int) strtoul (cp, &ep, 10);
|
* 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 group *grp;
|
2007-10-07 17:14:59 +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 (*cp != '\0' && *ep == '\0') { /* valid number */
|
2007-10-07 17:14:02 +05:30
|
|
|
def_group = val;
|
* 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 xgetgrgid */
|
2008-06-10 03:38:08 +05:30
|
|
|
grp = getgrgid (def_group);
|
|
|
|
if (NULL != grp) {
|
2007-10-07 17:14:59 +05:30
|
|
|
def_gname = xstrdup (grp->gr_name);
|
2007-10-07 17:14:02 +05:30
|
|
|
} else {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr,
|
2007-10-07 17:16:25 +05:30
|
|
|
_("%s: unknown GID %s\n"),
|
2007-10-07 17:14:59 +05:30
|
|
|
Prog, cp);
|
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 xgetgrnam */
|
2008-06-10 03:38:08 +05:30
|
|
|
} else if ((grp = getgrnam (cp)) != NULL) {
|
2007-10-07 17:14:02 +05:30
|
|
|
def_group = grp->gr_gid;
|
2007-10-07 17:14:59 +05:30
|
|
|
def_gname = xstrdup (cp);
|
2007-10-07 17:14:02 +05:30
|
|
|
} else {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr,
|
2007-10-07 17:16:07 +05:30
|
|
|
_("%s: unknown group %s\n"), Prog, cp);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
}
|
2007-10-07 17:14:59 +05:30
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
/*
|
|
|
|
* Default HOME filesystem
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
else if (MATCH (buf, HOME)) {
|
|
|
|
def_home = xstrdup (cp);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Default Login Shell command
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
else if (MATCH (buf, SHELL)) {
|
|
|
|
def_shell = xstrdup (cp);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2007-10-07 17:15:23 +05:30
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
/*
|
|
|
|
* Default Password Inactive value
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
else if (MATCH (buf, INACT)) {
|
|
|
|
long val = strtol (cp, &ep, 10);
|
|
|
|
|
2008-06-10 03:38:08 +05:30
|
|
|
if (('\0' != *cp) || (ERANGE == errno)) {
|
2007-10-07 17:14:02 +05:30
|
|
|
def_inactive = val;
|
2008-06-10 03:38:08 +05:30
|
|
|
} else {
|
2007-10-07 17:14:02 +05:30
|
|
|
def_inactive = -1;
|
2008-06-10 03:38:08 +05:30
|
|
|
}
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2007-10-07 17:14:59 +05:30
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
/*
|
|
|
|
* Default account expiration date
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
else if (MATCH (buf, EXPIRE)) {
|
|
|
|
def_expire = xstrdup (cp);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Default Skeleton information
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
else if (MATCH (buf, SKEL)) {
|
2008-06-10 03:38:08 +05:30
|
|
|
if ('\0' == *cp) {
|
2007-10-07 17:14:59 +05:30
|
|
|
cp = SKEL_DIR; /* XXX warning: const */
|
2008-06-10 03:38:08 +05:30
|
|
|
}
|
2007-10-07 17:14:59 +05:30
|
|
|
|
|
|
|
def_template = xstrdup (cp);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2007-10-07 17:15:40 +05:30
|
|
|
|
|
|
|
/*
|
2007-10-07 17:16:52 +05:30
|
|
|
* Create by default user mail spool or not ?
|
2007-10-07 17:15:40 +05:30
|
|
|
*/
|
|
|
|
else if (MATCH (buf, CREATE_MAIL_SPOOL)) {
|
2008-06-10 03:38:08 +05:30
|
|
|
if (*cp == '\0') {
|
2007-10-07 17:15:40 +05:30
|
|
|
cp = CREATE_MAIL_SPOOL; /* XXX warning: const */
|
2008-06-10 03:38:08 +05:30
|
|
|
}
|
2007-10-07 17:15:40 +05:30
|
|
|
|
|
|
|
def_create_mail_spool = xstrdup (cp);
|
|
|
|
}
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* show_defaults - show the contents of the defaults file
|
|
|
|
*
|
|
|
|
* show_defaults() displays the values that are used from the default
|
|
|
|
* file and the built-in values.
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
static void show_defaults (void)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
2007-10-07 17:15:49 +05:30
|
|
|
printf ("GROUP=%u\n", (unsigned int) def_group);
|
|
|
|
printf ("HOME=%s\n", def_home);
|
|
|
|
printf ("INACTIVE=%ld\n", def_inactive);
|
|
|
|
printf ("EXPIRE=%s\n", def_expire);
|
|
|
|
printf ("SHELL=%s\n", def_shell);
|
|
|
|
printf ("SKEL=%s\n", def_template);
|
|
|
|
printf ("CREATE_MAIL_SPOOL=%s\n", def_create_mail_spool);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* set_defaults - write new defaults file
|
|
|
|
*
|
|
|
|
* set_defaults() re-writes the defaults file using the values that
|
2007-10-07 17:14:59 +05:30
|
|
|
* are currently set. Duplicated lines are pruned, missing lines are
|
2007-10-07 17:14:02 +05:30
|
|
|
* added, and unrecognized lines are copied as is.
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
static int set_defaults (void)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
2007-10-07 17:14:59 +05:30
|
|
|
FILE *ifp;
|
|
|
|
FILE *ofp;
|
|
|
|
char buf[1024];
|
|
|
|
static char new_file[] = NEW_USER_FILE;
|
|
|
|
char *cp;
|
|
|
|
int ofd;
|
2008-06-10 03:38:08 +05:30
|
|
|
bool out_group = false;
|
|
|
|
bool out_home = false;
|
|
|
|
bool out_inactive = false;
|
|
|
|
bool out_expire = false;
|
|
|
|
bool out_shell = false;
|
|
|
|
bool out_skel = false;
|
|
|
|
bool out_create_mail_spool = false;
|
2007-10-07 17:14:59 +05:30
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
/*
|
|
|
|
* Create a temporary file to copy the new output to.
|
|
|
|
*/
|
2008-06-10 03:38:08 +05:30
|
|
|
ofd = mkstemp (new_file);
|
|
|
|
if (-1 == ofd) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: cannot create new defaults file\n"), Prog);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2008-06-10 03:38:08 +05:30
|
|
|
ofp = fdopen (ofd, "w");
|
|
|
|
if (NULL == ofp) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr, _("%s: cannot open new defaults file\n"),
|
|
|
|
Prog);
|
2007-10-07 17:14:02 +05:30
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Open the existing defaults file and copy the lines to the
|
2007-10-07 17:14:59 +05:30
|
|
|
* temporary file, using any new values. Each line is checked
|
2007-10-07 17:14:02 +05:30
|
|
|
* to insure that it is not output more than once.
|
|
|
|
*/
|
2008-06-10 03:38:08 +05:30
|
|
|
ifp = fopen (def_file, "r");
|
|
|
|
if (NULL == ifp) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (ofp, "# useradd defaults file\n");
|
2007-10-07 17:14:02 +05:30
|
|
|
goto skip;
|
|
|
|
}
|
|
|
|
|
2008-06-14 02:36:04 +05:30
|
|
|
while (fgets (buf, (int) sizeof buf, ifp) == buf) {
|
2008-06-10 03:38:08 +05:30
|
|
|
cp = strrchr (buf, '\n');
|
|
|
|
if (NULL != cp) {
|
2007-10-07 17:14:02 +05:30
|
|
|
*cp = '\0';
|
2008-06-10 03:38:08 +05:30
|
|
|
}
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
if (!out_group && MATCH (buf, DGROUP)) {
|
2007-10-07 17:16:07 +05:30
|
|
|
fprintf (ofp, DGROUP "%u\n", (unsigned int) def_group);
|
2008-06-10 03:38:08 +05:30
|
|
|
out_group = true;
|
2007-10-07 17:15:23 +05:30
|
|
|
} else if (!out_home && MATCH (buf, HOME)) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (ofp, HOME "%s\n", def_home);
|
2008-06-10 03:38:08 +05:30
|
|
|
out_home = true;
|
2007-10-07 17:14:59 +05:30
|
|
|
} else if (!out_inactive && MATCH (buf, INACT)) {
|
|
|
|
fprintf (ofp, INACT "%ld\n", def_inactive);
|
2008-06-10 03:38:08 +05:30
|
|
|
out_inactive = true;
|
2007-10-07 17:14:59 +05:30
|
|
|
} else if (!out_expire && MATCH (buf, EXPIRE)) {
|
|
|
|
fprintf (ofp, EXPIRE "%s\n", def_expire);
|
2008-06-10 03:38:08 +05:30
|
|
|
out_expire = true;
|
2007-10-07 17:15:23 +05:30
|
|
|
} else if (!out_shell && MATCH (buf, SHELL)) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (ofp, SHELL "%s\n", def_shell);
|
2008-06-10 03:38:08 +05:30
|
|
|
out_shell = true;
|
2007-10-07 17:14:59 +05:30
|
|
|
} else if (!out_skel && MATCH (buf, SKEL)) {
|
|
|
|
fprintf (ofp, SKEL "%s\n", def_template);
|
2008-06-10 03:38:08 +05:30
|
|
|
out_skel = true;
|
2007-10-07 17:15:40 +05:30
|
|
|
} else if (!out_create_mail_spool
|
|
|
|
&& MATCH (buf, CREATE_MAIL_SPOOL)) {
|
|
|
|
fprintf (ofp, CREATE_MAIL_SPOOL "%s\n",
|
|
|
|
def_create_mail_spool);
|
2008-06-10 03:38:08 +05:30
|
|
|
out_create_mail_spool = true;
|
2007-10-07 17:14:59 +05:30
|
|
|
} else
|
|
|
|
fprintf (ofp, "%s\n", buf);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2008-06-10 03:38:08 +05:30
|
|
|
(void) fclose (ifp);
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
skip:
|
2007-10-07 17:14:02 +05:30
|
|
|
/*
|
2007-10-07 17:14:59 +05:30
|
|
|
* Check each line to insure that every line was output. This
|
2007-10-07 17:14:02 +05:30
|
|
|
* causes new values to be added to a file which did not previously
|
|
|
|
* have an entry for that value.
|
|
|
|
*/
|
|
|
|
if (!out_group)
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (ofp, DGROUP "%u\n", (unsigned int) def_group);
|
2007-10-07 17:14:02 +05:30
|
|
|
if (!out_home)
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (ofp, HOME "%s\n", def_home);
|
2007-10-07 17:14:02 +05:30
|
|
|
if (!out_inactive)
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (ofp, INACT "%ld\n", def_inactive);
|
2007-10-07 17:14:02 +05:30
|
|
|
if (!out_expire)
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (ofp, EXPIRE "%s\n", def_expire);
|
2007-10-07 17:14:02 +05:30
|
|
|
if (!out_shell)
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (ofp, SHELL "%s\n", def_shell);
|
2007-10-07 17:14:02 +05:30
|
|
|
if (!out_skel)
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (ofp, SKEL "%s\n", def_template);
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2007-10-07 17:15:40 +05:30
|
|
|
if (!out_create_mail_spool)
|
2007-10-07 17:16:07 +05:30
|
|
|
fprintf (ofp, CREATE_MAIL_SPOOL "%s\n", def_create_mail_spool);
|
2007-10-07 17:15:40 +05:30
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
/*
|
2007-10-07 17:14:59 +05:30
|
|
|
* Flush and close the file. Check for errors to make certain
|
2007-10-07 17:14:02 +05:30
|
|
|
* the new file is intact.
|
|
|
|
*/
|
2008-06-10 03:38:08 +05:30
|
|
|
(void) fflush (ofp);
|
|
|
|
if ((ferror (ofp) != 0) || (fclose (ofp) != 0)) {
|
2007-10-07 17:14:59 +05:30
|
|
|
unlink (new_file);
|
2007-10-07 17:14:02 +05:30
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Rename the current default file to its backup name.
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
snprintf (buf, sizeof buf, "%s-", def_file);
|
2008-06-10 03:38:08 +05:30
|
|
|
if ((rename (def_file, buf) != 0) && (ENOENT != errno)) {
|
2007-10-07 17:16:07 +05:30
|
|
|
snprintf (buf, sizeof buf, _("%s: rename: %s"), Prog, def_file);
|
2007-10-07 17:14:59 +05:30
|
|
|
perror (buf);
|
|
|
|
unlink (new_file);
|
2007-10-07 17:14:02 +05:30
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Rename the new default file to its correct name.
|
|
|
|
*/
|
2008-06-10 03:38:08 +05:30
|
|
|
if (rename (new_file, def_file) != 0) {
|
2007-10-07 17:16:07 +05:30
|
|
|
snprintf (buf, sizeof buf, _("%s: rename: %s"), Prog, new_file);
|
2007-10-07 17:14:59 +05:30
|
|
|
perror (buf);
|
2007-10-07 17:14:02 +05:30
|
|
|
return -1;
|
|
|
|
}
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
2008-06-14 02:36:04 +05:30
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
|
|
|
"changing user defaults",
|
|
|
|
NULL, AUDIT_NO_ID, 1);
|
2007-10-07 17:17:01 +05:30
|
|
|
#endif
|
2007-10-07 17:14:59 +05:30
|
|
|
SYSLOG ((LOG_INFO,
|
2007-10-07 17:15:23 +05:30
|
|
|
"useradd defaults: GROUP=%u, HOME=%s, SHELL=%s, INACTIVE=%ld, "
|
2007-10-07 17:15:40 +05:30
|
|
|
"EXPIRE=%s, SKEL=%s, CREATE_MAIL_SPOOL=%s",
|
2007-10-07 17:15:23 +05:30
|
|
|
(unsigned int) def_group, def_home, def_shell,
|
2007-10-07 17:15:40 +05:30
|
|
|
def_inactive, def_expire, def_template,
|
|
|
|
def_create_mail_spool));
|
2007-10-07 17:14:02 +05:30
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
2007-10-07 17:14:02 +05:30
|
|
|
* names are reported as errors.
|
|
|
|
*/
|
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;
|
|
|
|
|
2008-06-10 03:38:08 +05:30
|
|
|
if ('\0' == *list) {
|
2007-10-07 17:14:02 +05:30
|
|
|
return 0;
|
2008-06-10 03:38:08 +05:30
|
|
|
}
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
/*
|
|
|
|
* So long as there is some data to be converted, strip off
|
2007-10-07 17:14:59 +05:30
|
|
|
* each name and look it up. A mix of numerical and string
|
2007-10-07 17:14:02 +05:30
|
|
|
* values for group identifiers is permitted.
|
|
|
|
*/
|
|
|
|
do {
|
|
|
|
/*
|
|
|
|
* Strip off a single name from the list
|
|
|
|
*/
|
2008-06-10 03:38:08 +05:30
|
|
|
cp = strchr (list, ',');
|
|
|
|
if (NULL != cp) {
|
2007-10-07 17:14:02 +05:30
|
|
|
*cp++ = '\0';
|
2008-06-10 03:38:08 +05:30
|
|
|
}
|
2007-10-07 17:14:02 +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: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.
|
|
|
|
*/
|
2008-06-10 03:38:08 +05:30
|
|
|
if (NULL == 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;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the group doesn't exist, don't dump core...
|
|
|
|
* Instead, try the next one. --marekm
|
|
|
|
*/
|
2008-06-10 03:38:08 +05:30
|
|
|
if (NULL == grp) {
|
2007-10-07 17:14:02 +05:30
|
|
|
continue;
|
2008-06-10 03:38:08 +05:30
|
|
|
}
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
#ifdef USE_NIS
|
|
|
|
/*
|
2007-10-07 17:14:59 +05:30
|
|
|
* Don't add this group if they are an NIS group. Tell
|
2007-10-07 17:14:02 +05:30
|
|
|
* the user to go to the server for this group.
|
|
|
|
*/
|
|
|
|
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);
|
2008-06-10 03:38:08 +05:30
|
|
|
} while (NULL != list);
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
user_groups[ngroups] = (char *) 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Any errors in finding group names are fatal
|
|
|
|
*/
|
2008-06-10 03:38:08 +05:30
|
|
|
if (0 != errors) {
|
2007-10-07 17:14:02 +05:30
|
|
|
return -1;
|
2008-06-10 03:38:08 +05:30
|
|
|
}
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
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: useradd [options] LOGIN\n"
|
2008-01-25 02:24:42 +05:30
|
|
|
"\n"
|
|
|
|
"Options:\n"
|
|
|
|
" -b, --base-dir BASE_DIR base directory for the new user account\n"
|
|
|
|
" home directory\n"
|
|
|
|
" -c, --comment COMMENT set the GECOS field for the new user account\n"
|
|
|
|
" -d, --home-dir HOME_DIR home directory for the new user account\n"
|
|
|
|
" -D, --defaults print or save modified default useradd\n"
|
|
|
|
" configuration\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 for the new user account\n"
|
|
|
|
" -G, --groups GROUPS list of supplementary groups for the new\n"
|
|
|
|
" user account\n"
|
|
|
|
" -h, --help display this help message and exit\n"
|
|
|
|
" -k, --skel SKEL_DIR specify an alternative skel directory\n"
|
|
|
|
" -K, --key KEY=VALUE overrides /etc/login.defs defaults\n"
|
|
|
|
" -l, do not add the user to the lastlog and\n"
|
|
|
|
" faillog databases\n"
|
|
|
|
" -m, --create-home create home directory for the new user\n"
|
|
|
|
" account\n"
|
2008-02-26 02:33:46 +05:30
|
|
|
" -N, --no-user-group do not create a group with the same name as\n"
|
|
|
|
" the user\n"
|
2008-01-25 02:24:42 +05:30
|
|
|
" -o, --non-unique allow create user with duplicate\n"
|
|
|
|
" (non-unique) UID\n"
|
|
|
|
" -p, --password PASSWORD use encrypted password for the new user\n"
|
|
|
|
" account\n"
|
2008-02-20 02:31:38 +05:30
|
|
|
" -r, --system create a system account\n"
|
2008-01-25 02:24:42 +05:30
|
|
|
" -s, --shell SHELL the login shell for the new user account\n"
|
|
|
|
" -u, --uid UID force use the UID for the new user account\n"
|
2008-02-26 02:33:46 +05:30
|
|
|
" -U, --user-group create a group with the same name as the user\n"
|
2008-01-25 02:24:42 +05:30
|
|
|
"\n"), stderr);
|
2007-10-07 17:14:59 +05:30
|
|
|
exit (E_USAGE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* new_pwent - initialize the values in a password file entry
|
|
|
|
*
|
|
|
|
* new_pwent() takes all of the values that have been entered and
|
|
|
|
* fills in a (struct passwd) with them.
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
static void new_pwent (struct passwd *pwent)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
2007-10-07 17:14:59 +05:30
|
|
|
memzero (pwent, sizeof *pwent);
|
2007-10-07 17:14:02 +05:30
|
|
|
pwent->pw_name = (char *) user_name;
|
|
|
|
if (is_shadow_pwd)
|
|
|
|
pwent->pw_passwd = (char *) SHADOW_PASSWD_STRING;
|
|
|
|
else
|
2007-10-07 17:14:59 +05:30
|
|
|
pwent->pw_passwd = (char *) user_pass;
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
pwent->pw_uid = user_id;
|
|
|
|
pwent->pw_gid = user_gid;
|
|
|
|
pwent->pw_gecos = (char *) user_comment;
|
|
|
|
pwent->pw_dir = (char *) user_home;
|
|
|
|
pwent->pw_shell = (char *) user_shell;
|
|
|
|
}
|
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
static long scale_age (long x)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
|
|
|
if (x <= 0)
|
|
|
|
return x;
|
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
return x * (DAY / SCALE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* new_spent - initialize the values in a shadow password file entry
|
|
|
|
*
|
|
|
|
* new_spent() takes all of the values that have been entered and
|
|
|
|
* fills in a (struct spwd) with them.
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
static void new_spent (struct spwd *spent)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
2007-10-07 17:14:59 +05:30
|
|
|
memzero (spent, sizeof *spent);
|
2007-10-07 17:14:02 +05:30
|
|
|
spent->sp_namp = (char *) user_name;
|
|
|
|
spent->sp_pwdp = (char *) user_pass;
|
2008-06-14 02:36:04 +05:30
|
|
|
spent->sp_lstchg = (long) time ((time_t *) 0) / SCALE;
|
2008-02-20 02:31:38 +05:30
|
|
|
if (!rflg) {
|
2008-05-20 02:01:48 +05:30
|
|
|
spent->sp_min = scale_age (getdef_num ("PASS_MIN_DAYS", -1));
|
|
|
|
spent->sp_max = scale_age (getdef_num ("PASS_MAX_DAYS", -1));
|
|
|
|
spent->sp_warn = scale_age (getdef_num ("PASS_WARN_AGE", -1));
|
|
|
|
spent->sp_inact = scale_age (def_inactive);
|
|
|
|
spent->sp_expire = scale_age (user_expire);
|
2008-02-20 02:31:38 +05:30
|
|
|
} else {
|
|
|
|
spent->sp_min = scale_age (-1);
|
|
|
|
spent->sp_max = scale_age (-1);
|
|
|
|
spent->sp_warn = scale_age (-1);
|
|
|
|
spent->sp_inact = scale_age (-1);
|
|
|
|
spent->sp_expire = scale_age (-1);
|
|
|
|
}
|
2008-06-14 02:36:04 +05:30
|
|
|
spent->sp_flag = SHADOW_SP_FLAG_UNSET;
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* grp_update - add user to secondary group set
|
|
|
|
*
|
|
|
|
* grp_update() takes the secondary group set given in user_groups
|
|
|
|
* and adds the user to each group given by that set.
|
2007-11-18 04:41:02 +05:30
|
|
|
*
|
|
|
|
* The group files are opened and locked in open_files().
|
|
|
|
*
|
|
|
|
* close_files() should be called afterwards to commit the changes
|
|
|
|
* and unlocking the group files.
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
static void grp_update (void)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
|
|
|
const struct group *grp;
|
|
|
|
struct group *ngrp;
|
2007-10-07 17:14:59 +05:30
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
#ifdef SHADOWGRP
|
|
|
|
const struct sgrp *sgrp;
|
|
|
|
struct sgrp *nsgrp;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
for (gr_rewind (), grp = gr_next (); grp; 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
|
|
|
if (!is_on_list (user_groups, grp->gr_name))
|
2007-10-07 17:14:02 +05:30
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make a copy - gr_update() will free() everything
|
|
|
|
* from the old entry, and we need it later.
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
ngrp = __gr_dup (grp);
|
2008-06-10 03:38:08 +05:30
|
|
|
if (NULL == ngrp) {
|
2007-11-17 05:09:42 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: Out of memory. Cannot update the group database.\n"),
|
|
|
|
Prog);
|
2007-10-07 17:14:59 +05:30
|
|
|
fail_exit (E_GRP_UPDATE); /* XXX */
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add the username to the list of group members and
|
|
|
|
* update the group entry to reflect the change.
|
|
|
|
*/
|
|
|
|
ngrp->gr_mem = add_list (ngrp->gr_mem, user_name);
|
2008-06-10 03:38:08 +05:30
|
|
|
if (gr_update (ngrp) == 0) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr,
|
2007-10-07 17:17:01 +05:30
|
|
|
_("%s: error adding new group entry\n"), Prog);
|
2007-10-07 17:14:59 +05:30
|
|
|
fail_exit (E_GRP_UPDATE);
|
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,
|
2008-06-14 02:36:04 +05:30
|
|
|
"adding user to group",
|
|
|
|
user_name, AUDIT_NO_ID, 1);
|
2007-10-07 17:17:01 +05:30
|
|
|
#endif
|
2007-10-07 17:14:59 +05:30
|
|
|
SYSLOG ((LOG_INFO, "add `%s' to group `%s'",
|
|
|
|
user_name, ngrp->gr_name));
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef SHADOWGRP
|
|
|
|
if (!is_shadow_grp)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Scan through the entire shadow group file looking for the groups
|
2007-10-07 17:14:59 +05:30
|
|
|
* that the user is a member of. The administrative list isn't
|
2007-10-07 17:14:02 +05:30
|
|
|
* modified.
|
|
|
|
*/
|
2008-06-10 03:38:08 +05:30
|
|
|
for (sgr_rewind (), sgrp = sgr_next (); NULL != sgrp; sgrp = sgr_next ()) {
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
/*
|
|
|
|
* See if the user specified this group as one of their
|
|
|
|
* concurrent groups.
|
|
|
|
*/
|
2008-06-10 03:38:08 +05:30
|
|
|
if (gr_locate (sgrp->sg_name) == NULL)
|
2007-10-07 17:14:02 +05:30
|
|
|
continue;
|
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
if (!is_on_list (user_groups, sgrp->sg_name))
|
2007-10-07 17:14:02 +05:30
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make a copy - sgr_update() will free() everything
|
|
|
|
* from the old entry, and we need it later.
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
nsgrp = __sgr_dup (sgrp);
|
2008-06-10 03:38:08 +05:30
|
|
|
if (NULL == nsgrp) {
|
2007-11-17 05:09:42 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: Out of memory. Cannot update the shadow group database.\n"),
|
|
|
|
Prog);
|
2007-10-07 17:14:59 +05:30
|
|
|
fail_exit (E_GRP_UPDATE); /* XXX */
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add the username to the list of group members and
|
|
|
|
* update the group entry to reflect the change.
|
|
|
|
*/
|
|
|
|
nsgrp->sg_mem = add_list (nsgrp->sg_mem, user_name);
|
2008-06-10 03:38:08 +05:30
|
|
|
if (sgr_update (nsgrp) == 0) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr,
|
2007-10-07 17:16:07 +05:30
|
|
|
_("%s: error adding new group entry\n"), Prog);
|
2007-10-07 17:14:59 +05:30
|
|
|
fail_exit (E_GRP_UPDATE);
|
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,
|
2008-06-14 02:36:04 +05:30
|
|
|
"adding user to shadow group",
|
|
|
|
user_name, AUDIT_NO_ID, 1);
|
2007-10-07 17:17:01 +05:30
|
|
|
#endif
|
2007-10-07 17:14:59 +05:30
|
|
|
SYSLOG ((LOG_INFO, "add `%s' to shadow group `%s'",
|
|
|
|
user_name, nsgrp->sg_name));
|
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
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* process_flags - perform command line argument setting
|
|
|
|
*
|
|
|
|
* process_flags() interprets the command line arguments and sets
|
2007-10-07 17:14:59 +05:30
|
|
|
* the values that the user will be created with accordingly. The
|
2007-10-07 17:14:02 +05:30
|
|
|
* values are checked for sanity.
|
|
|
|
*/
|
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;
|
2008-06-10 03:38:08 +05:30
|
|
|
bool anyflag = false;
|
2007-10-07 17:14:02 +05:30
|
|
|
char *cp;
|
|
|
|
|
2007-10-07 17:16:34 +05:30
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Parse the command line options.
|
|
|
|
*/
|
|
|
|
int c;
|
|
|
|
static struct option long_options[] = {
|
|
|
|
{"base-dir", required_argument, NULL, 'b'},
|
|
|
|
{"comment", required_argument, NULL, 'c'},
|
|
|
|
{"home-dir", required_argument, NULL, 'd'},
|
2008-01-13 02:39:46 +05:30
|
|
|
{"defaults", no_argument, NULL, 'D'},
|
2007-10-07 17:16:34 +05:30
|
|
|
{"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'},
|
|
|
|
{"skel", required_argument, NULL, 'k'},
|
|
|
|
{"key", required_argument, NULL, 'K'},
|
|
|
|
{"create-home", no_argument, NULL, 'm'},
|
2008-02-26 02:33:46 +05:30
|
|
|
{"no-user-group", no_argument, NULL, 'N'},
|
2007-10-07 17:16:34 +05:30
|
|
|
{"non-unique", no_argument, NULL, 'o'},
|
|
|
|
{"password", required_argument, NULL, 'p'},
|
2008-02-20 02:31:38 +05:30
|
|
|
{"system", no_argument, NULL, 'r'},
|
2007-10-07 17:16:34 +05:30
|
|
|
{"shell", required_argument, NULL, 's'},
|
|
|
|
{"uid", required_argument, NULL, 'u'},
|
2008-02-26 02:33:46 +05:30
|
|
|
{"user-group", no_argument, NULL, 'U'},
|
2007-10-07 17:16:34 +05:30
|
|
|
{NULL, 0, NULL, '\0'}
|
|
|
|
};
|
|
|
|
while ((c =
|
2008-02-26 02:33:46 +05:30
|
|
|
getopt_long (argc, argv, "b:c:d:De:f:g:G:k:K:lmMNop:rs:u:U",
|
2007-10-07 17:16:34 +05:30
|
|
|
long_options, NULL)) != -1) {
|
|
|
|
switch (c) {
|
|
|
|
case 'b':
|
|
|
|
if (!VALID (optarg)
|
|
|
|
|| optarg[0] != '/') {
|
|
|
|
fprintf (stderr,
|
|
|
|
_
|
2007-10-07 17:17:33 +05:30
|
|
|
("%s: invalid base directory '%s'\n"),
|
2007-10-07 17:16:34 +05:30
|
|
|
Prog, optarg);
|
|
|
|
exit (E_BAD_ARG);
|
|
|
|
}
|
|
|
|
def_home = optarg;
|
2008-06-10 03:38:08 +05:30
|
|
|
bflg = true;
|
2007-10-07 17:16:34 +05:30
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
if (!VALID (optarg)) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_
|
2007-10-07 17:17:33 +05:30
|
|
|
("%s: invalid comment '%s'\n"),
|
2007-10-07 17:16:34 +05:30
|
|
|
Prog, optarg);
|
|
|
|
exit (E_BAD_ARG);
|
|
|
|
}
|
|
|
|
user_comment = optarg;
|
2008-06-10 03:38:08 +05:30
|
|
|
cflg = true;
|
2007-10-07 17:16:34 +05:30
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
if (!VALID (optarg)
|
|
|
|
|| optarg[0] != '/') {
|
|
|
|
fprintf (stderr,
|
|
|
|
_
|
2007-10-07 17:17:33 +05:30
|
|
|
("%s: invalid home directory '%s'\n"),
|
2007-10-07 17:16:34 +05:30
|
|
|
Prog, optarg);
|
|
|
|
exit (E_BAD_ARG);
|
|
|
|
}
|
|
|
|
user_home = optarg;
|
2008-06-10 03:38:08 +05:30
|
|
|
dflg = true;
|
2007-10-07 17:16:34 +05:30
|
|
|
break;
|
|
|
|
case 'D':
|
|
|
|
if (anyflag)
|
|
|
|
usage ();
|
2008-06-10 03:38:08 +05:30
|
|
|
Dflg = true;
|
2007-10-07 17:16:34 +05:30
|
|
|
break;
|
|
|
|
case 'e':
|
2008-06-10 03:38:08 +05:30
|
|
|
if ('\0' != *optarg) {
|
2007-10-07 17:16:34 +05:30
|
|
|
user_expire = strtoday (optarg);
|
|
|
|
if (user_expire == -1) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_
|
2007-10-07 17:17:33 +05:30
|
|
|
("%s: invalid date '%s'\n"),
|
2007-10-07 17:16:34 +05:30
|
|
|
Prog, optarg);
|
|
|
|
exit (E_BAD_ARG);
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
user_expire = -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* -e "" is allowed - it's a no-op without /etc/shadow
|
|
|
|
*/
|
2008-06-10 03:38:08 +05:30
|
|
|
if (('\0' != *optarg) && !is_shadow_pwd) {
|
2007-10-07 17:16:34 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_
|
|
|
|
("%s: shadow passwords required for -e\n"),
|
|
|
|
Prog);
|
|
|
|
exit (E_USAGE);
|
|
|
|
}
|
|
|
|
if (Dflg)
|
|
|
|
def_expire = optarg;
|
2008-06-10 03:38:08 +05:30
|
|
|
eflg = true;
|
2007-10-07 17:16:34 +05:30
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
def_inactive = get_number (optarg);
|
|
|
|
/*
|
|
|
|
* -f -1 is allowed - it's a no-op without /etc/shadow
|
|
|
|
*/
|
2008-06-10 03:38:08 +05:30
|
|
|
if ((-1 != def_inactive) && !is_shadow_pwd) {
|
2007-10-07 17:16:34 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_
|
|
|
|
("%s: shadow passwords required for -f\n"),
|
|
|
|
Prog);
|
|
|
|
exit (E_USAGE);
|
|
|
|
}
|
2008-06-10 03:38:08 +05:30
|
|
|
fflg = true;
|
2007-10-07 17:16:34 +05:30
|
|
|
break;
|
|
|
|
case 'g':
|
|
|
|
grp = getgr_nam_gid (optarg);
|
2008-06-10 03:38:08 +05:30
|
|
|
if (NULL == grp) {
|
2007-10-07 17:16:34 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_
|
|
|
|
("%s: unknown group %s\n"),
|
|
|
|
Prog, optarg);
|
|
|
|
exit (E_NOTFOUND);
|
|
|
|
}
|
|
|
|
if (Dflg) {
|
|
|
|
def_group = grp->gr_gid;
|
|
|
|
def_gname = optarg;
|
|
|
|
} else {
|
|
|
|
user_gid = grp->gr_gid;
|
|
|
|
}
|
2008-06-10 03:38:08 +05:30
|
|
|
gflg = true;
|
2007-10-07 17:16:34 +05:30
|
|
|
break;
|
|
|
|
case 'G':
|
2008-06-10 03:38:08 +05:30
|
|
|
if (get_groups (optarg) != 0) {
|
2007-10-07 17:16:34 +05:30
|
|
|
exit (E_NOTFOUND);
|
2008-06-10 03:38:08 +05:30
|
|
|
}
|
|
|
|
if (NULL != user_groups[0]) {
|
|
|
|
do_grp_update = true;
|
|
|
|
}
|
|
|
|
Gflg = true;
|
2007-10-07 17:16:34 +05:30
|
|
|
break;
|
|
|
|
case 'h':
|
2007-10-07 17:14:59 +05:30
|
|
|
usage ();
|
2007-10-07 17:16:34 +05:30
|
|
|
break;
|
|
|
|
case 'k':
|
|
|
|
def_template = optarg;
|
2008-06-10 03:38:08 +05:30
|
|
|
kflg = true;
|
2007-10-07 17:16:34 +05:30
|
|
|
break;
|
|
|
|
case 'K':
|
|
|
|
/*
|
|
|
|
* override login.defs defaults (-K name=value)
|
|
|
|
* example: -K UID_MIN=100 -K UID_MAX=499
|
|
|
|
* note: -K UID_MIN=10,UID_MAX=499 doesn't work yet
|
|
|
|
*/
|
|
|
|
cp = strchr (optarg, '=');
|
2008-06-10 03:38:08 +05:30
|
|
|
if (NULL == cp) {
|
2007-10-07 17:16:34 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_
|
|
|
|
("%s: -K requires KEY=VALUE\n"),
|
|
|
|
Prog);
|
|
|
|
exit (E_BAD_ARG);
|
|
|
|
}
|
|
|
|
/* terminate name, point to value */
|
2008-06-10 03:38:08 +05:30
|
|
|
*cp = '\0';
|
|
|
|
cp++;
|
2007-10-07 17:16:34 +05:30
|
|
|
if (putdef_str (optarg, cp) < 0)
|
|
|
|
exit (E_BAD_ARG);
|
|
|
|
break;
|
2007-12-26 15:45:20 +05:30
|
|
|
case 'l':
|
2008-06-10 03:38:08 +05:30
|
|
|
lflg = true;
|
2007-12-26 15:45:20 +05:30
|
|
|
break;
|
2007-10-07 17:16:34 +05:30
|
|
|
case 'm':
|
2008-06-10 03:38:08 +05:30
|
|
|
mflg = true;
|
2007-10-07 17:16:34 +05:30
|
|
|
break;
|
2008-02-26 02:33:46 +05:30
|
|
|
case 'N':
|
2008-06-10 03:38:08 +05:30
|
|
|
Nflg = true;
|
2008-02-26 02:33:46 +05:30
|
|
|
break;
|
2007-10-07 17:16:34 +05:30
|
|
|
case 'o':
|
2008-06-10 03:38:08 +05:30
|
|
|
oflg = true;
|
2007-10-07 17:16:34 +05:30
|
|
|
break;
|
|
|
|
case 'p': /* set encrypted password */
|
|
|
|
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:16:34 +05:30
|
|
|
user_pass = optarg;
|
|
|
|
break;
|
2008-02-20 02:31:38 +05:30
|
|
|
case 'r':
|
2008-06-10 03:38:08 +05:30
|
|
|
rflg = true;
|
2008-02-20 02:31:38 +05:30
|
|
|
break;
|
2007-10-07 17:16:34 +05:30
|
|
|
case 's':
|
|
|
|
if (!VALID (optarg)
|
2008-06-10 03:38:08 +05:30
|
|
|
|| ( ('\0' != optarg[0])
|
|
|
|
&& ('/' != optarg[0])
|
|
|
|
&& ('*' != optarg[0]))) {
|
2007-10-07 17:16:34 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_
|
2007-10-07 17:17:33 +05:30
|
|
|
("%s: invalid shell '%s'\n"),
|
2007-10-07 17:16:34 +05:30
|
|
|
Prog, optarg);
|
|
|
|
exit (E_BAD_ARG);
|
|
|
|
}
|
|
|
|
user_shell = optarg;
|
|
|
|
def_shell = optarg;
|
2008-06-10 03:38:08 +05:30
|
|
|
sflg = true;
|
2007-10-07 17:16:34 +05:30
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
user_id = get_uid (optarg);
|
2008-06-10 03:38:08 +05:30
|
|
|
uflg = true;
|
2007-10-07 17:16:34 +05:30
|
|
|
break;
|
2008-02-26 02:33:46 +05:30
|
|
|
case 'U':
|
2008-06-10 03:38:08 +05:30
|
|
|
Uflg = true;
|
2008-02-26 02:33:46 +05:30
|
|
|
break;
|
2007-10-07 17:16:34 +05:30
|
|
|
default:
|
|
|
|
usage ();
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2008-06-10 03:38:08 +05:30
|
|
|
anyflag = true;
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
}
|
2007-10-07 17:17:01 +05:30
|
|
|
|
2008-05-20 02:01:48 +05:30
|
|
|
if (!gflg && !Nflg && !Uflg) {
|
2008-02-26 02:33:46 +05:30
|
|
|
/* Get the settings from login.defs */
|
|
|
|
Uflg = getdef_bool ("USERGROUPS_ENAB");
|
|
|
|
}
|
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
/*
|
|
|
|
* Certain options are only valid in combination with others.
|
|
|
|
* Check it here so that they can be specified in any order.
|
|
|
|
*/
|
2008-02-26 02:33:46 +05:30
|
|
|
if (oflg && !uflg) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: %s flag is ONLY allowed with the %s flag\n"),
|
|
|
|
Prog, "-o", "-u");
|
|
|
|
usage ();
|
|
|
|
}
|
|
|
|
if (kflg && !mflg) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: %s flag is ONLY allowed with the %s flag\n"),
|
|
|
|
Prog, "-k", "-m");
|
2007-10-07 17:14:59 +05:30
|
|
|
usage ();
|
2008-02-26 02:33:46 +05:30
|
|
|
}
|
|
|
|
if (Uflg && gflg) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: options %s and %s conflict\n"),
|
|
|
|
Prog, "-U", "-g");
|
|
|
|
usage ();
|
|
|
|
}
|
|
|
|
if (Uflg && Nflg) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: options %s and %s conflict\n"),
|
|
|
|
Prog, "-U", "-N");
|
|
|
|
usage ();
|
|
|
|
}
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
/*
|
2007-10-07 17:14:59 +05:30
|
|
|
* Either -D or username is required. Defaults can be set with -D
|
2007-10-07 17:14:02 +05:30
|
|
|
* for the -b, -e, -f, -g, -s options only.
|
|
|
|
*/
|
|
|
|
if (Dflg) {
|
|
|
|
if (optind != argc)
|
2007-10-07 17:14:59 +05:30
|
|
|
usage ();
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
if (uflg || oflg || Gflg || dflg || cflg || mflg)
|
2007-10-07 17:14:59 +05:30
|
|
|
usage ();
|
2007-10-07 17:14:02 +05:30
|
|
|
} else {
|
|
|
|
if (optind != argc - 1)
|
2007-10-07 17:14:59 +05:30
|
|
|
usage ();
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
user_name = argv[optind];
|
2008-05-26 02:28:16 +05:30
|
|
|
if (!is_valid_user_name (user_name)) {
|
2007-10-07 17:16:34 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_
|
|
|
|
("%s: invalid user name '%s'\n"),
|
2007-10-07 17:14:59 +05:30
|
|
|
Prog, user_name);
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
2008-06-14 02:36:04 +05:30
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
|
|
|
"adding user",
|
|
|
|
user_name, AUDIT_NO_ID, 0);
|
2007-10-07 17:17:01 +05:30
|
|
|
#endif
|
2007-10-07 17:14:59 +05:30
|
|
|
exit (E_BAD_ARG);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
if (!dflg) {
|
|
|
|
char *uh;
|
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
uh = xmalloc (strlen (def_home) +
|
|
|
|
strlen (user_name) + 2);
|
|
|
|
sprintf (uh, "%s/%s", def_home, user_name);
|
2007-10-07 17:14:02 +05:30
|
|
|
user_home = uh;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!eflg)
|
2007-10-07 17:14:59 +05:30
|
|
|
user_expire = strtoday (def_expire);
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
if (!gflg)
|
|
|
|
user_gid = def_group;
|
|
|
|
|
|
|
|
if (!sflg)
|
|
|
|
user_shell = def_shell;
|
2007-10-07 17:17:45 +05:30
|
|
|
|
|
|
|
/* TODO: add handle change default spool mail creation by
|
|
|
|
-K CREATE_MAIL_SPOOL={yes,no}. It need rewrite internal API for handle
|
|
|
|
shadow tools configuration */
|
|
|
|
create_mail_spool = def_create_mail_spool;
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* close_files - close all of the files that were opened
|
|
|
|
*
|
|
|
|
* close_files() closes all of the files that were opened for this
|
2007-10-07 17:14:59 +05:30
|
|
|
* 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
|
|
|
{
|
2008-06-10 03:38:08 +05:30
|
|
|
if (pw_close () == 0) {
|
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
|
|
|
}
|
2008-06-10 03:38:08 +05:30
|
|
|
if (is_shadow_pwd && (spw_close () == 0)) {
|
2007-10-07 17:14:59 +05:30
|
|
|
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
|
|
|
}
|
|
|
|
if (do_grp_update) {
|
2008-06-10 03:38:08 +05:30
|
|
|
if (gr_close () == 0) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr,
|
2007-10-07 17:16:07 +05:30
|
|
|
_("%s: cannot rewrite group file\n"), Prog);
|
2007-10-07 17:14:59 +05:30
|
|
|
fail_exit (E_GRP_UPDATE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
#ifdef SHADOWGRP
|
2008-06-10 03:38:08 +05:30
|
|
|
if (is_shadow_grp && (sgr_close () == 0)) {
|
2007-10-07 17:14:02 +05:30
|
|
|
fprintf (stderr,
|
2007-10-07 17:14:59 +05:30
|
|
|
_
|
|
|
|
("%s: cannot rewrite shadow group file\n"),
|
|
|
|
Prog);
|
|
|
|
fail_exit (E_GRP_UPDATE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2008-03-09 04:14:53 +05:30
|
|
|
if (is_shadow_pwd) {
|
2007-10-07 17:14:59 +05:30
|
|
|
spw_unlock ();
|
2008-06-10 03:38:08 +05:30
|
|
|
shadow_locked = false;
|
2008-03-09 04:14:53 +05:30
|
|
|
}
|
2007-10-07 17:14:59 +05:30
|
|
|
pw_unlock ();
|
2008-06-10 03:38:08 +05:30
|
|
|
passwd_locked = false;
|
2007-10-07 17:17:22 +05:30
|
|
|
gr_unlock ();
|
2008-06-10 03:38:08 +05:30
|
|
|
group_locked = false;
|
2007-10-07 17:17:22 +05:30
|
|
|
#ifdef SHADOWGRP
|
2008-03-09 04:14:53 +05:30
|
|
|
if (is_shadow_grp) {
|
2007-10-07 17:17:22 +05:30
|
|
|
sgr_unlock ();
|
2008-06-10 03:38:08 +05:30
|
|
|
gshadow_locked = false;
|
2008-03-09 04:14:53 +05:30
|
|
|
}
|
2007-10-07 17:17:22 +05:30
|
|
|
#endif
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
{
|
2008-06-10 03:38:08 +05:30
|
|
|
if (pw_lock () == 0) {
|
2007-10-07 17:16:07 +05:30
|
|
|
fprintf (stderr, _("%s: unable to lock password file\n"), Prog);
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
2008-06-14 02:36:04 +05:30
|
|
|
"locking password file",
|
|
|
|
user_name, (unsigned int) user_id, 0);
|
2007-10-07 17:17:01 +05:30
|
|
|
#endif
|
2007-10-07 17:14:59 +05:30
|
|
|
exit (E_PW_UPDATE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2008-06-10 03:38:08 +05:30
|
|
|
passwd_locked = true;
|
|
|
|
if (pw_open (O_RDWR) == 0) {
|
2007-10-07 17:16:07 +05:30
|
|
|
fprintf (stderr, _("%s: unable to open password file\n"), Prog);
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
2008-06-14 02:36:04 +05:30
|
|
|
"opening password file",
|
|
|
|
user_name, (unsigned int) user_id, 0);
|
2007-10-07 17:17:01 +05:30
|
|
|
#endif
|
2008-03-09 04:14:53 +05:30
|
|
|
fail_exit (E_PW_UPDATE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2008-03-09 04:14:53 +05:30
|
|
|
if (is_shadow_pwd) {
|
2008-06-10 03:38:08 +05:30
|
|
|
if (spw_lock () == 0) {
|
2008-03-09 04:14:53 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: cannot lock shadow password file\n"),
|
|
|
|
Prog);
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
2008-03-09 04:14:53 +05:30
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
2008-06-14 02:36:04 +05:30
|
|
|
"locking shadow password file",
|
|
|
|
user_name, (unsigned int) user_id, 0);
|
2007-10-07 17:17:01 +05:30
|
|
|
#endif
|
2008-03-09 04:14:53 +05:30
|
|
|
fail_exit (E_PW_UPDATE);
|
|
|
|
}
|
2008-06-10 03:38:08 +05:30
|
|
|
shadow_locked = true;
|
|
|
|
if (spw_open (O_RDWR) == 0) {
|
2008-03-09 04:14:53 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: cannot open shadow password file\n"),
|
|
|
|
Prog);
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
2008-03-09 04:14:53 +05:30
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
2008-06-14 02:36:04 +05:30
|
|
|
"opening shadow password file",
|
|
|
|
user_name, (unsigned int) user_id, 0);
|
2007-10-07 17:17:01 +05:30
|
|
|
#endif
|
2008-03-09 04:14:53 +05:30
|
|
|
fail_exit (E_PW_UPDATE);
|
|
|
|
}
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2008-03-09 04:14:53 +05:30
|
|
|
|
2007-10-07 17:17:11 +05:30
|
|
|
/*
|
|
|
|
* Lock and open the group file.
|
|
|
|
*/
|
2008-06-10 03:38:08 +05:30
|
|
|
if (gr_lock () == 0) {
|
2007-10-07 17:17:11 +05:30
|
|
|
fprintf (stderr, _("%s: error locking group file\n"), Prog);
|
|
|
|
fail_exit (E_GRP_UPDATE);
|
|
|
|
}
|
2008-06-10 03:38:08 +05:30
|
|
|
group_locked = true;
|
|
|
|
if (gr_open (O_RDWR) == 0) {
|
2007-10-07 17:17:11 +05:30
|
|
|
fprintf (stderr, _("%s: error opening group file\n"), Prog);
|
|
|
|
fail_exit (E_GRP_UPDATE);
|
|
|
|
}
|
|
|
|
#ifdef SHADOWGRP
|
2008-03-09 04:14:53 +05:30
|
|
|
if (is_shadow_grp) {
|
2008-06-10 03:38:08 +05:30
|
|
|
if (sgr_lock () == 0) {
|
2008-03-09 04:14:53 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: error locking shadow group file\n"),
|
|
|
|
Prog);
|
|
|
|
fail_exit (E_GRP_UPDATE);
|
|
|
|
}
|
2008-06-10 03:38:08 +05:30
|
|
|
gshadow_locked = true;
|
|
|
|
if (sgr_open (O_RDWR) == 0) {
|
2008-03-09 04:14:53 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: error opening shadow group file\n"),
|
|
|
|
Prog);
|
|
|
|
fail_exit (E_GRP_UPDATE);
|
|
|
|
}
|
2007-10-07 17:17:11 +05:30
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *empty_list = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* new_grent - initialize the values in a group file entry
|
|
|
|
*
|
|
|
|
* new_grent() takes all of the values that have been entered and fills
|
|
|
|
* in a (struct group) with them.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void new_grent (struct group *grent)
|
|
|
|
{
|
|
|
|
memzero (grent, sizeof *grent);
|
|
|
|
grent->gr_name = (char *) user_name;
|
|
|
|
grent->gr_passwd = SHADOW_PASSWD_STRING; /* XXX warning: const */
|
|
|
|
grent->gr_gid = user_gid;
|
|
|
|
grent->gr_mem = &empty_list;
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
2007-10-07 17:17:11 +05:30
|
|
|
#ifdef SHADOWGRP
|
|
|
|
/*
|
|
|
|
* new_sgent - initialize the values in a shadow group file entry
|
|
|
|
*
|
|
|
|
* new_sgent() takes all of the values that have been entered and fills
|
|
|
|
* in a (struct sgrp) with them.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void new_sgent (struct sgrp *sgent)
|
|
|
|
{
|
|
|
|
memzero (sgent, sizeof *sgent);
|
|
|
|
sgent->sg_name = (char *) user_name;
|
|
|
|
sgent->sg_passwd = "!"; /* XXX warning: const */
|
|
|
|
sgent->sg_adm = &empty_list;
|
|
|
|
sgent->sg_mem = &empty_list;
|
|
|
|
}
|
|
|
|
#endif /* SHADOWGRP */
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* grp_add - add new group file entries
|
|
|
|
*
|
|
|
|
* grp_add() writes the new records to the group files.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void grp_add (void)
|
|
|
|
{
|
|
|
|
struct group grp;
|
|
|
|
|
|
|
|
#ifdef SHADOWGRP
|
|
|
|
struct sgrp sgrp;
|
|
|
|
#endif /* SHADOWGRP */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create the initial entries for this new group.
|
|
|
|
*/
|
|
|
|
new_grent (&grp);
|
|
|
|
#ifdef SHADOWGRP
|
|
|
|
new_sgent (&sgrp);
|
|
|
|
#endif /* SHADOWGRP */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write out the new group file entry.
|
|
|
|
*/
|
2008-06-10 03:38:08 +05:30
|
|
|
if (gr_update (&grp) == 0) {
|
2007-10-07 17:17:11 +05:30
|
|
|
fprintf (stderr, _("%s: error adding new group entry\n"), Prog);
|
|
|
|
fail_exit (E_GRP_UPDATE);
|
|
|
|
}
|
|
|
|
#ifdef SHADOWGRP
|
|
|
|
/*
|
|
|
|
* Write out the new shadow group entries as well.
|
|
|
|
*/
|
2008-06-10 03:38:08 +05:30
|
|
|
if (is_shadow_grp && (sgr_update (&sgrp) == 0)) {
|
2007-10-07 17:17:11 +05:30
|
|
|
fprintf (stderr, _("%s: error adding new group entry\n"), Prog);
|
|
|
|
fail_exit (E_GRP_UPDATE);
|
|
|
|
}
|
|
|
|
#endif /* SHADOWGRP */
|
|
|
|
SYSLOG ((LOG_INFO, "new group: name=%s, GID=%u", user_name, user_gid));
|
2008-06-10 03:38:08 +05:30
|
|
|
do_grp_update = true;
|
2007-10-07 17:17:11 +05:30
|
|
|
}
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
static void faillog_reset (uid_t uid)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
|
|
|
struct faillog fl;
|
|
|
|
int fd;
|
2008-06-16 03:55:51 +05:30
|
|
|
off_t offset_uid = (off_t) (sizeof fl) * uid;
|
|
|
|
|
|
|
|
if (access (FAILLOG_FILE, F_OK) != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
memzero (&fl, sizeof (fl));
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
fd = open (FAILLOG_FILE, O_RDWR);
|
2008-06-16 03:55:51 +05:30
|
|
|
if ( (-1 == fd)
|
|
|
|
|| (lseek (fd, offset_uid, SEEK_SET) != offset_uid)
|
|
|
|
|| (write (fd, &fl, sizeof (fl)) != (ssize_t) sizeof (fl))
|
|
|
|
|| (close (fd) != 0)) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: failed to reset the faillog entry of UID %lu: %s\n"),
|
2008-06-18 03:30:36 +05:30
|
|
|
Prog, (unsigned long) uid, strerror (errno));
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
static void lastlog_reset (uid_t uid)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
|
|
|
struct lastlog ll;
|
|
|
|
int fd;
|
2008-06-16 03:55:51 +05:30
|
|
|
off_t offset_uid = (off_t) (sizeof ll) * uid;
|
|
|
|
|
|
|
|
if (access (LASTLOG_FILE, F_OK) != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
memzero (&ll, sizeof (ll));
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
fd = open (LASTLOG_FILE, O_RDWR);
|
2008-06-16 03:55:51 +05:30
|
|
|
if ( (-1 == fd)
|
|
|
|
|| (lseek (fd, offset_uid, SEEK_SET) != offset_uid)
|
|
|
|
|| (write (fd, &ll, sizeof (ll)) != (ssize_t) sizeof (ll))
|
|
|
|
|| (close (fd) != 0)) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: failed to reset the lastlog entry of UID %lu: %s\n"),
|
2008-06-18 03:30:36 +05:30
|
|
|
Prog, (unsigned long) uid, strerror (errno));
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* usr_update - create the user entries
|
|
|
|
*
|
|
|
|
* usr_update() creates the password file entries for this user
|
|
|
|
* and will update the group entries if required.
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
static void usr_update (void)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
2007-10-07 17:14:59 +05:30
|
|
|
struct passwd pwent;
|
|
|
|
struct spwd spent;
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
/*
|
|
|
|
* Fill in the password structure with any new fields, making
|
|
|
|
* copies of strings.
|
|
|
|
*/
|
|
|
|
new_pwent (&pwent);
|
|
|
|
new_spent (&spent);
|
|
|
|
|
|
|
|
/*
|
2007-10-07 17:14:59 +05:30
|
|
|
* Create a syslog entry. We need to do this now in case anything
|
2007-10-07 17:14:02 +05:30
|
|
|
* happens so we know what we were trying to accomplish.
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
SYSLOG ((LOG_INFO,
|
2007-10-07 17:16:25 +05:30
|
|
|
"new user: name=%s, UID=%u, GID=%u, home=%s, shell=%s",
|
2007-10-07 17:15:23 +05:30
|
|
|
user_name, (unsigned int) user_id,
|
|
|
|
(unsigned int) user_gid, user_home, user_shell));
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize faillog and lastlog entries for this UID in case
|
2007-10-07 17:14:59 +05:30
|
|
|
* it belongs to a previously deleted user. We do it only if
|
2007-10-07 17:14:02 +05:30
|
|
|
* no user with this UID exists yet (entries for shared UIDs
|
|
|
|
* are left unchanged). --marekm
|
|
|
|
*/
|
* 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-12-26 15:45:20 +05:30
|
|
|
if ((!lflg) && (getpwuid (user_id) == NULL)) {
|
2007-10-07 17:14:59 +05:30
|
|
|
faillog_reset (user_id);
|
|
|
|
lastlog_reset (user_id);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Put the new (struct passwd) in the table.
|
|
|
|
*/
|
2008-06-10 03:38:08 +05:30
|
|
|
if (pw_update (&pwent) == 0) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: error adding new password entry\n"), Prog);
|
2008-03-09 04:14:53 +05:30
|
|
|
fail_exit (E_PW_UPDATE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Put the new (struct spwd) in the table.
|
|
|
|
*/
|
2008-06-10 03:38:08 +05:30
|
|
|
if (is_shadow_pwd && (spw_update (&spent) == 0)) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr,
|
2007-10-07 17:16:34 +05:30
|
|
|
_
|
|
|
|
("%s: error adding new shadow password entry\n"),
|
2007-10-07 17:14:59 +05:30
|
|
|
Prog);
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
2008-06-14 02:36:04 +05:30
|
|
|
"adding shadow password",
|
|
|
|
user_name, (unsigned int) user_id, 0);
|
2007-10-07 17:17:01 +05:30
|
|
|
#endif
|
2008-03-09 04:14:53 +05:30
|
|
|
fail_exit (E_PW_UPDATE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
2008-06-14 02:36:04 +05:30
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
|
|
|
"adding user",
|
|
|
|
user_name, (unsigned int) user_id, 1);
|
2007-10-07 17:17:01 +05:30
|
|
|
#endif
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
/*
|
|
|
|
* Do any group file updates for this user.
|
|
|
|
*/
|
2008-06-10 03:38:08 +05:30
|
|
|
if (do_grp_update) {
|
2007-10-07 17:14:59 +05:30
|
|
|
grp_update ();
|
2008-06-10 03:38:08 +05:30
|
|
|
}
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* create_home - create the user's home directory
|
|
|
|
*
|
|
|
|
* create_home() creates the user's home directory if it does not
|
2007-10-07 17:14:59 +05:30
|
|
|
* already exist. It will be created mode 755 owned by the user
|
2007-10-07 17:14:02 +05:30
|
|
|
* with the user's default group.
|
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
static void create_home (void)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
2008-06-10 03:38:08 +05:30
|
|
|
if (access (user_home, F_OK) != 0) {
|
2007-10-07 17:14:02 +05:30
|
|
|
/* XXX - create missing parent directories. --marekm */
|
2008-06-10 03:38:08 +05:30
|
|
|
if (mkdir (user_home, 0) != 0) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr,
|
2007-10-07 17:16:34 +05:30
|
|
|
_
|
|
|
|
("%s: cannot create directory %s\n"),
|
2007-10-07 17:14:59 +05:30
|
|
|
Prog, user_home);
|
2007-10-07 20:06:51 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
2008-06-14 02:36:04 +05:30
|
|
|
"adding home directory",
|
|
|
|
user_name, (unsigned int) user_id, 0);
|
2007-10-07 20:06:51 +05:30
|
|
|
#endif
|
2007-10-07 17:14:59 +05:30
|
|
|
fail_exit (E_HOMEDIR);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
chown (user_home, user_id, user_gid);
|
2007-10-07 17:17:22 +05:30
|
|
|
chmod (user_home,
|
|
|
|
0777 & ~getdef_num ("UMASK", GETDEF_DEFAULT_UMASK));
|
2008-06-10 03:38:08 +05:30
|
|
|
home_added = true;
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
2008-06-14 02:36:04 +05:30
|
|
|
"adding home directory",
|
|
|
|
user_name, (unsigned int) user_id, 1);
|
2007-10-07 17:17:01 +05:30
|
|
|
#endif
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-07 17:15:40 +05:30
|
|
|
/*
|
|
|
|
* create_mail - create the user's mail spool
|
|
|
|
*
|
|
|
|
* create_mail() creates the user's mail spool if it does not already
|
|
|
|
* exist. It will be created mode 660 owned by the user and group
|
|
|
|
* 'mail'
|
|
|
|
*/
|
|
|
|
static void create_mail (void)
|
|
|
|
{
|
2007-10-07 17:17:33 +05:30
|
|
|
char *spool, *file;
|
2007-10-07 17:15:40 +05:30
|
|
|
int fd;
|
2007-10-07 17:17:33 +05:30
|
|
|
struct group *gr;
|
|
|
|
gid_t gid;
|
2007-10-07 17:15:40 +05:30
|
|
|
mode_t mode;
|
|
|
|
|
|
|
|
if (strcasecmp (create_mail_spool, "yes") == 0) {
|
2008-01-01 20:04:07 +05:30
|
|
|
spool = getdef_str ("MAIL_DIR");
|
|
|
|
if (NULL == spool) {
|
|
|
|
spool = "/var/mail";
|
|
|
|
}
|
2007-10-07 17:17:33 +05:30
|
|
|
file = alloca (strlen (spool) + strlen (user_name) + 2);
|
|
|
|
sprintf (file, "%s/%s", spool, user_name);
|
|
|
|
fd = open (file, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0);
|
|
|
|
if (fd < 0) {
|
|
|
|
perror (_("Creating mailbox file"));
|
|
|
|
return;
|
2007-10-07 17:17:45 +05:30
|
|
|
}
|
2007-10-07 17:15:40 +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
|
|
|
gr = getgrnam ("mail"); /* local, no need for xgetgrnam */
|
2008-06-10 03:38:08 +05:30
|
|
|
if (NULL == gr) {
|
2008-01-25 02:12:12 +05:30
|
|
|
fputs (_("Group 'mail' not found. Creating the user mailbox file with 0600 mode.\n"),
|
|
|
|
stderr);
|
2007-10-07 17:17:45 +05:30
|
|
|
gid = user_gid;
|
|
|
|
mode = 0600;
|
|
|
|
} else {
|
|
|
|
gid = gr->gr_gid;
|
|
|
|
mode = 0660;
|
|
|
|
}
|
2007-10-07 17:17:33 +05:30
|
|
|
|
2008-06-10 03:38:08 +05:30
|
|
|
if ( (fchown (fd, user_id, gid) != 0)
|
|
|
|
|| (fchmod (fd, mode) != 0)) {
|
2007-10-07 17:17:45 +05:30
|
|
|
perror (_("Setting mailbox file permissions"));
|
2008-06-10 03:38:08 +05:30
|
|
|
}
|
2007-10-07 17:17:33 +05:30
|
|
|
|
2007-10-07 17:17:45 +05:30
|
|
|
close (fd);
|
2007-10-07 17:15:40 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
/*
|
|
|
|
* main - useradd 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:15:40 +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
|
|
|
|
2008-06-10 03:38:08 +05:30
|
|
|
(void) setlocale (LC_ALL, "");
|
|
|
|
(void) bindtextdomain (PACKAGE, LOCALEDIR);
|
|
|
|
(void) textdomain (PACKAGE);
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2007-10-07 17:16:07 +05:30
|
|
|
OPENLOG ("useradd");
|
2007-10-07 17:15:40 +05:30
|
|
|
|
2007-10-07 17:16:07 +05:30
|
|
|
sys_ngroups = sysconf (_SC_NGROUPS_MAX);
|
|
|
|
user_groups = malloc ((1 + sys_ngroups) * sizeof (char *));
|
2007-10-07 17:17:11 +05:30
|
|
|
/*
|
|
|
|
* Initialize the list to be empty
|
|
|
|
*/
|
|
|
|
user_groups[0] = (char *) 0;
|
|
|
|
|
2007-10-07 17:15:40 +05:30
|
|
|
|
2007-10-07 17:16:07 +05:30
|
|
|
is_shadow_pwd = spw_file_present ();
|
2007-10-07 17:15:40 +05:30
|
|
|
#ifdef SHADOWGRP
|
2007-10-07 17:16:07 +05:30
|
|
|
is_shadow_grp = sgr_file_present ();
|
2007-10-07 17:15:40 +05:30
|
|
|
#endif
|
|
|
|
|
2007-10-07 17:16:07 +05:30
|
|
|
get_defaults ();
|
2007-10-07 17:15:40 +05:30
|
|
|
|
2007-10-07 17:16:07 +05:30
|
|
|
process_flags (argc, argv);
|
2007-10-07 17:15:40 +05:30
|
|
|
|
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
|
|
|
|
2008-06-10 03:38:08 +05:30
|
|
|
if (PAM_SUCCESS == retval) {
|
* 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
|
|
|
retval = pam_start ("useradd", pampw->pw_name,
|
|
|
|
&conv, &pamh);
|
|
|
|
}
|
2007-10-07 17:14:38 +05:30
|
|
|
}
|
|
|
|
|
2008-06-10 03:38:08 +05:30
|
|
|
if (PAM_SUCCESS == retval) {
|
2007-10-07 17:14:59 +05:30
|
|
|
retval = pam_authenticate (pamh, 0);
|
2008-06-10 03:38:08 +05:30
|
|
|
if (PAM_SUCCESS != retval) {
|
|
|
|
(void) pam_end (pamh, retval);
|
2007-10-07 17:14:38 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-10 03:38:08 +05:30
|
|
|
if (PAM_SUCCESS == retval) {
|
2007-10-07 17:14:59 +05:30
|
|
|
retval = pam_acct_mgmt (pamh, 0);
|
2008-06-10 03:38:08 +05:30
|
|
|
if (PAM_SUCCESS != retval) {
|
|
|
|
(void) pam_end (pamh, retval);
|
2007-10-07 17:14:38 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-10 03:38:08 +05:30
|
|
|
if (PAM_SUCCESS != retval) {
|
2007-10-07 17:16:07 +05:30
|
|
|
fprintf (stderr, _("%s: PAM authentication failed\n"), Prog);
|
2008-03-09 04:14:53 +05:30
|
|
|
fail_exit (1);
|
2007-10-07 17:14:38 +05:30
|
|
|
}
|
2007-10-07 17:15:40 +05:30
|
|
|
#endif /* USE_PAM */
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
/*
|
|
|
|
* See if we are messing with the defaults file, or creating
|
|
|
|
* a new user.
|
|
|
|
*/
|
|
|
|
if (Dflg) {
|
2008-06-10 03:38:08 +05:30
|
|
|
if (gflg || bflg || fflg || eflg || sflg) {
|
|
|
|
exit ((set_defaults () != 0) ? 1 : 0);
|
|
|
|
}
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2007-10-07 17:14:59 +05:30
|
|
|
show_defaults ();
|
|
|
|
exit (E_SUCCESS);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Start with a quick check to see if the user exists.
|
|
|
|
*/
|
2008-06-10 03:38:08 +05:30
|
|
|
if (getpwnam (user_name) != NULL) { /* local, no need for xgetpwnam */
|
2007-10-07 17:16:07 +05:30
|
|
|
fprintf (stderr, _("%s: user %s exists\n"), Prog, user_name);
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
2008-06-14 02:36:04 +05:30
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
|
|
|
"adding user",
|
|
|
|
user_name, AUDIT_NO_ID, 0);
|
2007-10-07 17:17:01 +05:30
|
|
|
#endif
|
2008-03-09 04:14:53 +05:30
|
|
|
fail_exit (E_NAME_IN_USE);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
2007-10-07 17:14:38 +05:30
|
|
|
/*
|
|
|
|
* Don't blindly overwrite a group when a user is added...
|
|
|
|
* If you already have a group username, and want to add the user
|
|
|
|
* to that group, use useradd -g username username.
|
|
|
|
* --bero
|
|
|
|
*/
|
2008-02-26 02:33:46 +05:30
|
|
|
if (Uflg) {
|
2008-06-10 03:38:08 +05:30
|
|
|
/* local, no need for xgetgrnam */
|
|
|
|
if (getgrnam (user_name) != NULL) {
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_
|
|
|
|
("%s: group %s exists - if you want to add this user to that group, use -g.\n"),
|
|
|
|
Prog, user_name);
|
2007-10-07 17:17:01 +05:30
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
2008-06-14 02:36:04 +05:30
|
|
|
"adding group",
|
|
|
|
user_name, AUDIT_NO_ID, 0);
|
2007-10-07 17:17:01 +05:30
|
|
|
#endif
|
2008-03-09 04:14:53 +05:30
|
|
|
fail_exit (E_NAME_IN_USE);
|
2007-10-07 17:14:59 +05:30
|
|
|
}
|
2007-10-07 17:14:38 +05:30
|
|
|
}
|
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
/*
|
2007-10-07 17:15:23 +05:30
|
|
|
* Do the hard stuff:
|
|
|
|
* - open the files,
|
|
|
|
* - create the user entries,
|
|
|
|
* - create the home directory,
|
2007-10-07 17:16:52 +05:30
|
|
|
* - create user mail spool,
|
2007-10-07 17:15:23 +05:30
|
|
|
* - flush nscd caches for passwd and group services,
|
|
|
|
* - then close and update the files.
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
|
|
|
open_files ();
|
|
|
|
|
2007-10-07 17:17:22 +05:30
|
|
|
if (!oflg) {
|
|
|
|
/* first, seek for a valid uid to use for this user.
|
|
|
|
* We do this because later we can use the uid we found as
|
|
|
|
* gid too ... --gafton */
|
2008-02-03 22:26:23 +05:30
|
|
|
if (!uflg) {
|
2008-02-20 02:31:38 +05:30
|
|
|
if (find_new_uid (rflg, &user_id, NULL) < 0) {
|
2008-02-03 22:26:23 +05:30
|
|
|
fprintf (stderr, _("%s: can't create user\n"), Prog);
|
|
|
|
fail_exit (E_UID_IN_USE);
|
|
|
|
}
|
|
|
|
} else {
|
2007-12-26 18:48:27 +05:30
|
|
|
if (getpwuid (user_id) != NULL) {
|
2008-06-14 02:36:04 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: UID %lu is not unique\n"),
|
|
|
|
Prog, (unsigned long) user_id);
|
2007-12-26 18:48:27 +05:30
|
|
|
#ifdef WITH_AUDIT
|
2008-06-14 02:36:04 +05:30
|
|
|
audit_logger (AUDIT_USER_CHAUTHTOK, Prog,
|
|
|
|
"adding user",
|
|
|
|
user_name, (unsigned int) user_id, 0);
|
2007-12-26 18:48:27 +05:30
|
|
|
#endif
|
2008-03-09 04:14:53 +05:30
|
|
|
fail_exit (E_UID_IN_USE);
|
2007-12-26 18:48:27 +05:30
|
|
|
}
|
|
|
|
}
|
2007-10-07 17:17:22 +05:30
|
|
|
}
|
2007-10-07 17:17:11 +05:30
|
|
|
|
|
|
|
/* do we have to add a group for that user? This is why we need to
|
|
|
|
* open the group files in the open_files() function --gafton */
|
2008-02-26 02:33:46 +05:30
|
|
|
if (Uflg) {
|
2008-02-20 02:31:38 +05:30
|
|
|
if (find_new_gid (rflg, &user_gid, &user_id) < 0) {
|
2008-02-03 22:26:23 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: can't create group\n"),
|
|
|
|
Prog);
|
|
|
|
fail_exit (4);
|
|
|
|
}
|
2007-10-07 17:17:11 +05:30
|
|
|
grp_add ();
|
|
|
|
}
|
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
usr_update ();
|
|
|
|
|
|
|
|
if (mflg) {
|
|
|
|
create_home ();
|
2007-10-07 17:16:52 +05:30
|
|
|
if (home_added)
|
|
|
|
copy_tree (def_template, user_home, user_id, user_gid);
|
|
|
|
else
|
|
|
|
fprintf (stderr,
|
|
|
|
_
|
|
|
|
("%s: warning: the home directory already exists.\n"
|
2007-10-07 17:17:01 +05:30
|
|
|
"Not copying any file from skel directory into it.\n"),
|
|
|
|
Prog);
|
2007-10-07 17:16:52 +05:30
|
|
|
|
2008-06-10 03:38:08 +05:30
|
|
|
} else if (getdef_str ("CREATE_HOME") != NULL) {
|
2007-10-07 17:14:02 +05:30
|
|
|
/*
|
|
|
|
* RedHat added the CREATE_HOME option in login.defs in their
|
|
|
|
* version of shadow-utils (which makes -m the default, with
|
2007-10-07 17:14:59 +05:30
|
|
|
* new -M option to turn it off). Unfortunately, this
|
2007-10-07 17:14:02 +05:30
|
|
|
* changes the way useradd works (it can be run by scripts
|
|
|
|
* expecting some standard behaviour), compared to other
|
|
|
|
* Unices and other Linux distributions, and also adds a lot
|
|
|
|
* of confusion :-(.
|
|
|
|
* So we now recognize CREATE_HOME and give a warning here
|
|
|
|
* (better than "configuration error ... notify administrator"
|
2007-10-07 17:14:59 +05:30
|
|
|
* errors in every program that reads /etc/login.defs). -MM
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
2007-10-07 17:14:59 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_
|
|
|
|
("%s: warning: CREATE_HOME not supported, please use -m instead.\n"),
|
|
|
|
Prog);
|
2007-10-07 17:14:02 +05:30
|
|
|
}
|
|
|
|
|
2007-10-07 17:15:40 +05:30
|
|
|
create_mail ();
|
|
|
|
|
2007-10-07 20:06:51 +05:30
|
|
|
close_files ();
|
|
|
|
|
2007-10-07 17:15:23 +05:30
|
|
|
nscd_flush_cache ("passwd");
|
|
|
|
nscd_flush_cache ("group");
|
|
|
|
|
2007-10-07 17:14:38 +05:30
|
|
|
#ifdef USE_PAM
|
2008-06-10 03:38:08 +05:30
|
|
|
if (PAM_SUCCESS == retval) {
|
|
|
|
(void) pam_end (pamh, PAM_SUCCESS);
|
|
|
|
}
|
2007-10-07 17:14:59 +05:30
|
|
|
#endif /* USE_PAM */
|
2007-10-07 17:14:38 +05:30
|
|
|
|
2008-03-09 04:14:53 +05:30
|
|
|
return E_SUCCESS;
|
2007-10-07 17:15:23 +05:30
|
|
|
}
|
2008-06-10 03:38:08 +05:30
|
|
|
|