2 * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
44 #include <sys/types.h>
47 #include <security/pam_appl.h>
48 #include <security/pam_modules.h>
49 #ifndef PAM_AUTHTOK_RECOVERY_ERR /* Fix linsux typo. */
50 #define PAM_AUTHTOK_RECOVERY_ERR PAM_AUTHTOK_RECOVER_ERR
53 #include <netinet/in.h>
58 /* Debugging PAM modules is a royal pain, truss helps. */
59 #define DEBUG(msg) (access(msg " at line", __LINE__))
63 psyslog(int level
, const char *format
, ...)
66 va_start(args
, format
);
67 openlog("pam_krb4", LOG_PID
, LOG_AUTH
);
68 vsyslog(level
, format
, args
);
80 KRB4_CTRLS
/* Number of ctrl arguments defined. */
83 #define KRB4_DEFAULTS 0
85 static int ctrl_flags
= KRB4_DEFAULTS
;
86 #define ctrl_on(x) (krb4_args[x].flag & ctrl_flags)
87 #define ctrl_off(x) (!ctrl_on(x))
95 static krb4_ctrls_t krb4_args
[KRB4_CTRLS
] =
97 /* KRB4_DEBUG */ { "debug", 0x01 },
98 /* KRB4_USE_FIRST_PASS */ { "use_first_pass", 0x02 },
99 /* KRB4_TRY_FIRST_PASS */ { "try_first_pass", 0x04 },
100 /* KRB4_IGNORE_ROOT */ { "ignore_root", 0x08 },
101 /* KRB4_NO_VERIFY */ { "no_verify", 0x10 },
102 /* KRB4_REAFSLOG */ { "reafslog", 0x20 },
106 parse_ctrl(int argc
, const char **argv
)
110 ctrl_flags
= KRB4_DEFAULTS
;
111 for (i
= 0; i
< argc
; i
++)
113 for (j
= 0; j
< KRB4_CTRLS
; j
++)
114 if (strcmp(argv
[i
], krb4_args
[j
].token
) == 0)
118 psyslog(LOG_ALERT
, "unrecognized option [%s]", *argv
);
120 ctrl_flags
|= krb4_args
[j
].flag
;
125 pdeb(const char *format
, ...)
128 if (ctrl_off(KRB4_DEBUG
))
130 va_start(args
, format
);
131 openlog("pam_krb4", LOG_PID
, LOG_AUTH
);
132 vsyslog(LOG_DEBUG
, format
, args
);
137 #define ENTRY(func) pdeb("%s() flags = %d ruid = %d euid = %d", func, flags, getuid(), geteuid())
140 set_tkt_string(uid_t uid
)
144 snprintf(buf
, sizeof(buf
), "%s%u", TKT_ROOT
, (unsigned)uid
);
145 krb_set_tkt_string(buf
);
148 /* pam_set_data+pam_get_data are not guaranteed to work, grr. */
149 pam_set_data(pamh
, "KRBTKFILE", strdup(t
), cleanup
);
150 if (pam_get_data(pamh
, "KRBTKFILE", (const void**)&tkt
) == PAM_SUCCESS
)
152 pam_putenv(pamh
, var
);
156 /* We don't want to inherit this variable.
157 * If we still do, it must have a sane value. */
158 if (getenv("KRBTKFILE") != 0)
160 char *var
= malloc(sizeof(buf
));
161 snprintf(var
, sizeof(buf
), "KRBTKFILE=%s", tkt_string());
168 verify_pass(pam_handle_t
*pamh
,
173 char realm
[REALM_SZ
];
174 int ret
, krb_verify
, old_euid
, old_ruid
;
176 krb_get_lrealm(realm
, 1);
177 if (ctrl_on(KRB4_NO_VERIFY
))
178 krb_verify
= KRB_VERIFY_SECURE_FAIL
;
180 krb_verify
= KRB_VERIFY_SECURE
;
182 old_euid
= geteuid();
184 ret
= krb_verify_user(name
, inst
, realm
, pass
, krb_verify
, NULL
);
185 pdeb("krb_verify_user(`%s', `%s', `%s', pw, %d, NULL) returns %s",
186 name
, inst
, realm
, krb_verify
,
187 krb_get_err_text(ret
));
188 setreuid(old_ruid
, old_euid
);
189 if (getuid() != old_ruid
|| geteuid() != old_euid
)
191 psyslog(LOG_ALERT
, "setreuid(%d, %d) failed at line %d",
192 old_ruid
, old_euid
, __LINE__
);
200 return PAM_USER_UNKNOWN
;
204 return PAM_AUTHINFO_UNAVAIL
;
211 krb4_auth(pam_handle_t
*pamh
,
215 struct pam_conv
*conv
)
217 struct pam_response
*resp
;
219 struct pam_message msg
, *pmsg
= &msg
;
222 if (ctrl_on(KRB4_TRY_FIRST_PASS
) || ctrl_on(KRB4_USE_FIRST_PASS
))
225 ret
= pam_get_item(pamh
, PAM_AUTHTOK
, (void **) &pass
);
226 if (ret
!= PAM_SUCCESS
)
228 psyslog(LOG_ERR
, "pam_get_item returned error to get-password");
231 else if (pass
!= 0 && verify_pass(pamh
, name
, inst
, pass
) == PAM_SUCCESS
)
233 else if (ctrl_on(KRB4_USE_FIRST_PASS
))
234 return PAM_AUTHTOK_RECOVERY_ERR
; /* Wrong password! */
236 /* We tried the first password but it didn't work, cont. */;
239 msg
.msg_style
= PAM_PROMPT_ECHO_OFF
;
241 snprintf(prompt
, sizeof(prompt
), "%s's Password: ", name
);
243 snprintf(prompt
, sizeof(prompt
), "%s.%s's Password: ", name
, inst
);
246 ret
= conv
->conv(1, &pmsg
, &resp
, conv
->appdata_ptr
);
247 if (ret
!= PAM_SUCCESS
)
250 ret
= verify_pass(pamh
, name
, inst
, resp
->resp
);
251 if (ret
== PAM_SUCCESS
)
253 memset(resp
->resp
, 0, strlen(resp
->resp
)); /* Erase password! */
259 pam_set_item(pamh
, PAM_AUTHTOK
, resp
->resp
); /* Save password. */
260 /* free(resp->resp); XXX */
261 /* free(resp); XXX */
268 pam_sm_authenticate(pam_handle_t
*pamh
,
275 struct pam_conv
*conv
;
278 const char *name
, *inst
;
279 char realm
[REALM_SZ
];
282 parse_ctrl(argc
, argv
);
283 ENTRY("pam_sm_authenticate");
285 ret
= pam_get_user(pamh
, &user
, "login: ");
286 if (ret
!= PAM_SUCCESS
)
289 if (ctrl_on(KRB4_IGNORE_ROOT
) && strcmp(user
, "root") == 0)
290 return PAM_AUTHINFO_UNAVAIL
;
292 ret
= pam_get_item(pamh
, PAM_CONV
, (void*)&conv
);
293 if (ret
!= PAM_SUCCESS
)
303 if (strcmp(user
, "root") == 0 && getuid() != 0)
305 pw
= getpwuid(getuid());
308 name
= strdup(pw
->pw_name
);
318 ret
= krb4_auth(pamh
, flags
, name
, inst
, conv
);
321 * The realm was lost inside krb_verify_user() so we can't simply do
322 * a krb_kuserok() when inst != "".
324 if (ret
== PAM_SUCCESS
&& inst
[0] != 0)
326 uid_t old_euid
= geteuid();
327 uid_t old_ruid
= getuid();
329 setreuid(0, 0); /* To read ticket file. */
330 if (krb_get_tf_fullname(tkt_string(), 0, 0, realm
) != KSUCCESS
)
331 ret
= PAM_SERVICE_ERR
;
332 else if (krb_kuserok(name
, inst
, realm
, user
) != KSUCCESS
)
334 setreuid(0, uid
); /* To read ~/.klogin. */
335 if (krb_kuserok(name
, inst
, realm
, user
) != KSUCCESS
)
336 ret
= PAM_PERM_DENIED
;
339 if (ret
!= PAM_SUCCESS
)
341 dest_tkt(); /* Passwd known, ok to kill ticket. */
343 "%s.%s@%s is not allowed to log in as %s",
344 name
, inst
, realm
, user
);
347 setreuid(old_ruid
, old_euid
);
348 if (getuid() != old_ruid
|| geteuid() != old_euid
)
350 psyslog(LOG_ALERT
, "setreuid(%d, %d) failed at line %d",
351 old_ruid
, old_euid
, __LINE__
);
356 if (ret
== PAM_SUCCESS
)
359 "%s.%s@%s authenticated as user %s",
360 name
, inst
, realm
, user
);
361 if (chown(tkt_string(), uid
, -1) == -1)
364 psyslog(LOG_ALERT
, "chown(%s, %d, -1) failed", tkt_string(), uid
);
370 * Kludge alert!!! Sun dtlogin unlock screen fails to call
371 * pam_setcred(3) with PAM_REFRESH_CRED after a successful
372 * authentication attempt, sic.
374 * This hack is designed as a workaround to that problem.
376 if (ctrl_on(KRB4_REAFSLOG
))
377 if (ret
== PAM_SUCCESS
)
378 pam_sm_setcred(pamh
, PAM_REFRESH_CRED
, argc
, argv
);
384 pam_sm_setcred(pam_handle_t
*pamh
, int flags
, int argc
, const char **argv
)
386 parse_ctrl(argc
, argv
);
387 ENTRY("pam_sm_setcred");
389 switch (flags
& ~PAM_SILENT
) {
391 case PAM_ESTABLISH_CRED
:
394 /* Fall through, fill PAG with credentials below. */
395 case PAM_REINITIALIZE_CRED
:
396 case PAM_REFRESH_CRED
:
401 if (pam_get_item(pamh
, PAM_USER
, &user
) == PAM_SUCCESS
)
403 struct passwd
*pw
= getpwnam((char *)user
);
405 krb_afslog_uid_home(/*cell*/ 0,/*realm_hint*/ 0,
406 pw
->pw_uid
, pw
->pw_dir
);
410 case PAM_DELETE_CRED
:
416 psyslog(LOG_ALERT
, "pam_sm_setcred: unknown flags 0x%x", flags
);
424 pam_sm_open_session(pam_handle_t
*pamh
, int flags
, int argc
, const char **argv
)
426 parse_ctrl(argc
, argv
);
427 ENTRY("pam_sm_open_session");
434 pam_sm_close_session(pam_handle_t
*pamh
, int flags
, int argc
, const char**argv
)
436 parse_ctrl(argc
, argv
);
437 ENTRY("pam_sm_close_session");
439 /* This isn't really kosher, but it's handy. */
440 pam_sm_setcred(pamh
, PAM_DELETE_CRED
, argc
, argv
);