chfn: make command to obey login.defs CHFN_RESTRICT instructions
Reference: http://man7.org/linux/man-pages/man5/login.defs.5.html Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=138519 Signed-off-by: Sami Kerola <kerolasa@iki.fi>
This commit is contained in:
parent
f723cbf544
commit
e88f005949
|
@ -119,7 +119,11 @@ chfn_chsh_sources += \
|
||||||
chfn_chsh_ldadd += -lselinux
|
chfn_chsh_ldadd += -lselinux
|
||||||
endif
|
endif
|
||||||
|
|
||||||
chfn_SOURCES = login-utils/chfn.c $(chfn_chsh_sources)
|
chfn_SOURCES = \
|
||||||
|
login-utils/chfn.c \
|
||||||
|
login-utils/logindefs.c \
|
||||||
|
login-utils/logindefs.h \
|
||||||
|
$(chfn_chsh_sources)
|
||||||
chfn_CFLAGS = $(chfn_chsh_cflags)
|
chfn_CFLAGS = $(chfn_chsh_cflags)
|
||||||
chfn_LDFLAGS = $(chfn_chsh_ldflags)
|
chfn_LDFLAGS = $(chfn_chsh_ldflags)
|
||||||
chfn_LDADD = $(LDADD) $(chfn_chsh_ldadd)
|
chfn_LDADD = $(LDADD) $(chfn_chsh_ldadd)
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include "setpwnam.h"
|
#include "setpwnam.h"
|
||||||
#include "strutils.h"
|
#include "strutils.h"
|
||||||
#include "xalloc.h"
|
#include "xalloc.h"
|
||||||
|
#include "logindefs.h"
|
||||||
|
|
||||||
#ifdef HAVE_LIBSELINUX
|
#ifdef HAVE_LIBSELINUX
|
||||||
# include <selinux/selinux.h>
|
# include <selinux/selinux.h>
|
||||||
|
@ -71,6 +72,10 @@ struct chfn_control {
|
||||||
* In the end, "newf" is folded into "oldf". */
|
* In the end, "newf" is folded into "oldf". */
|
||||||
struct finfo oldf, newf;
|
struct finfo oldf, newf;
|
||||||
unsigned int
|
unsigned int
|
||||||
|
allow_fullname:1, /* The login.defs restriction */
|
||||||
|
allow_room:1, /* see: man login.defs(5) */
|
||||||
|
allow_work:1, /* and look for CHFN_RESTRICT */
|
||||||
|
allow_home:1, /* keyword for these four. */
|
||||||
changed:1, /* is change requested */
|
changed:1, /* is change requested */
|
||||||
interactive:1; /* whether to prompt for fields or not */
|
interactive:1; /* whether to prompt for fields or not */
|
||||||
};
|
};
|
||||||
|
@ -144,18 +149,26 @@ static void parse_argv(struct chfn_control *ctl, int argc, char **argv)
|
||||||
&index)) != -1) {
|
&index)) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'f':
|
case 'f':
|
||||||
|
if (!ctl->allow_fullname)
|
||||||
|
errx(EXIT_FAILURE, _("login.defs forbids setting %s"), _("Name"));
|
||||||
ctl->newf.full_name = optarg;
|
ctl->newf.full_name = optarg;
|
||||||
status += check_gecos_string(_("Name"), optarg);
|
status += check_gecos_string(_("Name"), optarg);
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
|
if (!ctl->allow_room)
|
||||||
|
errx(EXIT_FAILURE, _("login.defs forbids setting %s"), _("Office"));
|
||||||
ctl->newf.office = optarg;
|
ctl->newf.office = optarg;
|
||||||
status += check_gecos_string(_("Office"), optarg);
|
status += check_gecos_string(_("Office"), optarg);
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
|
if (!ctl->allow_work)
|
||||||
|
errx(EXIT_FAILURE, _("login.defs forbids setting %s"), _("Office Phone"));
|
||||||
ctl->newf.office_phone = optarg;
|
ctl->newf.office_phone = optarg;
|
||||||
status += check_gecos_string(_("Office Phone"), optarg);
|
status += check_gecos_string(_("Office Phone"), optarg);
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
|
if (!ctl->allow_home)
|
||||||
|
errx(EXIT_FAILURE, _("login.defs forbids setting %s"), _("Home Phone"));
|
||||||
ctl->newf.home_phone = optarg;
|
ctl->newf.home_phone = optarg;
|
||||||
status += check_gecos_string(_("Home Phone"), optarg);
|
status += check_gecos_string(_("Home Phone"), optarg);
|
||||||
break;
|
break;
|
||||||
|
@ -238,17 +251,70 @@ static char *ask_new_field(struct chfn_control *ctl, const char *question,
|
||||||
return xstrdup(ans);
|
return xstrdup(ans);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get_login_defs()
|
||||||
|
* find /etc/login.defs CHFN_RESTRICT and save restrictions to run time
|
||||||
|
*/
|
||||||
|
static void get_login_defs(struct chfn_control *ctl)
|
||||||
|
{
|
||||||
|
const char *s;
|
||||||
|
size_t i;
|
||||||
|
int broken = 0;
|
||||||
|
|
||||||
|
/* real root does not have restrictions */
|
||||||
|
if (geteuid() == getuid() && getuid() == 0) {
|
||||||
|
ctl->allow_fullname = ctl->allow_room = ctl->allow_work = ctl->allow_home = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s = getlogindefs_str("CHFN_RESTRICT", "");
|
||||||
|
if (!strcmp(s, "yes")) {
|
||||||
|
ctl->allow_room = ctl->allow_work = ctl->allow_home = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!strcmp(s, "no")) {
|
||||||
|
ctl->allow_fullname = ctl->allow_room = ctl->allow_work = ctl->allow_home = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (i = 0; s[i]; i++) {
|
||||||
|
switch (s[i]) {
|
||||||
|
case 'f':
|
||||||
|
ctl->allow_fullname = 1;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
ctl->allow_room = 1;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
ctl->allow_work = 1;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
ctl->allow_home = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
broken = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (broken)
|
||||||
|
warnx(_("%s: CHFN_RESTRICT has unexpected value: %s"), _PATH_LOGINDEFS, s);
|
||||||
|
if (!ctl->allow_fullname && !ctl->allow_room && !ctl->allow_work && !ctl->allow_home)
|
||||||
|
errx(EXIT_FAILURE, _("%s: CHFN_RESTRICT does not allow any changes"), _PATH_LOGINDEFS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ask_info () --
|
* ask_info () --
|
||||||
* prompt the user for the finger information and store it.
|
* prompt the user for the finger information and store it.
|
||||||
*/
|
*/
|
||||||
static void ask_info(struct chfn_control *ctl)
|
static void ask_info(struct chfn_control *ctl)
|
||||||
{
|
{
|
||||||
ctl->newf.full_name = ask_new_field(ctl, _("Name"), ctl->oldf.full_name);
|
if (ctl->allow_fullname)
|
||||||
ctl->newf.office = ask_new_field(ctl, _("Office"), ctl->oldf.office);
|
ctl->newf.full_name = ask_new_field(ctl, _("Name"), ctl->oldf.full_name);
|
||||||
ctl->newf.office_phone = ask_new_field(ctl, _("Office Phone"), ctl->oldf.office_phone);
|
if (ctl->allow_room)
|
||||||
ctl->newf.home_phone = ask_new_field(ctl, _("Home Phone"), ctl->oldf.home_phone);
|
ctl->newf.office = ask_new_field(ctl, _("Office"), ctl->oldf.office);
|
||||||
printf("\n");
|
if (ctl->allow_work)
|
||||||
|
ctl->newf.office_phone = ask_new_field(ctl, _("Office Phone"), ctl->oldf.office_phone);
|
||||||
|
if (ctl->allow_home)
|
||||||
|
ctl->newf.home_phone = ask_new_field(ctl, _("Home Phone"), ctl->oldf.home_phone);
|
||||||
|
putchar('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -335,6 +401,9 @@ int main(int argc, char **argv)
|
||||||
atexit(close_stdout);
|
atexit(close_stdout);
|
||||||
uid = getuid();
|
uid = getuid();
|
||||||
|
|
||||||
|
/* check /etc/login.defs CHFN_RESTRICT */
|
||||||
|
get_login_defs(&ctl);
|
||||||
|
|
||||||
parse_argv(&ctl, argc, argv);
|
parse_argv(&ctl, argc, argv);
|
||||||
if (!ctl.username) {
|
if (!ctl.username) {
|
||||||
ctl.pw = getpwuid(uid);
|
ctl.pw = getpwuid(uid);
|
||||||
|
@ -395,8 +464,8 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
if (ctl.interactive)
|
if (ctl.interactive)
|
||||||
ask_info(&ctl);
|
ask_info(&ctl);
|
||||||
else
|
|
||||||
add_missing(&ctl);
|
add_missing(&ctl);
|
||||||
|
|
||||||
if (!ctl.changed) {
|
if (!ctl.changed) {
|
||||||
printf(_("Finger information not changed.\n"));
|
printf(_("Finger information not changed.\n"));
|
||||||
|
|
Loading…
Reference in New Issue