]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
chfn: make command to obey login.defs CHFN_RESTRICT instructions
authorSami Kerola <kerolasa@iki.fi>
Sun, 14 Dec 2014 16:45:50 +0000 (16:45 +0000)
committerSami Kerola <kerolasa@iki.fi>
Fri, 19 Dec 2014 09:11:04 +0000 (09:11 +0000)
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>
login-utils/Makemodule.am
login-utils/chfn.c

index 47291afd3d45246dbec70e2233cf18e9398e8712..e1f88c37731f01654341e1e14d0febfad3b198fe 100644 (file)
@@ -119,7 +119,11 @@ chfn_chsh_sources += \
 chfn_chsh_ldadd += -lselinux
 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_LDFLAGS = $(chfn_chsh_ldflags)
 chfn_LDADD = $(LDADD) $(chfn_chsh_ldadd)
index 50beea3ed24acd1cc0d1ffeda084279b3ba739e6..b42ad4f27078b93106a1b4236ba856c65e8f748f 100644 (file)
@@ -40,6 +40,7 @@
 #include "setpwnam.h"
 #include "strutils.h"
 #include "xalloc.h"
+#include "logindefs.h"
 
 #ifdef HAVE_LIBSELINUX
 # include <selinux/selinux.h>
@@ -71,6 +72,10 @@ struct chfn_control {
         *  In the end, "newf" is folded into "oldf".  */
        struct finfo oldf, newf;
        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 */
                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) {
                switch (c) {
                case 'f':
+                       if (!ctl->allow_fullname)
+                               errx(EXIT_FAILURE, _("login.defs forbids setting %s"), _("Name"));
                        ctl->newf.full_name = optarg;
                        status += check_gecos_string(_("Name"), optarg);
                        break;
                case 'o':
+                       if (!ctl->allow_room)
+                               errx(EXIT_FAILURE, _("login.defs forbids setting %s"), _("Office"));
                        ctl->newf.office = optarg;
                        status += check_gecos_string(_("Office"), optarg);
                        break;
                case 'p':
+                       if (!ctl->allow_work)
+                               errx(EXIT_FAILURE, _("login.defs forbids setting %s"), _("Office Phone"));
                        ctl->newf.office_phone = optarg;
                        status += check_gecos_string(_("Office Phone"), optarg);
                        break;
                case 'h':
+                       if (!ctl->allow_home)
+                               errx(EXIT_FAILURE, _("login.defs forbids setting %s"), _("Home Phone"));
                        ctl->newf.home_phone = optarg;
                        status += check_gecos_string(_("Home Phone"), optarg);
                        break;
@@ -238,17 +251,70 @@ static char *ask_new_field(struct chfn_control *ctl, const char *question,
        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 () --
  *     prompt the user for the finger information and store it.
  */
 static void ask_info(struct chfn_control *ctl)
 {
-       ctl->newf.full_name = ask_new_field(ctl, _("Name"), ctl->oldf.full_name);
-       ctl->newf.office = ask_new_field(ctl, _("Office"), ctl->oldf.office);
-       ctl->newf.office_phone = ask_new_field(ctl, _("Office Phone"), ctl->oldf.office_phone);
-       ctl->newf.home_phone = ask_new_field(ctl, _("Home Phone"), ctl->oldf.home_phone);
-       printf("\n");
+       if (ctl->allow_fullname)
+               ctl->newf.full_name = ask_new_field(ctl, _("Name"), ctl->oldf.full_name);
+       if (ctl->allow_room)
+               ctl->newf.office = ask_new_field(ctl, _("Office"), ctl->oldf.office);
+       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);
        uid = getuid();
 
+       /* check /etc/login.defs CHFN_RESTRICT */
+       get_login_defs(&ctl);
+
        parse_argv(&ctl, argc, argv);
        if (!ctl.username) {
                ctl.pw = getpwuid(uid);
@@ -395,8 +464,8 @@ int main(int argc, char **argv)
 
        if (ctl.interactive)
                ask_info(&ctl);
-       else
-               add_missing(&ctl);
+
+       add_missing(&ctl);
 
        if (!ctl.changed) {
                printf(_("Finger information not changed.\n"));