1 /*
2 * pam_rootok module
3 *
4 * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11
5 */
6
7 #include "config.h"
8
9 #include <stdio.h>
10 #include <unistd.h>
11 #include <syslog.h>
12 #include <stdarg.h>
13 #include <string.h>
14
15 #include <security/pam_modules.h>
16 #include <security/pam_ext.h>
17
18 #ifdef WITH_SELINUX
19 #include <selinux/selinux.h>
20 #include <selinux/avc.h>
21 #endif
22
23 #ifdef HAVE_LIBAUDIT
24 #include <libaudit.h>
25 #endif
26
27 /* argument parsing */
28
29 #define PAM_DEBUG_ARG 01
30
31 static int
32 _pam_parse (const pam_handle_t *pamh, int argc, const char **argv)
33 {
34 int ctrl=0;
35
36 /* step through arguments */
37 for (ctrl=0; argc-- > 0; ++argv) {
38
39 /* generic options */
40
41 if (!strcmp(*argv,"debug"))
42 ctrl |= PAM_DEBUG_ARG;
43 else {
44 pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
45 }
46 }
47
48 return ctrl;
49 }
50
51 #ifdef WITH_SELINUX
52 static int
53 PAM_FORMAT((printf, 2, 3))
54 log_callback (int type UNUSED, const char *fmt, ...)
55 {
56 va_list ap;
57
58 #ifdef HAVE_LIBAUDIT
59 int audit_fd = audit_open();
60
61 if (audit_fd >= 0) {
62 char *buf;
63 int ret;
64
65 va_start(ap, fmt);
66 ret = vasprintf (&buf, fmt, ap);
67 va_end(ap);
68 if (ret < 0) {
69 return 0;
70 }
71 audit_log_user_avc_message(audit_fd, AUDIT_USER_AVC, buf, NULL, NULL,
72 NULL, 0);
73 audit_close(audit_fd);
74 free(buf);
75 va_end(ap);
76 return 0;
77 }
78
79 #endif
80 va_start(ap, fmt);
81 vsyslog (LOG_USER | LOG_INFO, fmt, ap);
82 va_end(ap);
83 return 0;
84 }
85
86 static int
87 selinux_check_root (void)
88 {
89 int status = -1;
90 char *user_context_raw;
91 union selinux_callback old_callback;
92
93 if (is_selinux_enabled() < 1)
94 return 0;
95
96 old_callback = selinux_get_callback(SELINUX_CB_LOG);
97 /* setup callbacks */
98 selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) &log_callback);
99 if ((status = getprevcon_raw(&user_context_raw)) < 0) {
100 selinux_set_callback(SELINUX_CB_LOG, old_callback);
101 return status;
102 }
103
104 status = selinux_check_access(user_context_raw, user_context_raw, "passwd", "rootok", NULL);
105
106 selinux_set_callback(SELINUX_CB_LOG, old_callback);
107 freecon(user_context_raw);
108 return status;
109 }
110 #endif
111
112 static int
113 check_for_root (pam_handle_t *pamh, int ctrl)
114 {
115 int retval = PAM_AUTH_ERR;
116
117 if (getuid() == 0)
118 #ifdef WITH_SELINUX
119 if (selinux_check_root() == 0 || security_getenforce() == 0)
120 #endif
121 retval = PAM_SUCCESS;
122
123 if (ctrl & PAM_DEBUG_ARG) {
124 pam_syslog(pamh, LOG_DEBUG, "root check %s",
125 (retval==PAM_SUCCESS) ? "succeeded" : "failed");
126 }
127
128 return retval;
129 }
130
131 /* --- management functions --- */
132
133 int
134 pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED,
135 int argc, const char **argv)
136 {
137 int ctrl;
138
139 ctrl = _pam_parse(pamh, argc, argv);
140
141 return check_for_root (pamh, ctrl);
142 }
143
144 int
145 pam_sm_setcred (pam_handle_t *pamh UNUSED, int flags UNUSED,
146 int argc UNUSED, const char **argv UNUSED)
147 {
148 return PAM_SUCCESS;
149 }
150
151 int
152 pam_sm_acct_mgmt (pam_handle_t *pamh, int flags UNUSED,
153 int argc, const char **argv)
154 {
155 int ctrl;
156
157 ctrl = _pam_parse(pamh, argc, argv);
158
159 return check_for_root (pamh, ctrl);
160 }
161
162 int
163 pam_sm_chauthtok (pam_handle_t *pamh, int flags UNUSED,
164 int argc, const char **argv)
165 {
166 int ctrl;
167
168 ctrl = _pam_parse(pamh, argc, argv);
169
170 return check_for_root (pamh, ctrl);
171 }
172
173 /* end of module definition */