]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
login: extract get_hushlogin_status
authorOndrej Oprala <ooprala@redhat.com>
Tue, 8 Apr 2014 11:26:33 +0000 (13:26 +0200)
committerKarel Zak <kzak@redhat.com>
Thu, 15 May 2014 11:55:59 +0000 (13:55 +0200)
Signed-off-by: Ondrej Oprala <ooprala@redhat.com>
login-utils/login.c
login-utils/logindefs.c
login-utils/logindefs.h

index 89df48955dcc51ef1df6cd322898aa9fa2c00daa..b16a8123156e5a1429c2976af025a3864c71a796 100644 (file)
@@ -920,124 +920,6 @@ static void loginpam_session(struct login_context *cxt)
        }
 }
 
-/*
- * We need to check the effective UID/GID. For example, $HOME could be on a
- * root-squashed NFS or on an NFS with UID mapping, and access(2) uses the
- * real UID/GID.  Then open(2) seems as the surest solution.
- * -- kzak@redhat.com (10-Apr-2009)
- */
-static int effective_access(const char *path, int mode)
-{
-       int fd = open(path, mode);
-       if (fd != -1)
-               close(fd);
-       return fd == -1 ? -1 : 0;
-}
-
-/*
- * Check the per-account or the global hush-login setting.
- *
- * Hushed mode is enabled:
- *
- * a) if a global (e.g. /etc/hushlogins) hush file exists:
- *     1) for ALL ACCOUNTS if the file is empty
- *     2) for the current user if the username or shell is found in the file
- *
- * b) if a ~/.hushlogin file exists
- *
- * The ~/.hushlogin file is ignored if the global hush file exists.
- *
- * The HUSHLOGIN_FILE login.def variable overrides the default hush filename.
- *
- * Note that shadow-utils login(1) does not support "a1)". The "a1)" is
- * necessary if you want to use PAM for "Last login" message.
- *
- * -- Karel Zak <kzak@redhat.com> (26-Aug-2011)
- *
- *
- * The per-account check requires some explanation: As root we may not be able
- * to read the directory of the user if it is on an NFS-mounted filesystem. We
- * temporarily set our effective uid to the user-uid, making sure that we keep
- * root privileges in the real uid.
- *
- * A portable solution would require a fork(), but we rely on Linux having the
- * BSD setreuid().
- */
-static int get_hushlogin_status(struct passwd *pwd)
-{
-       const char *files[] = { _PATH_HUSHLOGINS, _PATH_HUSHLOGIN, NULL };
-       const char *file;
-       char buf[BUFSIZ];
-       int i;
-
-       file = getlogindefs_str("HUSHLOGIN_FILE", NULL);
-       if (file) {
-               if (!*file)
-                       return 0;       /* empty HUSHLOGIN_FILE defined */
-
-               files[0] = file;
-               files[1] = NULL;
-       }
-
-       for (i = 0; files[i]; i++) {
-               int ok = 0;
-
-               file = files[i];
-
-               /* global hush-file */
-               if (*file == '/') {
-                       struct stat st;
-                       FILE *f;
-
-                       if (stat(file, &st) != 0)
-                               continue;       /* file does not exist */
-
-                       if (st.st_size == 0)
-                               return 1;       /* for all accounts */
-
-                       f = fopen(file, "r");
-                       if (!f)
-                               continue;       /* ignore errors... */
-
-                       while (ok == 0 && fgets(buf, sizeof(buf), f)) {
-                               buf[strlen(buf) - 1] = '\0';
-                               ok = !strcmp(buf, *buf == '/' ? pwd->pw_shell :
-                                                               pwd->pw_name);
-                       }
-                       fclose(f);
-                       if (ok)
-                               return 1;       /* found username/shell */
-
-                       return 0;               /* ignore per-account files */
-               }
-
-               /* per-account setting */
-               if (strlen(pwd->pw_dir) + sizeof(file) + 2 > sizeof(buf))
-                       continue;
-               else {
-                       uid_t ruid = getuid();
-                       gid_t egid = getegid();
-
-                       sprintf(buf, "%s/%s", pwd->pw_dir, file);
-
-                       if (setregid(-1, pwd->pw_gid) == 0 &&
-                           setreuid(0, pwd->pw_uid) == 0)
-                               ok = effective_access(buf, O_RDONLY) == 0;
-
-                       if (setuid(0) != 0 ||
-                           setreuid(ruid, 0) != 0 ||
-                           setregid(-1, egid) != 0) {
-                               syslog(LOG_ALERT, _("hush login status: restore original IDs failed"));
-                               exit(EXIT_FAILURE);
-                       }
-                       if (ok)
-                               return 1;       /* enabled by user */
-               }
-       }
-
-       return 0;
-}
-
 /*
  * Detach the controlling terminal, fork, restore syslog stuff, and create
  * a new session.
index 25f743b26f56fc4453419de55f7aef33028aa18e..804ab3e31fb9b05431694dac0de9776150253063 100644 (file)
@@ -27,6 +27,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/syslog.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <pwd.h>
 
 #include "c.h"
 #include "closestream.h"
@@ -259,6 +262,125 @@ int logindefs_setenv(const char *name, const char *conf, const char *dflt)
        return val ? setenv(name, val, 1) : -1;
 }
 
+/*
+ * We need to check the effective UID/GID. For example, $HOME could be on a
+ * root-squashed NFS or on an NFS with UID mapping, and access(2) uses the
+ * real UID/GID.  Then open(2) seems as the surest solution.
+ * -- kzak@redhat.com (10-Apr-2009)
+ */
+int effective_access(const char *path, int mode)
+{
+       int fd = open(path, mode);
+       if (fd != -1)
+               close(fd);
+       return fd == -1 ? -1 : 0;
+}
+
+
+/*
+ * Check the per-account or the global hush-login setting.
+ *
+ * Hushed mode is enabled:
+ *
+ * a) if a global (e.g. /etc/hushlogins) hush file exists:
+ *     1) for ALL ACCOUNTS if the file is empty
+ *     2) for the current user if the username or shell is found in the file
+ *
+ * b) if a ~/.hushlogin file exists
+ *
+ * The ~/.hushlogin file is ignored if the global hush file exists.
+ *
+ * The HUSHLOGIN_FILE login.def variable overrides the default hush filename.
+ *
+ * Note that shadow-utils login(1) does not support "a1)". The "a1)" is
+ * necessary if you want to use PAM for "Last login" message.
+ *
+ * -- Karel Zak <kzak@redhat.com> (26-Aug-2011)
+ *
+ *
+ * The per-account check requires some explanation: As root we may not be able
+ * to read the directory of the user if it is on an NFS-mounted filesystem. We
+ * temporarily set our effective uid to the user-uid, making sure that we keep
+ * root privileges in the real uid.
+ *
+ * A portable solution would require a fork(), but we rely on Linux having the
+ * BSD setreuid().
+ */
+
+int get_hushlogin_status(struct passwd *pwd)
+{
+       const char *files[] = { _PATH_HUSHLOGINS, _PATH_HUSHLOGIN, NULL };
+       const char *file;
+       char buf[BUFSIZ];
+       int i;
+
+       file = getlogindefs_str("HUSHLOGIN_FILE", NULL);
+       if (file) {
+               if (!*file)
+                       return 0;       /* empty HUSHLOGIN_FILE defined */
+
+               files[0] = file;
+               files[1] = NULL;
+       }
+
+       for (i = 0; files[i]; i++) {
+               int ok = 0;
+
+               file = files[i];
+
+               /* global hush-file */
+               if (*file == '/') {
+                       struct stat st;
+                       FILE *f;
+
+                       if (stat(file, &st) != 0)
+                               continue;       /* file does not exist */
+
+                       if (st.st_size == 0)
+                               return 1;       /* for all accounts */
+
+                       f = fopen(file, "r");
+                       if (!f)
+                               continue;       /* ignore errors... */
+
+                       while (ok == 0 && fgets(buf, sizeof(buf), f)) {
+                               buf[strlen(buf) - 1] = '\0';
+                               ok = !strcmp(buf, *buf == '/' ? pwd->pw_shell :
+                                                               pwd->pw_name);
+                       }
+                       fclose(f);
+                       if (ok)
+                               return 1;       /* found username/shell */
+
+                       return 0;               /* ignore per-account files */
+               }
+
+               /* per-account setting */
+               if (strlen(pwd->pw_dir) + sizeof(file) + 2 > sizeof(buf))
+                       continue;
+               else {
+                       uid_t ruid = getuid();
+                       gid_t egid = getegid();
+
+                       sprintf(buf, "%s/%s", pwd->pw_dir, file);
+
+                       if (setregid(-1, pwd->pw_gid) == 0 &&
+                           setreuid(0, pwd->pw_uid) == 0)
+                               ok = effective_access(buf, O_RDONLY) == 0;
+
+                       if (setuid(0) != 0 ||
+                           setreuid(ruid, 0) != 0 ||
+                           setregid(-1, egid) != 0) {
+                               syslog(LOG_ALERT, _("hush login status: restore original IDs failed"));
+                               exit(EXIT_FAILURE);
+                       }
+                       if (ok)
+                               return 1;       /* enabled by user */
+               }
+       }
+
+       return 0;
+}
 #ifdef TEST_PROGRAM
 int main(int argc, char *argv[])
 {
index c5ccbc91bdc2e687e250603f5869766c0eb7b570..6a72762f4e62c45d8b9192ddc1f9626b0dff3411 100644 (file)
@@ -8,5 +8,7 @@ extern unsigned long getlogindefs_num(const char *name, long dflt);
 extern const char *getlogindefs_str(const char *name, const char *dflt);
 extern void free_getlogindefs_data(void);
 extern int logindefs_setenv(const char *name, const char *conf, const char *dflt);
+extern int effective_access(const char *path, int mode);
+extern int get_hushlogin_status(struct passwd *pwd);
 
 #endif /* UTIL_LINUX_LOGINDEFS_H */