diff options
-rw-r--r-- | lib/libpam/modules/modules.inc | 1 | ||||
-rw-r--r-- | lib/libpam/modules/pam_ksu/Makefile | 42 | ||||
-rw-r--r-- | lib/libpam/modules/pam_ksu/pam_ksu.8 | 113 | ||||
-rw-r--r-- | lib/libpam/modules/pam_ksu/pam_ksu.c | 256 |
4 files changed, 412 insertions, 0 deletions
diff --git a/lib/libpam/modules/modules.inc b/lib/libpam/modules/modules.inc index 13cc28d..029cc85 100644 --- a/lib/libpam/modules/modules.inc +++ b/lib/libpam/modules/modules.inc @@ -11,6 +11,7 @@ MODULES += pam_kerberosIV .endif .if defined(MAKE_KERBEROS5) && !defined(NOCRYPT) && !defined(NO_OPENSSL) MODULES += pam_krb5 +MODULES += pam_ksu .endif MODULES += pam_lastlog MODULES += pam_login_access diff --git a/lib/libpam/modules/pam_ksu/Makefile b/lib/libpam/modules/pam_ksu/Makefile new file mode 100644 index 0000000..e86a158 --- /dev/null +++ b/lib/libpam/modules/pam_ksu/Makefile @@ -0,0 +1,42 @@ +# Copyright 2002 FreeBSD, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ + +PAMDIR= ${.CURDIR}/../../../../contrib/libpam + +LIB= pam_ksu +SRCS= pam_ksu.c +CFLAGS+= -Wall +CFLAGS+= -I${PAMDIR}/libpam/include +CFLAGS+= -I${.CURDIR}/../../libpam +DPADD= ${LIBKRB5} ${LIBASN1} ${LIBCRYPTO} ${LIBCRYPT} \ + ${LIBCOM_ERR} ${LIBROKEN} +LDADD= -lkrb5 -lasn1 -lcrypto -lcrypt -lcom_err \ + -L${.OBJDIR}/../../../../kerberos5/lib/libroken -lroken +MAN= pam_ksu.8 +#INTERNALLIB= yes +#INTERNALSTATICLIB=yes + +.include <bsd.lib.mk> diff --git a/lib/libpam/modules/pam_ksu/pam_ksu.8 b/lib/libpam/modules/pam_ksu/pam_ksu.8 new file mode 100644 index 0000000..2923ce0 --- /dev/null +++ b/lib/libpam/modules/pam_ksu/pam_ksu.8 @@ -0,0 +1,113 @@ +.\" Copyright (c) 2001 Mark R V Murray +.\" All rights reserved. +.\" Copyright (c) 2001 Networks Associates Technology, Inc. +.\" All rights reserved. +.\" +.\" This software was developed for the FreeBSD Project by ThinkSec AS and +.\" NAI Labs, the Security Research Division of Network Associates, Inc. +.\" under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the +.\" DARPA CHATS research program. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the author may not be used to endorse or promote +.\" products derived from this software without specific prior written +.\" permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd May 15, 2002 +.Dt pam_ksu 8 +.Os +.Sh NAME +.Nm pam_ksu +.Nd Kerberos 5 SU PAM module +.Sh SYNOPSIS +.Op Ar service-name +.Ar module-type +.Ar control-flag +.Pa pam_ksu +.Op Ar options +.Sh DESCRIPTION +The Kerberos 5 SU authentication service module for PAM, +.Nm +for only one PAM category: authentication. +In terms of the +.Ar module-type +parameter, this is the +.Dq Li auth +feature. +The module is specifically designed to be used with the +.Xr su 1 +utility. +.\" It also provides a null function for session management. +.Ss Kerberos 5 SU Authentication Module +The Kerberos 5 SU authentication component provides functions to verify +the identity of a user +.Pq Fn pam_sm_authenticate , +and determine whether or not the user is authorized to obtain the +privileges of the target account. +If the target account is `root', then the Kerberos 5 principal used +for authentication and authorization will be the `root' instance of +the current user, e.g. `user/root@REAL.M'. +Otherwise, the principal will simply be the current user's default +principal, e.g. `user@REAL.M'. +.Pp +The user is prompted for a password if necessary. Authorization is performed +by comparing the Kerberos 5 principal with those listed in the +.Pa .k5login +file in the target account's home directory +.Pq e.g. /root/.k5login for root . +.Pp +The following options may be passed to the authentication module: +.Bl -tag -width ".Cm use_first_pass" +.It Cm debug +.Xr syslog 3 +debugging information at +.Dv LOG_DEBUG +level. +.It Cm use_first_pass +If the authentication module +is not the first in the stack, +and a previous module +obtained the user's password, +that password is used +to authenticate the user. +If this fails, +the authentication module returns failure +without prompting the user for a password. +This option has no effect +if the authentication module +is the first in the stack, +or if no previous modules +obtained the user's password. +.It Cm try_first_pass +This option is similar to the +.Cm use_first_pass +option, +except that if the previously obtained password fails, +the user is prompted for another password. +.El +.Sh SEE ALSO +.Xr su 1 , +.Xr syslog 3 , +.Xr pam.conf 5 , +.Xr pam 8 diff --git a/lib/libpam/modules/pam_ksu/pam_ksu.c b/lib/libpam/modules/pam_ksu/pam_ksu.c new file mode 100644 index 0000000..d50d43f --- /dev/null +++ b/lib/libpam/modules/pam_ksu/pam_ksu.c @@ -0,0 +1,256 @@ +/*- + * Copyright (c) 2002 Jacques A. Vidrine <nectar@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <krb5.h> + +#define PAM_SM_AUTH +#define PAM_SM_CRED +#include <security/pam_appl.h> +#include <security/pam_modules.h> +#include <security/pam_mod_misc.h> + +static const char superuser[] = "root"; + +static long get_su_principal(krb5_context, const char *, const char *, + char **, krb5_principal *); +static int auth_krb5(pam_handle_t *, krb5_context, const char *, + krb5_principal); + +PAM_EXTERN int +pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, + int argc __unused, const char *argv[] __unused) +{ + krb5_context context; + krb5_principal su_principal; + const char *user, *ruser; + char *su_principal_name; + long rv; + int pamret; + + pamret = pam_get_user(pamh, &user, NULL); + if (pamret != PAM_SUCCESS) + return (pamret); + PAM_LOG("Got user: %s", user); + pamret = pam_get_item(pamh, PAM_RUSER, (const void **)&ruser); + if (pamret != PAM_SUCCESS) + return (pamret); + PAM_LOG("Got ruser: %s", ruser); + rv = krb5_init_context(&context); + if (rv != 0) { + PAM_LOG("krb5_init_context failed: %s", + krb5_get_err_text(context, rv)); + return (PAM_SERVICE_ERR); + } + rv = get_su_principal(context, user, ruser, &su_principal_name, &su_principal); + if (rv != 0) + return (PAM_AUTH_ERR); + PAM_LOG("kuserok: %s -> %s", su_principal_name, user); + rv = krb5_kuserok(context, su_principal, user); + pamret = rv ? auth_krb5(pamh, context, su_principal_name, su_principal) : PAM_AUTH_ERR; + free(su_principal_name); + krb5_free_principal(context, su_principal); + krb5_free_context(context); + return (pamret); +} + +PAM_EXTERN int +pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused, + int ac __unused, const char *av[] __unused) +{ + + return (PAM_SUCCESS); +} + +/* Authenticate using Kerberos 5. + * pamh -- The PAM handle. + * context -- An initialized krb5_context. + * su_principal_name -- The target principal name, used only for password prompts. + * If NULL, the password prompts will not include a principal + * name. + * su_principal -- The target krb5_principal. + * Note that a valid keytab in the default location with a host entry + * must be available, and that the PAM application must have sufficient + * privileges to access it. + * Returns PAM_SUCCESS if authentication was successful, or an appropriate + * PAM error code if it was not. + */ +static int +auth_krb5(pam_handle_t *pamh, krb5_context context, const char *su_principal_name, + krb5_principal su_principal) +{ + krb5_creds creds; + krb5_get_init_creds_opt gic_opt; + krb5_verify_init_creds_opt vic_opt; + const char *pass; + char *prompt; + long rv; + int pamret; + + prompt = NULL; + krb5_get_init_creds_opt_init(&gic_opt); + krb5_verify_init_creds_opt_init(&vic_opt); + if (su_principal_name != NULL) + (void)asprintf(&prompt, "Password for %s:", su_principal_name); + else + (void)asprintf(&prompt, "Password:"); + if (prompt == NULL) + return (PAM_BUF_ERR); + pass = NULL; + (void)pam_get_item(pamh, PAM_AUTHTOK, (const void **)&pass); + free(prompt); + if (pass == NULL) { + pamret = pam_get_authtok(pamh, PAM_AUTHTOK, &pass, prompt); + if (pamret != PAM_SUCCESS) + return (pamret); + } + rv = krb5_get_init_creds_password(context, &creds, su_principal, + pass, NULL, NULL, 0, NULL, &gic_opt); + if (rv != 0) { + PAM_LOG("krb5_get_init_creds_password: %s", + krb5_get_err_text(context, rv)); + return (PAM_AUTH_ERR); + } + krb5_verify_init_creds_opt_set_ap_req_nofail(&vic_opt, 1); + rv = krb5_verify_init_creds(context, &creds, NULL, NULL, NULL, + &vic_opt); + krb5_free_cred_contents(context, &creds); + if (rv != 0) { + PAM_LOG("krb5_verify_init_creds: %s", + krb5_get_err_text(context, rv)); + return (PAM_AUTH_ERR); + } + return (PAM_SUCCESS); +} + +/* Determine the target principal given the current user and the target user. + * context -- An initialized krb5_context. + * target_user -- The target username. + * current_user -- The current username. + * su_principal_name -- (out) The target principal name. + * su_principal -- (out) The target krb5_principal. + * When the target user is `root', the target principal will be a `root + * instance', e.g. `luser/root@REA.LM'. Otherwise, the target principal + * will simply be the current user's default principal name. Note that + * in any case, if KRB5CCNAME is set and a credentials cache exists, the + * principal name found there will be the `starting point', rather than + * the ruser parameter. + * + * Returns 0 for success, or a com_err error code on failure. + */ +static long +get_su_principal(krb5_context context, const char *target_user, const char *current_user, + char **su_principal_name, krb5_principal *su_principal) +{ + krb5_principal default_principal; + krb5_ccache ccache; + char *principal_name, *ccname, *p; + long rv; + uid_t euid, ruid; + + *su_principal = NULL; + default_principal = NULL; + /* Unless KRB5CCNAME was explicitly set, we won't really be able + * to look at the credentials cache since krb5_cc_default will + * look at getuid(). + */ + ruid = getuid(); + euid = geteuid(); + rv = seteuid(ruid); + if (rv != 0) + return (errno); + p = getenv("KRB5CCNAME"); + if (p != NULL) + ccname = strdup(p); + else + (void)asprintf(&ccname, "%s%lu", KRB5_DEFAULT_CCROOT, (unsigned long)ruid); + if (ccname == NULL) + return (errno); + rv = krb5_cc_resolve(context, ccname, &ccache); + free(ccname); + if (rv == 0) { + rv = krb5_cc_get_principal(context, ccache, &default_principal); + krb5_cc_close(context, ccache); + if (rv != 0) + default_principal = NULL; /* just to be safe */ + } + rv = seteuid(euid); + if (rv != 0) + return (errno); + if (default_principal == NULL) { + rv = krb5_make_principal(context, &default_principal, NULL, current_user, NULL); + if (rv != 0) { + PAM_LOG("Could not determine default principal name."); + return (rv); + } + } + /* Now that we have some principal, if the target account is + * `root', then transform it into a `root' instance, e.g. + * `user@REA.LM' -> `user/root@REA.LM'. + */ + rv = krb5_unparse_name(context, default_principal, &principal_name); + krb5_free_principal(context, default_principal); + if (rv != 0) { + PAM_LOG("krb5_unparse_name: %s", + krb5_get_err_text(context, rv)); + return (rv); + } + PAM_LOG("Default principal name: %s", principal_name); + if (strcmp(target_user, superuser) == 0) { + p = strrchr(principal_name, '@'); + if (p == NULL) { + PAM_LOG("malformed principal name `%s'", principal_name); + free(principal_name); + return (rv); + } + *p++ = '\0'; + *su_principal_name = NULL; + (void)asprintf(su_principal_name, "%s/%s@%s", principal_name, superuser, p); + free(principal_name); + } else + *su_principal_name = principal_name; + + if (*su_principal_name == NULL) + return (errno); + rv = krb5_parse_name(context, *su_principal_name, &default_principal); + if (rv != 0) { + PAM_LOG("krb5_parse_name `%s': %s", *su_principal_name, + krb5_get_err_text(context, rv)); + free(*su_principal_name); + return (rv); + } + PAM_LOG("Target principal name: %s", *su_principal_name); + *su_principal = default_principal; + return (0); +} |