Date: Thu, 16 May 2002 15:45:25 -0500 From: "Jacques A. Vidrine" <nectar@FreeBSD.org> To: freebsd-audit@FreeBSD.org Subject: Kerberos 5 and SU Message-ID: <20020516204525.GA26640@madman.nectar.cc>
next in thread | raw e-mail | index | archive | help
--dDRMvlgZJXvWKvBx Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hello, Attached are two similar implementations of Kerberos 5 support for su(1). Why two? 1. pam_ksu --- This is the long-term solution, but is only appropriate for -CURRENT. -STABLE does not have OpenPAM, and more importantly does not have a PAMified SU [1]. 2. su --- This is for -STABLE only. Support was added in parallel to the existing Kerberos 4 support. This has made the code even more #ifdef grotty, but it will not be maintained after 4.x anyway. The code path is still straightforward. FYI, the `get_target_principal' functions in each correspond, and the `auth_krb5' function in pam_ksu corresponds with the `kerberos5' function in su(1). Please tear it up :-) I'm gone for the weekend. Cheers, -- Jacques A. Vidrine <n@nectar.cc> http://www.nectar.cc/ NTT/Verio SME . FreeBSD UNIX . Heimdal Kerberos jvidrine@verio.net . nectar@FreeBSD.org . nectar@kth.se [1] DES reports that he currently has no plans to backport the SU PAMificiation. --dDRMvlgZJXvWKvBx Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="su.patch" Index: Makefile =================================================================== RCS file: /home/ncvs/src/usr.bin/su/Makefile,v retrieving revision 1.29 diff -u -r1.29 Makefile --- Makefile 2000/02/24 21:06:21 1.29 +++ Makefile 2002/05/16 20:42:46 @@ -14,10 +14,19 @@ CFLAGS+= -Wall .if exists(${DESTDIR}${LIBDIR}/libkrb.a) && defined(MAKE_KERBEROS4) -CFLAGS+=-DKERBEROS +CFLAGS+=-DKERBEROS4 DPADD+= ${LIBKRB} ${LIBCRYPTO} ${LIBCOM_ERR} LDADD+= -lkrb -lcrypto -lcom_err DISTRIBUTION= krb4 +.endif + +.if exists(${DESTDIR}${LIBDIR}/libkrb5.a) && defined(MAKE_KERBEROS5) +CFLAGS+=-DKERBEROS5 +DPADD+= ${LIBKRB5} ${LIBASN1} ${LIBCRYPTO} ${LIBCRYPT} ${LIBCOM_ERR} \ + ${LIBROKEN} +LDADD+= -lkrb5 -lasn1 -lcrypto -lcrypt -lcom_err \ + -L${.OBJDIR}/../../../../kerberos5/lib/libroken -lroken +DISTRIBUTION= krb5 .endif BINMODE=4555 Index: su.c =================================================================== RCS file: /home/ncvs/src/usr.bin/su/su.c,v retrieving revision 1.34.2.3 diff -u -r1.34.2.3 su.c --- su.c 2001/08/17 15:44:42 1.34.2.3 +++ su.c 2002/05/16 20:42:46 @@ -69,28 +69,42 @@ #include <skey.h> #endif -#ifdef KERBEROS +#ifdef KERBEROS5 +#include <com_err.h> +#include <krb5.h> + +static long get_target_principal(krb5_context context, const char *user, + const char *ruser, char **su, krb5_principal *suprinc); +static long kerberos5(krb5_context context, krb5_principal suprinc, + const char *pass); + +int use_kerberos5 = 1; +#endif + +#ifdef KERBEROS4 #include <openssl/des.h> #include <krb.h> #include <netdb.h> -#ifdef LOGIN_CAP -#define ARGSTR "-Kflmc:" -#else -#define ARGSTR "-Kflm" -#endif -static int kerberos(char *username, char *user, int uid, char *pword); +static int kerberos4(char *username, char *user, int uid, char *pword); static int koktologin(char *name, char *toname); + +int use_kerberos4 = 1; +#endif /* KERBEROS4 */ -int use_kerberos = 1; -#else /* !KERBEROS */ #ifdef LOGIN_CAP -#define ARGSTR "-flmc:" +#define LOGIN_CAP_ARG(x) x #else -#define ARGSTR "-flm" +#define LOGIN_CAP_ARG(x) #endif -#endif /* KERBEROS */ +#if defined(KERBEROS4) || defined(KERBEROS5) +#define KERBEROS_ARG(x) x +#else +#define KERBEROS_ARG(x) +#endif +#define COMMON_ARG(x) x +#define ARGSTR "-" COMMON_ARG("flm") LOGIN_CAP_ARG("c:") KERBEROS_ARG("K") char *ontty __P((void)); int chshell __P((char *)); @@ -118,9 +132,14 @@ char *class=NULL; int setwhat; #endif -#ifdef KERBEROS +#if defined(KERBEROS4) || defined(KERBEROS5) char *k; #endif +#ifdef KERBEROS5 + char *suname, *ccname; + krb5_context context; + krb5_principal suprinc; +#endif char shellbuf[MAXPATHLEN]; #ifdef WHEELSU @@ -130,9 +149,14 @@ user = "root"; while((ch = getopt(argc, argv, ARGSTR)) != -1) switch((char)ch) { -#ifdef KERBEROS +#if defined(KERBEROS4) || defined(KERBEROS5) case 'K': - use_kerberos = 0; +#ifdef KERBEROS4 + use_kerberos4 = 0; +#endif +#ifdef KERBEROS5 + use_kerberos5 = 0; +#endif break; #endif case 'f': @@ -179,10 +203,22 @@ argv += optind; -#ifdef KERBEROS +#if defined(KERBEROS4) || defined(KERBEROS5) k = auth_getval("auth_list"); - if (k && !strstr(k, "kerberos")) - use_kerberos = 0; + if (k && !strstr(k, "kerberos")) { +#ifdef KERBEROS4 + use_kerberos4 = 0; +#endif +#ifdef KERBEROS5 + use_kerberos5 = 0; +#endif + } +#endif +#ifdef KERBEROS5 + suname = NULL; + suprinc = NULL; + if (krb5_init_context(&context) != 0) + use_kerberos5 = 0; #endif errno = 0; prio = getpriority(PRIO_PROCESS, 0); @@ -235,13 +271,23 @@ #endif /* WHEELSU */ if (ruid) { -#ifdef KERBEROS - if (use_kerberos && koktologin(username, user) +#ifdef KERBEROS4 + if (use_kerberos4 && koktologin(username, user) && !pwd->pw_uid) { - warnx("kerberos: not in %s's ACL.", user); - use_kerberos = 0; + warnx("kerberos4: not in %s's ACL.", user); + use_kerberos4 = 0; } #endif +#ifdef KERBEROS5 + if (use_kerberos5) { + if (!(get_target_principal(context, user, username, + &suname, &suprinc) == 0 && + krb5_kuserok(context, suprinc, user))) { + warnx("kerberos5: not in %s's ACL.", user); + use_kerberos5 = 0; + } + } +#endif { /* * Only allow those with pw_gid==0 or those listed in @@ -288,15 +334,23 @@ p = getpass("Password:"); if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) { #endif -#ifdef KERBEROS - if (!use_kerberos || (use_kerberos && kerberos(username, user, pwd->pw_uid, p))) -#endif - { - fprintf(stderr, "Sorry\n"); - syslog(LOG_AUTH|LOG_WARNING, "BAD SU %s to %s%s", username, user, ontty()); - exit(1); - } +#ifdef KERBEROS4 + if (use_kerberos4 && kerberos4(username, user, + pwd->pw_uid, p) == 0) + goto authok; +#endif +#ifdef KERBEROS5 + if (use_kerberos5 && kerberos5(context, + suprinc, p) == 0) + goto authok; +#endif + fprintf(stderr, "Sorry\n"); + syslog(LOG_AUTH|LOG_WARNING, + "BAD SU %s to %s%s", username, user, + ontty()); + exit(1); } + authok: #ifdef WHEELSU if (iswheelsu) { pwd = getpwnam(user); @@ -361,9 +415,12 @@ if (!asme) { if (asthem) { p = getenv("TERM"); -#ifdef KERBEROS +#ifdef KERBEROS4 k = getenv("KRBTKFILE"); #endif +#ifdef KERBEROS5 + ccname = getenv("KRB5CCNAME"); +#endif if ((cleanenv = calloc(20, sizeof(char*))) == NULL) errx(1, "calloc"); cleanenv[0] = NULL; @@ -376,10 +433,14 @@ #endif if (p) (void)setenv("TERM", p, 1); -#ifdef KERBEROS +#ifdef KERBEROS4 if (k) (void)setenv("KRBTKFILE", k, 1); #endif +#ifdef KERBEROS5 + if (ccname) + (void)setenv("KRB5CCNAME", ccname, 1); +#endif if (chdir(pwd->pw_dir) < 0) errx(1, "no directory"); } @@ -413,12 +474,8 @@ static void usage() { - (void)fprintf(stderr, "usage: su [-] %s%s[login [args]]\n", -#ifdef KERBEROS - "[-Kflm] ", -#else - "[-flm] ", -#endif + (void)fprintf(stderr, "usage: su [-] [-%s] %s[login [args]]\n", + KERBEROS_ARG("K") COMMON_ARG("flm"), #ifdef LOGIN_CAP "[-c class] " #else @@ -454,10 +511,146 @@ snprintf(buf, sizeof(buf), " on %s", p); return (buf); } + +#ifdef KERBEROS5 +const char superuser[] = "root"; + +/* Authenticate using Kerberos 5. + * context -- An initialized krb5_context. + * suprinc -- The target krb5_principal. + * pass -- The user's password. + * Note that a valid keytab in the default location with a host entry + * must be available. + * Returns 0 if authentication was successful, or a com_err error code if + * it was not. + */ +static long +kerberos5(krb5_context context, krb5_principal suprinc, const char *pass) +{ + krb5_creds creds; + krb5_get_init_creds_opt gic_opt; + krb5_verify_init_creds_opt vic_opt; + long rv; + + krb5_get_init_creds_opt_init(&gic_opt); + krb5_verify_init_creds_opt_init(&vic_opt); + rv = krb5_get_init_creds_password(context, &creds, suprinc, + pass, NULL, NULL, 0, NULL, &gic_opt); + if (rv != 0) { + syslog(LOG_NOTICE|LOG_AUTH, "BAD Kerberos5 SU: %s", + error_message(rv)); /* XXX */ + return (rv); + } + 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) { + syslog(LOG_NOTICE|LOG_AUTH, "BAD Kerberos5 SU: %s", + error_message(rv)); /* XXX */ + return (rv); + } + return (0); +} + +/* Determine the target principal given the current user and the target user. + * context -- An initialized krb5_context. + * user -- The target username. + * ruser -- The current username. + * su -- (out) The target principal name. + * suprinc -- (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_target_principal(krb5_context context, const char *user, const char *ruser, + char **su, krb5_principal *suprinc) +{ + krb5_principal princ; + krb5_ccache ccache; + char *unparsed, *p; + long rv; + uid_t euid; + + *suprinc = NULL; + princ = 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(). + */ + if (getenv("KRB5CCNAME") != NULL) { + /* Lower privs while messing about with the credentials + * cache. + */ + euid = geteuid(); + rv = seteuid(getuid()); + if (rv != 0) + return (errno); + rv = krb5_cc_default(context, &ccache); + if (rv == 0) { + rv = krb5_cc_get_principal(context, ccache, &princ); + krb5_cc_close(context, ccache); + if (rv != 0) + princ = NULL; /* just to be safe */ + } + rv = seteuid(euid); + if (rv != 0) + return (errno); + } + if (princ == NULL) { + rv = krb5_make_principal(context, &princ, NULL, ruser, NULL); + if (rv != 0) { + warnx("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, princ, &unparsed); + krb5_free_principal(context, princ); + if (rv != 0) { + warnx("krb5_unparse_name: %s", error_message(rv)); + return (rv); + } + if (strcmp(user, superuser) == 0) { + p = strrchr(unparsed, '@'); + if (p == NULL) { + warnx("malformed principal name `%s'", unparsed); + free(unparsed); + return (rv); + } + *p++ = '\0'; + *su = NULL; + (void)asprintf(su, "%s/%s@%s", unparsed, superuser, p); + free(unparsed); + } else + *su = unparsed; + + if (*su == NULL) + return errno; + rv = krb5_parse_name(context, *su, &princ); + if (rv != 0) { + warnx("krb5_parse_name `%s': %s", *su, error_message(rv)); + free(*su); + return (rv); + } + *suprinc = princ; + return 0; +} + +#endif -#ifdef KERBEROS +#ifdef KERBEROS4 int -kerberos(username, user, uid, pword) +kerberos4(username, user, uid, pword) char *username, *user; int uid; char *pword; @@ -503,14 +696,14 @@ if (kerno != KSUCCESS) { if (kerno == KDC_PR_UNKNOWN) { - warnx("kerberos: principal unknown: %s.%s@%s", + warnx("kerberos4: principal unknown: %s.%s@%s", (uid == 0 ? username : user), (uid == 0 ? "root" : ""), lrealm); return (1); } - warnx("kerberos: unable to su: %s", krb_err_txt[kerno]); + warnx("kerberos4: unable to su: %s", krb_err_txt[kerno]); syslog(LOG_NOTICE|LOG_AUTH, - "BAD Kerberos SU: %s to %s%s: %s", + "BAD Kerberos4 SU: %s to %s%s: %s", username, user, ontty(), krb_err_txt[kerno]); return (1); } @@ -556,7 +749,7 @@ if ((kerno = krb_rd_req(&ticket, "rcmd", savehost, faddr, &authdata, "")) != KSUCCESS) { - warnx("kerberos: unable to verify rcmd ticket: %s\n", + warnx("kerberos4: unable to verify rcmd ticket: %s\n", krb_err_txt[kerno]); syslog(LOG_NOTICE|LOG_AUTH, "failed su: %s to %s%s: %s", username, --dDRMvlgZJXvWKvBx Content-Type: application/x-shar Content-Disposition: attachment; filename="pam_ksu.shar" Content-Transfer-Encoding: quoted-printable # This is a shell archive. Save it in a file, remove anything before=0A# t= his line, and then unpack it by entering "sh file". Note, it may=0A# creat= e directories; files and directories will be owned by you and=0A# have defa= ult permissions.=0A#=0A# This archive contains:=0A#=0A# pam_ksu=0A# pam_ksu= /Makefile=0A# pam_ksu/pam_ksu.8=0A# pam_ksu/pam_ksu.c=0A#=0Aecho c - pam_ks= u=0Amkdir -p pam_ksu > /dev/null 2>&1=0Aecho x - pam_ksu/Makefile=0Ased 's/= ^X//' >pam_ksu/Makefile << 'END-of-pam_ksu/Makefile'=0AX# Copyright 2002 Fr= eeBSD, Inc.=0AX# All rights reserved.=0AX#=0AX# Redistribution and use in s= ource and binary forms, with or without=0AX# modification, are permitted pr= ovided that the following conditions=0AX# are met:=0AX# 1. Redistributions = of source code must retain the above copyright=0AX# notice, this list of= conditions and the following disclaimer.=0AX# 2. Redistributions in binary= form must reproduce the above copyright=0AX# notice, this list of condi= tions and the following disclaimer in the=0AX# documentation and/or othe= r materials provided with the distribution.=0AX#=0AX# THIS SOFTWARE IS PROV= IDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND=0AX# ANY EXPRESS OR IMPLI= ED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE=0AX# IMPLIED WARRANTIES O= F MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE=0AX# ARE DISCLAIMED.= IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE=0AX# FOR ANY DIREC= T, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL=0AX# DAMAGES = (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS=0AX# OR SER= VICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)=0AX# HOWEVE= R CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT=0AX# L= IABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY=0A= X# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF= =0AX# SUCH DAMAGE.=0AX#=0AX# $FreeBSD: src/lib/libpam/modules/pam_krb5/Make= file,v 1.2.2.3 2001/07/30 10:03:58 markm Exp $=0AX=0AXPAMDIR=3D ${.CURDIR}= /../../../../contrib/libpam=0AX=0AXLIB=3D pam_ksu=0AXSRCS=3D pam_ksu.c=0A= XCFLAGS+=3D -Wall=0AXCFLAGS+=3D -I${PAMDIR}/libpam/include=0AXCFLAGS+=3D -I= ${.CURDIR}/../../libpam=0AXDPADD=3D ${LIBKRB5} ${LIBASN1} ${LIBCRYPTO} ${L= IBCRYPT} \=0AX ${LIBCOM_ERR} ${LIBROKEN}=0AXLDADD=3D -lkrb5 -lasn1 -lcryp= to -lcrypt -lcom_err \=0AX -L${.OBJDIR}/../../../../kerberos5/lib/libroken= -lroken =0AXMAN=3D pam_ksu.8=0AX#INTERNALLIB=3D yes=0AX#INTERNALSTATICLIB= =3Dyes=0AX=0AX.include <bsd.lib.mk>=0AEND-of-pam_ksu/Makefile=0Aecho x - pa= m_ksu/pam_ksu.8=0Ased 's/^X//' >pam_ksu/pam_ksu.8 << 'END-of-pam_ksu/pam_ks= u.8'=0AX.\" Copyright (c) 2001 Mark R V Murray=0AX.\" All rights reserved.= =0AX.\" Copyright (c) 2001 Networks Associates Technology, Inc.=0AX.\" All = rights reserved.=0AX.\"=0AX.\" This software was developed for the FreeBSD = Project by ThinkSec AS and=0AX.\" NAI Labs, the Security Research Division = of Network Associates, Inc.=0AX.\" under DARPA/SPAWAR contract N66001-01-C-= 8035 ("CBOSS"), as part of the=0AX.\" DARPA CHATS research program.=0AX.\"= =0AX.\" Redistribution and use in source and binary forms, with or without= =0AX.\" modification, are permitted provided that the following conditions= =0AX.\" are met:=0AX.\" 1. Redistributions of source code must retain the a= bove copyright=0AX.\" notice, this list of conditions and the following = disclaimer.=0AX.\" 2. Redistributions in binary form must reproduce the abo= ve copyright=0AX.\" notice, this list of conditions and the following di= sclaimer in the=0AX.\" documentation and/or other materials provided wit= h the distribution.=0AX.\" 3. The name of the author may not be used to end= orse or promote=0AX.\" products derived from this software without speci= fic prior written=0AX.\" permission.=0AX.\"=0AX.\" THIS SOFTWARE IS PROV= IDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND=0AX.\" ANY EXPRESS OR IMP= LIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE=0AX.\" IMPLIED WARRANTI= ES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE=0AX.\" ARE DISCL= AIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE=0AX.\" FOR A= NY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL=0AX.\= " DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS= =0AX.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTIO= N)=0AX.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRAC= T, STRICT=0AX.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARI= SING IN ANY WAY=0AX.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF = THE POSSIBILITY OF=0AX.\" SUCH DAMAGE.=0AX.\"=0AX.\" $FreeBSD$=0AX.\"=0AX.D= d May 15, 2002=0AX.Dt pam_ksu 8=0AX.Os=0AX.Sh NAME=0AX.Nm pam_ksu=0AX.Nd Ke= rberos 5 SU PAM module=0AX.Sh SYNOPSIS=0AX.Op Ar service-name=0AX.Ar module= -type=0AX.Ar control-flag=0AX.Pa pam_ksu=0AX.Op Ar options=0AX.Sh DESCRIPTI= ON=0AXThe Kerberos 5 SU authentication service module for PAM,=0AX.Nm=0AXfo= r only one PAM category: authentication.=0AXIn terms of the=0AX.Ar module-t= ype=0AXparameter, this is the=0AX.Dq Li auth=0AXfeature.=0AXThe module is s= pecifically designed to be used with the=0AX.Xr su 1=0AXutility.=0AX.\" It = also provides a null function for session management.=0AX.Ss Kerberos 5 SU = Authentication Module=0AXThe Kerberos 5 SU authentication component provide= s functions to verify=0AXthe identity of a user=0AX.Pq Fn pam_sm_authentica= te ,=0AXand determine whether or not the user is authorized to obtain the= =0AXprivileges of the target account.=0AXIf the target account is `root', t= hen the Kerberos 5 principal used=0AXfor authentication and authorization w= ill be the `root' instance of=0AXthe current user, e.g. `user/root@REAL.M'.= =0AXOtherwise, the principal will simply be the current user's default=0AXp= rincipal, e.g. `user@REAL.M'.=0AX.Pp=0AXThe user is prompted for a password= if necessary. Authorization is performed=0AXby comparing the Kerberos 5 p= rincipal with those listed in the=0AX.Pa .k5login=0AXfile in the target acc= ount's home directory=0AX.Pq e.g. /root/.k5login for root .=0AX.Pp=0AXThe f= ollowing options may be passed to the authentication module:=0AX.Bl -tag -w= idth ".Cm use_first_pass"=0AX.It Cm debug=0AX.Xr syslog 3=0AXdebugging info= rmation at=0AX.Dv LOG_DEBUG=0AXlevel.=0AX.It Cm use_first_pass=0AXIf the au= thentication module=0AXis not the first in the stack,=0AXand a previous mod= ule=0AXobtained the user's password,=0AXthat password is used=0AXto authent= icate the user.=0AXIf this fails,=0AXthe authentication module returns fail= ure=0AXwithout prompting the user for a password.=0AXThis option has no eff= ect=0AXif the authentication module=0AXis the first in the stack,=0AXor if = no previous modules=0AXobtained the user's password.=0AX.It Cm try_first_pa= ss=0AXThis option is similar to the=0AX.Cm use_first_pass=0AXoption,=0AXexc= ept that if the previously obtained password fails,=0AXthe user is prompted= for another password.=0AX.El=0AX.Sh SEE ALSO=0AX.Xr su 1 ,=0AX.Xr syslog 3= ,=0AX.Xr pam.conf 5 ,=0AX.Xr pam 8=0AEND-of-pam_ksu/pam_ksu.8=0Aecho x - p= am_ksu/pam_ksu.c=0Ased 's/^X//' >pam_ksu/pam_ksu.c << 'END-of-pam_ksu/pam_k= su.c'=0AX/*-=0AX * Copyright (c) 2002 Jacques A. Vidrine <nectar@FreeBSD.or= g>=0AX * All rights reserved.=0AX *=0AX * Redistribution and use in source = and binary forms, with or without=0AX * modification, are permitted provide= d that the following conditions=0AX * are met:=0AX * 1. Redistributions of = source code must retain the above copyright=0AX * notice, this list of c= onditions and the following disclaimer.=0AX * 2. Redistributions in binary = form must reproduce the above copyright=0AX * notice, this list of condi= tions and the following disclaimer in the=0AX * documentation and/or oth= er materials provided with the distribution.=0AX *=0AX * THIS SOFTWARE IS P= ROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND=0AX * ANY EXPRESS OR I= MPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE=0AX * IMPLIED WARRANT= IES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE=0AX * ARE DISCL= AIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE=0AX * FOR AN= Y DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL=0AX * = DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS=0AX= * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)=0A= X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STR= ICT=0AX * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN= ANY WAY=0AX * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSS= IBILITY OF=0AX * SUCH DAMAGE.=0AX */=0AX#include <sys/cdefs.h>=0AX__FBSDID(= "$FreeBSD$");=0AX=0AX#include <sys/param.h>=0AX#include <com_err.h>=0AX#inc= lude <errno.h>=0AX#include <stdio.h>=0AX#include <stdlib.h>=0AX#include <st= ring.h>=0AX#include <unistd.h>=0AX=0AX#include <krb5.h>=0AX=0AX#define PAM_= SM_AUTH=0AX#define PAM_SM_CRED=0AX#include <security/pam_appl.h>=0AX#includ= e <security/pam_modules.h>=0AX#include <security/pam_mod_misc.h>=0AX=0AXsta= tic const char superuser[] =3D "root";=0AX=0AXstatic long get_target_princi= pal(krb5_context, const char *, const char *,=0AX char **su, krb5_prin= cipal *);=0AXstatic int auth_krb5(pam_handle_t *, krb5_context, const char = *,=0AX krb5_principal);=0AX=0AXstatic struct opttab other_options[] = =3D {=0AX { NULL, 0 }=0AX};=0AX=0AX=0AXPAM_EXTERN int=0AXpam_sm_authenticat= e(pam_handle_t *pamh, int flags __unused, int ac __unused,=0AX const cha= r *av[] __unused)=0AX{=0AX struct options options;=0AX krb5_context conte= xt;=0AX krb5_principal suprinc;=0AX const char *user, *ruser;=0AX char *s= u;=0AX long rv;=0AX int pamret;=0AX =0AX pam_std_option(&options, other= _options, ac, av);=0AX PAM_LOG("pam_ksu: Options processed");=0AX pamret = =3D pam_get_user(pamh, &user, NULL);=0AX if (pamret !=3D PAM_SUCCESS)=0AX = return (pamret);=0AX PAM_LOG("Got user: %s", user);=0AX pamret =3D pam_get_= item(pamh, PAM_RUSER, (const void **)&ruser);=0AX if (pamret !=3D PAM_SUCCE= SS)=0AX return (pamret);=0AX PAM_LOG("Got ruser: %s", ruser);=0AX rv =3D k= rb5_init_context(&context);=0AX if (rv !=3D 0) {=0AX PAM_LOG("krb5_init_co= ntext failed: %s", error_message(rv));=0AX return (PAM_SERVICE_ERR);=0AX }= =0AX rv =3D get_target_principal(context, user, ruser, &su, &suprinc);=0AX = if (rv !=3D 0)=0AX return (PAM_AUTH_ERR);=0AX PAM_LOG("kuserok: %s -> %s",= su, user);=0AX rv =3D krb5_kuserok(context, suprinc, user);=0AX pamret =3D= rv ? auth_krb5(pamh, context, su, suprinc) : PAM_AUTH_ERR;=0AX free(su);= =0AX krb5_free_principal(context, suprinc);=0AX krb5_free_context(context);= =0AX return (pamret);=0AX}=0AX=0AXPAM_EXTERN int=0AXpam_sm_setcred(pam_hand= le_t *pamh __unused, int flags __unused,=0AX int ac __unused, const char= *av[] __unused)=0AX{=0AX return (PAM_SUCCESS);=0AX}=0AX=0AX/* Authenticate= using Kerberos 5.=0AX * pamh -- The PAM handle.=0AX * context -- An= initialized krb5_context.=0AX * su -- The target principal name, us= ed only for password prompts.=0AX * If NULL, the password prom= pts will not include a principal=0AX * name.=0AX * suprinc -= - The target krb5_principal.=0AX * Note that a valid keytab in the default = location with a host entry=0AX * must be available, and that the PAM applic= ation must have sufficient=0AX * privileges to access it.=0AX * Returns PAM= _SUCCESS if authentication was successful, or an appropriate=0AX * PAM erro= r code if it was not.=0AX */=0AXstatic int=0AXauth_krb5(pam_handle_t *pamh,= krb5_context context, const char *su,=0AX krb5_principal suprinc)=0AX{= =0AX krb5_creds creds;=0AX krb5_get_init_creds_opt gic_opt;=0AX krb5_verif= y_init_creds_opt vic_opt;=0AX const char *pass;=0AX char *prompt;=0AX long= rv;=0AX int pamret;=0AX=0AX prompt =3D NULL;=0AX krb5_get_init_creds_o= pt_init(&gic_opt);=0AX krb5_verify_init_creds_opt_init(&vic_opt);=0AX if (s= u !=3D NULL)=0AX (void)asprintf(&prompt, "Password for %s:", su);=0AX else= =0AX (void)asprintf(&prompt, "Password:");=0AX if (prompt =3D=3D NULL)=0AX= return (PAM_BUF_ERR);=0AX pass =3D NULL;=0AX (void)pam_get_item(pamh, PAM= _AUTHTOK, (const void **)&pass);=0AX free(prompt);=0AX if (pass =3D=3D NULL= ) {=0AX pamret =3D pam_get_authtok(pamh, PAM_AUTHTOK, &pass, prompt);=0AX = if (pamret !=3D PAM_SUCCESS)=0AX return (pamret);=0AX }=0AX rv =3D krb5_= get_init_creds_password(context, &creds, suprinc,=0AX pass, NULL, NULL,= 0, NULL, &gic_opt);=0AX if (rv !=3D 0) {=0AX PAM_LOG("krb5_get_init_creds= _password: %s", error_message(rv));=0AX return (PAM_AUTH_ERR);=0AX }=0AX k= rb5_verify_init_creds_opt_set_ap_req_nofail(&vic_opt, 1);=0AX rv =3D krb5_v= erify_init_creds(context, &creds, NULL, NULL, NULL,=0AX &vic_opt);=0AX = krb5_free_cred_contents(context, &creds);=0AX if (rv !=3D 0) {=0AX PAM_LOG= ("krb5_verify_init_creds: %s", error_message(rv));=0AX return (PAM_AUTH_ER= R);=0AX }=0AX return (PAM_SUCCESS);=0AX}=0AX=0AX/* Determine the target pri= ncipal given the current user and the target user.=0AX * context -- An in= itialized krb5_context.=0AX * user -- The target username.=0AX * rus= er -- The current username.=0AX * su -- (out) The target principal= name.=0AX * suprinc -- (out) The target krb5_principal.=0AX * When the t= arget user is `root', the target principal will be a `root=0AX * instance',= e.g. `luser/root@REA.LM'. Otherwise, the target principal=0AX * will simp= ly be the current user's default principal name. Note that=0AX * in any ca= se, if KRB5CCNAME is set and a credentials cache exists, the=0AX * principa= l name found there will be the `starting point', rather than=0AX * the ruse= r parameter.=0AX *=0AX * Returns 0 for success, or a com_err error code on = failure.=0AX */=0AXstatic long=0AXget_target_principal(krb5_context context= , const char *user, const char *ruser,=0AX char **su, krb5_principal *su= princ)=0AX{=0AX krb5_principal princ;=0AX krb5_ccache ccache;=0AX char *= unparsed, *p;=0AX long rv;=0AX uid_t euid;=0AX=0AX *suprinc =3D NULL;= =0AX princ =3D NULL;=0AX /* Unless KRB5CCNAME was explicitly set, we won't = really be able=0AX * to look at the credentials cache since krb5_cc_defaul= t will=0AX * look at getuid().=0AX */=0AX if (getenv("KRB5CCNAME") !=3D N= ULL) {=0AX /* Lower privs while messing about with the credentials=0AX *= cache.=0AX */=0AX euid =3D geteuid();=0AX rv =3D seteuid(getuid());=0A= X if (rv !=3D 0)=0AX return (errno);=0AX rv =3D krb5_cc_default(context= , &ccache);=0AX if (rv =3D=3D 0) {=0AX rv =3D krb5_cc_get_principal(cont= ext, ccache, &princ);=0AX krb5_cc_close(context, ccache);=0AX if (rv != =3D 0)=0AX princ =3D NULL; /* just to be safe */=0AX }=0AX rv =3D sete= uid(euid);=0AX if (rv !=3D 0)=0AX return (errno);=0AX }=0AX if (princ = =3D=3D NULL) {=0AX rv =3D krb5_make_principal(context, &princ, NULL, ruser= , NULL);=0AX if (rv !=3D 0) {=0AX PAM_LOG("Could not determine default p= rincipal name.");=0AX return (rv);=0AX }=0AX }=0AX /* Now that we have s= ome principal, if the target account is=0AX * `root', then transform it in= to a `root' instance, e.g.=0AX * `user@REA.LM' -> `user/root@REA.LM'.=0AX = */=0AX rv =3D krb5_unparse_name(context, princ, &unparsed);=0AX krb5_free_= principal(context, princ);=0AX if (rv !=3D 0) {=0AX PAM_LOG("krb5_unparse_= name: %s", error_message(rv));=0AX return (rv);=0AX }=0AX PAM_LOG("Default= principal name: %s", unparsed);=0AX if (strcmp(user, superuser) =3D=3D 0) = {=0AX p =3D strrchr(unparsed, '@');=0AX if (p =3D=3D NULL) {=0AX PAM_LO= G("malformed principal name `%s'", unparsed);=0AX free(unparsed);=0AX r= eturn (rv);=0AX }=0AX *p++ =3D '\0';=0AX *su =3D NULL;=0AX (void)asprin= tf(su, "%s/%s@%s", unparsed, superuser, p);=0AX free(unparsed);=0AX } else= =0AX *su =3D unparsed;=0AX=0AX if (*su =3D=3D NULL)=0AX return errno;=0A= X rv =3D krb5_parse_name(context, *su, &princ);=0AX if (rv !=3D 0) {=0AX P= AM_LOG("krb5_parse_name `%s': %s", *su, error_message(rv));=0AX free(*su);= =0AX return (rv);=0AX }=0AX PAM_LOG("Target principal name: %s", *su);=0AX= *suprinc =3D princ;=0AX return 0;=0AX}=0AEND-of-pam_ksu/pam_ksu.c=0Aexit= =0A=0A --dDRMvlgZJXvWKvBx-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-audit" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020516204525.GA26640>