summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOndrej Oprala2014-04-08 13:26:33 +0200
committerKarel Zak2014-05-15 13:55:59 +0200
commit78dd74508931a2990a20f973854e0749505fdea0 (patch)
tree19421097ccabbb7f14649764cfcdab552ac77677
parentlslogins: move to login-utils (diff)
downloadkernel-qcow2-util-linux-78dd74508931a2990a20f973854e0749505fdea0.tar.gz
kernel-qcow2-util-linux-78dd74508931a2990a20f973854e0749505fdea0.tar.xz
kernel-qcow2-util-linux-78dd74508931a2990a20f973854e0749505fdea0.zip
login: extract get_hushlogin_status
Signed-off-by: Ondrej Oprala <ooprala@redhat.com>
-rw-r--r--login-utils/login.c118
-rw-r--r--login-utils/logindefs.c122
-rw-r--r--login-utils/logindefs.h2
3 files changed, 124 insertions, 118 deletions
diff --git a/login-utils/login.c b/login-utils/login.c
index 89df48955..b16a81231 100644
--- a/login-utils/login.c
+++ b/login-utils/login.c
@@ -921,124 +921,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.
*/
diff --git a/login-utils/logindefs.c b/login-utils/logindefs.c
index 25f743b26..804ab3e31 100644
--- a/login-utils/logindefs.c
+++ b/login-utils/logindefs.c
@@ -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[])
{
diff --git a/login-utils/logindefs.h b/login-utils/logindefs.h
index c5ccbc91b..6a72762f4 100644
--- a/login-utils/logindefs.h
+++ b/login-utils/logindefs.h
@@ -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 */