No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / lib / auth / pam / pam.c
blobcc80324639e911d505ef934d750bda7eeb74c92a
1 /*
2 * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #ifdef HAVE_CONFIG_H
35 #include<config.h>
36 __RCSID("$Heimdal: pam.c 11417 2002-09-09 15:57:24Z joda $"
37 "$NetBSD$");
38 #endif
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <pwd.h>
44 #include <unistd.h>
45 #include <sys/types.h>
46 #include <syslog.h>
48 #include <security/pam_appl.h>
49 #include <security/pam_modules.h>
50 #ifndef PAM_AUTHTOK_RECOVERY_ERR /* Fix linsux typo. */
51 #define PAM_AUTHTOK_RECOVERY_ERR PAM_AUTHTOK_RECOVER_ERR
52 #endif
54 #include <netinet/in.h>
55 #include <krb.h>
56 #include <kafs.h>
58 #if 0
59 /* Debugging PAM modules is a royal pain, truss helps. */
60 #define DEBUG(msg) (access(msg " at line", __LINE__))
61 #endif
63 static void
64 psyslog(int level, const char *format, ...)
66 va_list args;
67 va_start(args, format);
68 openlog("pam_krb4", LOG_PID, LOG_AUTH);
69 vsyslog(level, format, args);
70 va_end(args);
71 closelog();
74 enum {
75 KRB4_DEBUG,
76 KRB4_USE_FIRST_PASS,
77 KRB4_TRY_FIRST_PASS,
78 KRB4_IGNORE_ROOT,
79 KRB4_NO_VERIFY,
80 KRB4_REAFSLOG,
81 KRB4_CTRLS /* Number of ctrl arguments defined. */
84 #define KRB4_DEFAULTS 0
86 static int ctrl_flags = KRB4_DEFAULTS;
87 #define ctrl_on(x) (krb4_args[x].flag & ctrl_flags)
88 #define ctrl_off(x) (!ctrl_on(x))
90 typedef struct
92 const char *token;
93 unsigned int flag;
94 } krb4_ctrls_t;
96 static krb4_ctrls_t krb4_args[KRB4_CTRLS] =
98 /* KRB4_DEBUG */ { "debug", 0x01 },
99 /* KRB4_USE_FIRST_PASS */ { "use_first_pass", 0x02 },
100 /* KRB4_TRY_FIRST_PASS */ { "try_first_pass", 0x04 },
101 /* KRB4_IGNORE_ROOT */ { "ignore_root", 0x08 },
102 /* KRB4_NO_VERIFY */ { "no_verify", 0x10 },
103 /* KRB4_REAFSLOG */ { "reafslog", 0x20 },
106 static void
107 parse_ctrl(int argc, const char **argv)
109 int i, j;
111 ctrl_flags = KRB4_DEFAULTS;
112 for (i = 0; i < argc; i++)
114 for (j = 0; j < KRB4_CTRLS; j++)
115 if (strcmp(argv[i], krb4_args[j].token) == 0)
116 break;
118 if (j >= KRB4_CTRLS)
119 psyslog(LOG_ALERT, "unrecognized option [%s]", *argv);
120 else
121 ctrl_flags |= krb4_args[j].flag;
125 static void
126 pdeb(const char *format, ...)
128 va_list args;
129 if (ctrl_off(KRB4_DEBUG))
130 return;
131 va_start(args, format);
132 openlog("pam_krb4", LOG_PID, LOG_AUTH);
133 vsyslog(LOG_DEBUG, format, args);
134 va_end(args);
135 closelog();
138 #define ENTRY(func) pdeb("%s() flags = %d ruid = %d euid = %d", func, flags, getuid(), geteuid())
140 static void
141 set_tkt_string(uid_t uid)
143 char buf[128];
145 snprintf(buf, sizeof(buf), "%s%u", TKT_ROOT, (unsigned)uid);
146 krb_set_tkt_string(buf);
148 #if 0
149 /* pam_set_data+pam_get_data are not guaranteed to work, grr. */
150 pam_set_data(pamh, "KRBTKFILE", strdup(t), cleanup);
151 if (pam_get_data(pamh, "KRBTKFILE", (const void**)&tkt) == PAM_SUCCESS)
153 pam_putenv(pamh, var);
155 #endif
157 /* We don't want to inherit this variable.
158 * If we still do, it must have a sane value. */
159 if (getenv("KRBTKFILE") != 0)
161 char *var = malloc(sizeof(buf));
162 snprintf(var, sizeof(buf), "KRBTKFILE=%s", tkt_string());
163 putenv(var);
164 /* free(var); XXX */
168 static int
169 verify_pass(pam_handle_t *pamh,
170 const char *name,
171 const char *inst,
172 const char *pass)
174 char realm[REALM_SZ];
175 int ret, krb_verify, old_euid, old_ruid;
177 krb_get_lrealm(realm, 1);
178 if (ctrl_on(KRB4_NO_VERIFY))
179 krb_verify = KRB_VERIFY_SECURE_FAIL;
180 else
181 krb_verify = KRB_VERIFY_SECURE;
182 old_ruid = getuid();
183 old_euid = geteuid();
184 setreuid(0, 0);
185 ret = krb_verify_user(name, inst, realm, pass, krb_verify, NULL);
186 pdeb("krb_verify_user(`%s', `%s', `%s', pw, %d, NULL) returns %s",
187 name, inst, realm, krb_verify,
188 krb_get_err_text(ret));
189 setreuid(old_ruid, old_euid);
190 if (getuid() != old_ruid || geteuid() != old_euid)
192 psyslog(LOG_ALERT , "setreuid(%d, %d) failed at line %d",
193 old_ruid, old_euid, __LINE__);
194 exit(1);
197 switch(ret) {
198 case KSUCCESS:
199 return PAM_SUCCESS;
200 case KDC_PR_UNKNOWN:
201 return PAM_USER_UNKNOWN;
202 case SKDC_CANT:
203 case SKDC_RETRY:
204 case RD_AP_TIME:
205 return PAM_AUTHINFO_UNAVAIL;
206 default:
207 return PAM_AUTH_ERR;
211 static int
212 krb4_auth(pam_handle_t *pamh,
213 int flags,
214 const char *name,
215 const char *inst,
216 struct pam_conv *conv)
218 struct pam_response *resp;
219 char prompt[128];
220 struct pam_message msg, *pmsg = &msg;
221 int ret;
223 if (ctrl_on(KRB4_TRY_FIRST_PASS) || ctrl_on(KRB4_USE_FIRST_PASS))
225 char *pass = 0;
226 ret = pam_get_item(pamh, PAM_AUTHTOK, (void **) &pass);
227 if (ret != PAM_SUCCESS)
229 psyslog(LOG_ERR , "pam_get_item returned error to get-password");
230 return ret;
232 else if (pass != 0 && verify_pass(pamh, name, inst, pass) == PAM_SUCCESS)
233 return PAM_SUCCESS;
234 else if (ctrl_on(KRB4_USE_FIRST_PASS))
235 return PAM_AUTHTOK_RECOVERY_ERR; /* Wrong password! */
236 else
237 /* We tried the first password but it didn't work, cont. */;
240 msg.msg_style = PAM_PROMPT_ECHO_OFF;
241 if (*inst == 0)
242 snprintf(prompt, sizeof(prompt), "%s's Password: ", name);
243 else
244 snprintf(prompt, sizeof(prompt), "%s.%s's Password: ", name, inst);
245 msg.msg = prompt;
247 ret = conv->conv(1, &pmsg, &resp, conv->appdata_ptr);
248 if (ret != PAM_SUCCESS)
249 return ret;
251 ret = verify_pass(pamh, name, inst, resp->resp);
252 if (ret == PAM_SUCCESS)
254 memset(resp->resp, 0, strlen(resp->resp)); /* Erase password! */
255 free(resp->resp);
256 free(resp);
258 else
260 pam_set_item(pamh, PAM_AUTHTOK, resp->resp); /* Save password. */
261 /* free(resp->resp); XXX */
262 /* free(resp); XXX */
265 return ret;
269 pam_sm_authenticate(pam_handle_t *pamh,
270 int flags,
271 int argc,
272 const char **argv)
274 char *user;
275 int ret;
276 struct pam_conv *conv;
277 struct passwd *pw;
278 uid_t uid = -1;
279 const char *name, *inst;
280 char realm[REALM_SZ];
281 realm[0] = 0;
283 parse_ctrl(argc, argv);
284 ENTRY("pam_sm_authenticate");
286 ret = pam_get_user(pamh, &user, "login: ");
287 if (ret != PAM_SUCCESS)
288 return ret;
290 if (ctrl_on(KRB4_IGNORE_ROOT) && strcmp(user, "root") == 0)
291 return PAM_AUTHINFO_UNAVAIL;
293 ret = pam_get_item(pamh, PAM_CONV, (void*)&conv);
294 if (ret != PAM_SUCCESS)
295 return ret;
297 pw = getpwnam(user);
298 if (pw != 0)
300 uid = pw->pw_uid;
301 set_tkt_string(uid);
304 if (strcmp(user, "root") == 0 && getuid() != 0)
306 pw = getpwuid(getuid());
307 if (pw != 0)
309 name = strdup(pw->pw_name);
310 inst = "root";
313 else
315 name = user;
316 inst = "";
319 ret = krb4_auth(pamh, flags, name, inst, conv);
322 * The realm was lost inside krb_verify_user() so we can't simply do
323 * a krb_kuserok() when inst != "".
325 if (ret == PAM_SUCCESS && inst[0] != 0)
327 uid_t old_euid = geteuid();
328 uid_t old_ruid = getuid();
330 setreuid(0, 0); /* To read ticket file. */
331 if (krb_get_tf_fullname(tkt_string(), 0, 0, realm) != KSUCCESS)
332 ret = PAM_SERVICE_ERR;
333 else if (krb_kuserok(name, inst, realm, user) != KSUCCESS)
335 setreuid(0, uid); /* To read ~/.klogin. */
336 if (krb_kuserok(name, inst, realm, user) != KSUCCESS)
337 ret = PAM_PERM_DENIED;
340 if (ret != PAM_SUCCESS)
342 dest_tkt(); /* Passwd known, ok to kill ticket. */
343 psyslog(LOG_NOTICE,
344 "%s.%s@%s is not allowed to log in as %s",
345 name, inst, realm, user);
348 setreuid(old_ruid, old_euid);
349 if (getuid() != old_ruid || geteuid() != old_euid)
351 psyslog(LOG_ALERT , "setreuid(%d, %d) failed at line %d",
352 old_ruid, old_euid, __LINE__);
353 exit(1);
357 if (ret == PAM_SUCCESS)
359 psyslog(LOG_INFO,
360 "%s.%s@%s authenticated as user %s",
361 name, inst, realm, user);
362 if (chown(tkt_string(), uid, -1) == -1)
364 dest_tkt();
365 psyslog(LOG_ALERT , "chown(%s, %d, -1) failed", tkt_string(), uid);
366 exit(1);
371 * Kludge alert!!! Sun dtlogin unlock screen fails to call
372 * pam_setcred(3) with PAM_REFRESH_CRED after a successful
373 * authentication attempt, sic.
375 * This hack is designed as a workaround to that problem.
377 if (ctrl_on(KRB4_REAFSLOG))
378 if (ret == PAM_SUCCESS)
379 pam_sm_setcred(pamh, PAM_REFRESH_CRED, argc, argv);
381 return ret;
384 int
385 pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
387 parse_ctrl(argc, argv);
388 ENTRY("pam_sm_setcred");
390 switch (flags & ~PAM_SILENT) {
391 case 0:
392 case PAM_ESTABLISH_CRED:
393 if (k_hasafs())
394 k_setpag();
395 /* Fall through, fill PAG with credentials below. */
396 case PAM_REINITIALIZE_CRED:
397 case PAM_REFRESH_CRED:
398 if (k_hasafs())
400 void *user = 0;
402 if (pam_get_item(pamh, PAM_USER, &user) == PAM_SUCCESS)
404 struct passwd *pw = getpwnam((char *)user);
405 if (pw != 0)
406 krb_afslog_uid_home(/*cell*/ 0,/*realm_hint*/ 0,
407 pw->pw_uid, pw->pw_dir);
410 break;
411 case PAM_DELETE_CRED:
412 dest_tkt();
413 if (k_hasafs())
414 k_unlog();
415 break;
416 default:
417 psyslog(LOG_ALERT , "pam_sm_setcred: unknown flags 0x%x", flags);
418 break;
421 return PAM_SUCCESS;
425 pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
427 parse_ctrl(argc, argv);
428 ENTRY("pam_sm_open_session");
430 return PAM_SUCCESS;
435 pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char**argv)
437 parse_ctrl(argc, argv);
438 ENTRY("pam_sm_close_session");
440 /* This isn't really kosher, but it's handy. */
441 pam_sm_setcred(pamh, PAM_DELETE_CRED, argc, argv);
443 return PAM_SUCCESS;