New pw -R rootdir option

This allows to set an alternate root directory in which the users/groups will be
manipulated

Requested by:	gjb, ian
Tested by:	gjb
This commit is contained in:
Baptiste Daroussin 2015-06-03 19:08:25 +00:00
parent 23c9098b2a
commit ac72be285f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=283961
3 changed files with 90 additions and 39 deletions

View File

@ -56,7 +56,7 @@ static const char *Combo2[] = {
struct pwf PWF =
{
0,
PWF_REGULAR,
setpwent,
endpwent,
getpwent,
@ -71,7 +71,7 @@ struct pwf PWF =
};
struct pwf VPWF =
{
1,
PWF_ALT,
vsetpwent,
vendpwent,
vgetpwent,
@ -99,24 +99,27 @@ main(int argc, char *argv[])
char *config = NULL;
struct userconf *cnf;
struct stat st;
char arg;
struct carg *carg;
char *etcpath = NULL;
static const char *opts[W_NUM][M_NUM] =
{
{ /* user */
"V:C:qn:u:c:d:e:p:g:G:mM:k:s:oL:i:w:h:H:Db:NPy:Y",
"V:C:qn:u:rY",
"V:C:qn:u:c:d:e:p:g:G:mM:l:k:s:w:L:h:H:FNPY",
"V:C:qn:u:FPa7",
"V:C:q",
"V:C:q",
"V:C:q"
"R:V:C:qn:u:c:d:e:p:g:G:mM:k:s:oL:i:w:h:H:Db:NPy:Y",
"R:V:C:qn:u:rY",
"R:V:C:qn:u:c:d:e:p:g:G:mM:l:k:s:w:L:h:H:FNPY",
"R:V:C:qn:u:FPa7",
"R:V:C:q",
"R:V:C:q",
"R:V:C:q"
},
{ /* grp */
"V:C:qn:g:h:H:M:opNPY",
"V:C:qn:g:Y",
"V:C:qn:d:g:l:h:H:FM:m:NPY",
"V:C:qn:g:FPa",
"V:C:q"
"R:V:C:qn:g:h:H:M:opNPY",
"R:V:C:qn:g:Y",
"R:V:C:qn:d:g:l:h:H:FM:m:NPY",
"R:V:C:qn:g:FPa",
"R:V:C:q"
}
};
@ -141,7 +144,8 @@ main(int argc, char *argv[])
/*
* Special case, allow pw -V<dir> <operation> [args] for scripts etc.
*/
if (argv[1][1] == 'V') {
arg = argv[1][1];
if (arg == 'V' || arg == 'R') {
optarg = &argv[1][2];
if (*optarg == '\0') {
if (stat(argv[2], &st) != 0)
@ -155,7 +159,7 @@ main(int argc, char *argv[])
++argv;
--argc;
}
addarg(&arglist, 'V', optarg);
addarg(&arglist, arg, optarg);
} else
break;
}
@ -217,19 +221,29 @@ main(int argc, char *argv[])
config = getarg(&arglist, 'C') ? getarg(&arglist, 'C')->val : NULL;
if (getarg(&arglist, 'V') != NULL) {
char * etcpath = getarg(&arglist, 'V')->val;
if (*etcpath) {
if (config == NULL) { /* Only override config location if -C not specified */
asprintf(&config, "%s/pw.conf", etcpath);
if (config == NULL)
errx(EX_OSERR, "out of memory");
}
memcpy(&PWF, &VPWF, sizeof PWF);
setpwdir(etcpath);
setgrdir(etcpath);
}
if ((carg = getarg(&arglist, 'R')) != NULL) {
asprintf(&etcpath, "%s/etc", carg->val);
if (etcpath == NULL)
errx(EX_OSERR, "out of memory");
}
if (etcpath == NULL && (carg = getarg(&arglist, 'V')) != NULL) {
etcpath = strdup(carg->val);
if (etcpath == NULL)
errx(EX_OSERR, "out of memory");
}
if (etcpath && *etcpath) {
if (config == NULL) { /* Only override config location if -C not specified */
asprintf(&config, "%s/pw.conf", etcpath);
if (config == NULL)
errx(EX_OSERR, "out of memory");
}
setpwdir(etcpath);
setgrdir(etcpath);
memcpy(&PWF, &VPWF, sizeof PWF);
if (getarg(&arglist, 'R'))
PWF._altdir = PWF_ROOTDIR;
}
free(etcpath);
/*
* Now, let's do the common initialisation
@ -303,6 +317,7 @@ cmdhelp(int mode, int which)
{
"usage: pw useradd [name] [switches]\n"
"\t-V etcdir alternate /etc location\n"
"\t-R rootir alternate root directory\n"
"\t-C config configuration file\n"
"\t-q quiet operation\n"
" Adding users:\n"
@ -325,6 +340,7 @@ cmdhelp(int mode, int which)
"\t-N no update\n"
" Setting defaults:\n"
"\t-V etcdir alternate /etc location\n"
"\t-R rootir alternate root directory\n"
"\t-D set user defaults\n"
"\t-b dir default home root dir\n"
"\t-e period default expiry period\n"
@ -341,12 +357,14 @@ cmdhelp(int mode, int which)
"\t-y path set NIS passwd file path\n",
"usage: pw userdel [uid|name] [switches]\n"
"\t-V etcdir alternate /etc location\n"
"\t-R rootir alternate root directory\n"
"\t-n name login name\n"
"\t-u uid user id\n"
"\t-Y update NIS maps\n"
"\t-r remove home & contents\n",
"usage: pw usermod [uid|name] [switches]\n"
"\t-V etcdir alternate /etc location\n"
"\t-R rootir alternate root directory\n"
"\t-C config configuration file\n"
"\t-q quiet operation\n"
"\t-F force add if no user\n"
@ -370,6 +388,7 @@ cmdhelp(int mode, int which)
"\t-N no update\n",
"usage: pw usershow [uid|name] [switches]\n"
"\t-V etcdir alternate /etc location\n"
"\t-R rootir alternate root directory\n"
"\t-n name login name\n"
"\t-u uid user id\n"
"\t-F force print\n"
@ -378,6 +397,7 @@ cmdhelp(int mode, int which)
"\t-7 print in v7 format\n",
"usage: pw usernext [switches]\n"
"\t-V etcdir alternate /etc location\n"
"\t-R rootir alternate root directory\n"
"\t-C config configuration file\n"
"\t-q quiet operation\n",
"usage pw: lock [switches]\n"
@ -392,6 +412,7 @@ cmdhelp(int mode, int which)
{
"usage: pw groupadd [group|gid] [switches]\n"
"\t-V etcdir alternate /etc location\n"
"\t-R rootir alternate root directory\n"
"\t-C config configuration file\n"
"\t-q quiet operation\n"
"\t-n group group name\n"
@ -402,11 +423,13 @@ cmdhelp(int mode, int which)
"\t-N no update\n",
"usage: pw groupdel [group|gid] [switches]\n"
"\t-V etcdir alternate /etc location\n"
"\t-R rootir alternate root directory\n"
"\t-n name group name\n"
"\t-g gid group id\n"
"\t-Y update NIS maps\n",
"usage: pw groupmod [group|gid] [switches]\n"
"\t-V etcdir alternate /etc location\n"
"\t-R rootir alternate root directory\n"
"\t-C config configuration file\n"
"\t-q quiet operation\n"
"\t-F force add if not exists\n"
@ -420,6 +443,7 @@ cmdhelp(int mode, int which)
"\t-N no update\n",
"usage: pw groupshow [group|gid] [switches]\n"
"\t-V etcdir alternate /etc location\n"
"\t-R rootir alternate root directory\n"
"\t-n name group name\n"
"\t-g gid group id\n"
"\t-F force print\n"
@ -427,6 +451,7 @@ cmdhelp(int mode, int which)
"\t-a print all accounting groups\n",
"usage: pw groupnext [switches]\n"
"\t-V etcdir alternate /etc location\n"
"\t-R rootir alternate root directory\n"
"\t-C config configuration file\n"
"\t-q quiet operation\n"
}

View File

@ -63,6 +63,28 @@ static char *shell_path(char const * path, char *shells[], char *sh);
static void rmat(uid_t uid);
static void rmopie(char const * name);
static void
create_and_populate_homedir(int mode, struct cargs *args, struct passwd *pwd,
struct userconf *cnf)
{
char *homedir, *dotdir;
struct carg *arg;
homedir = dotdir = NULL;
if ((arg = getarg(args, 'R'))) {
asprintf(&homedir, "%s/%s", arg->val, pwd->pw_dir);
if (homedir == NULL)
errx(EX_OSERR, "out of memory");
asprintf(&dotdir, "%s/%s", arg->val, cnf->dotdir);
}
copymkdir(homedir ? homedir : pwd->pw_dir, dotdir ? dotdir: cnf->dotdir,
cnf->homemode, pwd->pw_uid, pwd->pw_gid);
pw_log(cnf, mode, W_USER, "%s(%u) home %s made", pwd->pw_name,
pwd->pw_uid, pwd->pw_dir);
}
/*-
* -C config configuration file
* -q quiet operation
@ -108,6 +130,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
struct group *grp;
struct stat st;
char line[_PASSWORD_LEN+1];
char path[MAXPATHLEN];
FILE *fp;
char *dmode_c;
void *set = NULL;
@ -451,7 +474,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
pw_log(cnf, mode, W_USER, "%s(%u) account removed", a_name->val, uid);
if (!PWALTDIR()) {
if (PWALTDIR()) {
/*
* Remove mail file
*/
@ -800,11 +823,13 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
* doesn't hurt anything to create the empty mailfile
*/
if (mode == M_ADD) {
if (!PWALTDIR()) {
snprintf(line, sizeof(line), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
close(open(line, O_RDWR | O_CREAT, 0600)); /* Preserve contents &
if (PWALTDIR() != PWF_ALT) {
arg = getarg(args, 'R');
snprintf(path, sizeof(path), "%s%s/%s",
arg ? arg->val : "", _PATH_MAILDIR, pwd->pw_name);
close(open(path, O_RDWR | O_CREAT, 0600)); /* Preserve contents &
* mtime */
chown(line, pwd->pw_uid, pwd->pw_gid);
chown(path, pwd->pw_uid, pwd->pw_gid);
}
}
@ -813,12 +838,9 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
* that this also `works' for editing users if -m is used, but
* existing files will *not* be overwritten.
*/
if (!PWALTDIR() && getarg(args, 'm') != NULL && pwd->pw_dir && *pwd->pw_dir == '/' && pwd->pw_dir[1]) {
copymkdir(pwd->pw_dir, cnf->dotdir, cnf->homemode, pwd->pw_uid, pwd->pw_gid);
pw_log(cnf, mode, W_USER, "%s(%u) home %s made",
pwd->pw_name, pwd->pw_uid, pwd->pw_dir);
}
if (PWALTDIR() != PWF_ALT && getarg(args, 'm') != NULL && pwd->pw_dir &&
*pwd->pw_dir == '/' && pwd->pw_dir[1])
create_and_populate_homedir(mode, args, pwd, cnf);
/*
* Finally, send mail to the new user as well, if we are asked to

View File

@ -71,6 +71,10 @@ extern struct pwf VPWF;
#define GETGRGID(gid) PWF._getgrgid(gid)
#define GETGRNAM(nam) PWF._getgrnam(nam)
#define PWF_REGULAR 0
#define PWF_ALT 1
#define PWF_ROOTDIR 2
#define PWALTDIR() PWF._altdir
#ifndef _PATH_PWD
#define _PATH_PWD "/etc"