Bring in a few useful PAM modules.

pam_krb5 is a Kerberos 5 (Heimdal) authentication module.

pam_nologin checks for /etc/nologin and does the "usual stuff"
	if it is found, otherwise it silently succeeds.

pam_rootok silently succeeds if the user is root, otherwise
	it fails.

pam_wheel silently succeeds if the user is a member of group
	"wheel" (or another nominated group), and fails
	otherwise.

There is an issue with kerberosIV and kerberos5 - if both are
being built, then static linking fails with duplicate symbols.
This will take a bit of work to sort out in the kerberii.
This commit is contained in:
Mark Murray 2001-05-14 11:23:58 +00:00
parent 3abfa903d2
commit 84d6cd8ea1
17 changed files with 1810 additions and 4 deletions

View File

@ -70,15 +70,18 @@ STATIC_MODULES+= ${MODOBJDIR}/pam_deny/libpam_deny.a
.if defined(MAKE_KERBEROS4) && !defined(NOCRYPT) && !defined(NO_OPENSSL) .if defined(MAKE_KERBEROS4) && !defined(NOCRYPT) && !defined(NO_OPENSSL)
STATIC_MODULES+= ${MODOBJDIR}/pam_kerberosIV/libpam_kerberosIV.a STATIC_MODULES+= ${MODOBJDIR}/pam_kerberosIV/libpam_kerberosIV.a
.endif .endif
.if defined(MAKE_KERBEROS5__) && !defined(NOCRYPT) && !defined(NO_OPENSSL) .if defined(MAKE_KERBEROS5) && !defined(NOCRYPT) && !defined(NO_OPENSSL)
STATIC_MODULES+= ${MODOBJDIR}/pam_kerberos5/libpam_kerberos5.a STATIC_MODULES+= ${MODOBJDIR}/pam_krb5/libpam_krb5.a
.endif .endif
STATIC_MODULES+= ${MODOBJDIR}/pam_nologin/libpam_nologin.a
STATIC_MODULES+= ${MODOBJDIR}/pam_opie/libpam_opie.a STATIC_MODULES+= ${MODOBJDIR}/pam_opie/libpam_opie.a
STATIC_MODULES+= ${MODOBJDIR}/pam_permit/libpam_permit.a STATIC_MODULES+= ${MODOBJDIR}/pam_permit/libpam_permit.a
STATIC_MODULES+= ${MODOBJDIR}/pam_radius/libpam_radius.a STATIC_MODULES+= ${MODOBJDIR}/pam_radius/libpam_radius.a
STATIC_MODULES+= ${MODOBJDIR}/pam_rootok/libpam_rootok.a
STATIC_MODULES+= ${MODOBJDIR}/pam_skey/libpam_skey.a STATIC_MODULES+= ${MODOBJDIR}/pam_skey/libpam_skey.a
STATIC_MODULES+= ${MODOBJDIR}/pam_tacplus/libpam_tacplus.a STATIC_MODULES+= ${MODOBJDIR}/pam_tacplus/libpam_tacplus.a
STATIC_MODULES+= ${MODOBJDIR}/pam_unix/libpam_unix.a STATIC_MODULES+= ${MODOBJDIR}/pam_unix/libpam_unix.a
STATIC_MODULES+= ${MODOBJDIR}/pam_wheel/libpam_wheel.a
STATICOBJS+= pam_static_modules.o STATICOBJS+= pam_static_modules.o
CLEANFILES+= pam_static.o CLEANFILES+= pam_static.o

View File

@ -29,14 +29,17 @@ SUBDIR+= pam_deny
.if defined(MAKE_KERBEROS4) && !defined(NOCRYPT) && !defined(NO_OPENSSL) .if defined(MAKE_KERBEROS4) && !defined(NOCRYPT) && !defined(NO_OPENSSL)
SUBDIR+= pam_kerberosIV SUBDIR+= pam_kerberosIV
.endif .endif
.if defined(MAKE_KERBEROS5__) && !defined(NOCRYPT) && !defined(NO_OPENSSL) .if defined(MAKE_KERBEROS5) && !defined(NOCRYPT) && !defined(NO_OPENSSL)
SUBDIR+= pam_kerberos5 SUBDIR+= pam_krb5
.endif .endif
SUBDIR+= pam_nologin
SUBDIR+= pam_opie SUBDIR+= pam_opie
SUBDIR+= pam_permit SUBDIR+= pam_permit
SUBDIR+= pam_radius SUBDIR+= pam_radius
SUBDIR+= pam_rootok
SUBDIR+= pam_skey SUBDIR+= pam_skey
SUBDIR+= pam_tacplus SUBDIR+= pam_tacplus
SUBDIR+= pam_unix SUBDIR+= pam_unix
SUBDIR+= pam_wheel
.include <bsd.subdir.mk> .include <bsd.subdir.mk>

View File

@ -0,0 +1,195 @@
pam_krb5:
$FreeBSD$
Copyright (c) Frank Cusack, 1999-2000.
fcusack@fcusack.com
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, and the entire permission notice in its entirety,
including the disclaimer of warranties.
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.
ALTERNATIVELY, this product may be distributed under the terms of
the GNU Public License, in which case the provisions of the GPL are
required INSTEAD OF the above restrictions. (This clause is
necessary due to a potential bad interaction between the GPL and
the restrictions contained in a BSD-style copyright.)
THIS SOFTWARE IS PROVIDED ``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 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.
---------------------------------------------------------------------------
This software may contain code from Naomaru Itoi:
PAM-kerberos5 module Copyright notice.
Naomaru Itoi <itoi@eecs.umich.edu>, June 24, 1997.
----------------------------------------------------------------------------
COPYRIGHT (c) 1997
THE REGENTS OF THE UNIVERSITY OF MICHIGAN
ALL RIGHTS RESERVED
PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS AND REDISTRIBUTE
THIS SOFTWARE AND SUCH DERIVATIVE WORKS FOR ANY PURPOSE, SO LONG AS THE NAME
OF THE UNIVERSITY OF MICHIGAN IS NOT USED IN ANY ADVERTISING OR PUBLICITY
PERTAINING TO THE USE OR DISTRIBUTION OF THIS SOFTWARE WITHOUT SPECIFIC,
WRITTEN PRIOR AUTHORIZATION. IF THE ABOVE COPYRIGHT NOTICE OR ANY OTHER
IDENTIFICATION OF THE UNIVERSITY OF MICHIGAN IS INCLUDED IN ANY COPY OF ANY
PORTION OF THIS SOFTWARE, THEN THE DISCLAIMER BELOW MUST ALSO BE INCLUDED.
THE SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE UNIVERSITY OF
MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND WITHOUT WARRANTY BY THE
UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
WITHOUT LIMITATION THE IMPLIED WARRANTIES OF MERCHANTABITILY AND FITNESS FOR A
PARTICULAR PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE
LIABLE FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING OUT OF OR IN
CONNECTION WITH THE USE OF THE SOFTWARE, EVEN IF IT HAS BEEN OR IS HEREAFTER
ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
PAM-kerberos5 module is written based on PAM-kerberos4 module
by Derrick J. Brashear and kerberos5-1.0pl1 by M.I.T. kerberos team.
Permission to use, copy, modify, distribute this software is hereby
granted, as long as it is granted by Derrick J. Brashear and
M.I.T. kerberos team. Followings are their copyright information.
----------------------------------------------------------------------------
This software may contain code from Derrick J. Brashear:
Copyright (c) Derrick J. Brashear, 1996. 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, and the entire permission notice in its entirety,
including the disclaimer of warranties.
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.
ALTERNATIVELY, this product may be distributed under the terms of
the GNU Public License, in which case the provisions of the GPL are
required INSTEAD OF the above restrictions. (This clause is
necessary due to a potential bad interaction between the GPL and
the restrictions contained in a BSD-style copyright.)
THIS SOFTWARE IS PROVIDED ``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 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.
----------------------------------------------------------------------------
This software may contain code from MIT Kerberos 5:
Copyright Notice and Legal Administrivia
----------------------------------------
Copyright (C) 1996 by the Massachusetts Institute of Technology.
All rights reserved.
Export of this software from the United States of America may require
a specific license from the United States Government. It is the
responsibility of any person or organization contemplating export to
obtain such a license before exporting.
WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
distribute this software and its documentation for any purpose and
without fee is hereby granted, provided that the above copyright
notice appear in all copies and that both that copyright notice and
this permission notice appear in supporting documentation, and that
the name of M.I.T. not be used in advertising or publicity pertaining
to distribution of the software without specific, written prior
permission. M.I.T. makes no representations about the suitability of
this software for any purpose. It is provided "as is" without express
or implied warranty.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
Individual source code files are copyright MIT, Cygnus Support,
OpenVision, Oracle, Sun Soft, and others.
Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
and Zephyr are trademarks of the Massachusetts Institute of Technology
(MIT). No commercial use of these trademarks may be made without
prior written permission of MIT.
"Commercial use" means use of a name in a product or other for-profit
manner. It does NOT prevent a commercial firm from referring to the
MIT trademarks in order to convey information (although in doing so,
recognition of their trademark status should be given).
The following copyright and permission notice applies to the
OpenVision Kerberos Administration system located in kadmin/create,
kadmin/dbutil, kadmin/passwd, kadmin/server, lib/kadm5, and portions
of lib/rpc:
Copyright, OpenVision Technologies, Inc., 1996, All Rights Reserved
WARNING: Retrieving the OpenVision Kerberos Administration system
source code, as described below, indicates your acceptance of the
following terms. If you do not agree to the following terms, do not
retrieve the OpenVision Kerberos administration system.
You may freely use and distribute the Source Code and Object Code
compiled from it, with or without modification, but this Source
Code is provided to you "AS IS" EXCLUSIVE OF ANY WARRANTY,
INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY OR
FITNESS FOR A PARTICULAR PURPOSE, OR ANY OTHER WARRANTY, WHETHER
EXPRESS OR IMPLIED. IN NO EVENT WILL OPENVISION HAVE ANY LIABILITY
FOR ANY LOST PROFITS, LOSS OF DATA OR COSTS OF PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES, OR FOR ANY SPECIAL, INDIRECT, OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, INCLUDING,
WITHOUT LIMITATION, THOSE RESULTING FROM THE USE OF THE SOURCE
CODE, OR THE FAILURE OF THE SOURCE CODE TO PERFORM, OR FOR ANY
OTHER REASON.
OpenVision retains all copyrights in the donated Source Code. OpenVision
also retains copyright to derivative works of the Source Code, whether
created by OpenVision or by a third party. The OpenVision copyright
notice must be preserved if derivative works are made based on the
donated Source Code.
OpenVision Technologies, Inc. has donated this Kerberos
Administration system to MIT for inclusion in the standard
Kerberos 5 distribution. This donation underscores our
commitment to continuing Kerberos technology development
and our gratitude for the valuable work which has been
performed by MIT and the Kerberos community.

View File

@ -0,0 +1,44 @@
# Copyright 2001 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_krb5
SHLIB_NAME= pam_krb5.so
SRCS= pam_krb5_auth.c pam_krb5_pass.c pam_krb5_acct.c \
pam_krb5_sess.c support.c compat_heimdal.c
CFLAGS+= -Wall
CFLAGS+= -I${PAMDIR}/libpam/include
CFLAGS+= -I${.CURDIR}/../../libpam
DPADD+= ${LIBKRB5} ${LIBGSSAPI} ${LIBASN1} ${LIBCRYPTO} ${LIBCRYPT} \
${LIBCOM_ERR}
LDADD+= -lkrb5 -lgssapi -lasn1 -lroken -lcrypto -lcrypt -lcom_err \
-L${.OBJDIR}/../../../../kerberos5/lib/libroken
INTERNALLIB= yes
INTERNALSTATICLIB=yes
MAN= pam_krb5.8
.include <bsd.lib.mk>

View File

@ -0,0 +1,72 @@
$FreeBSD$
This is the README for pam_krb5, a PAM module which support Kerberos 5
authentication.
This software is Copyright (c) 1999-2000 Frank Cusack.
All Rights Reserved.
See the COPYRIGHT file, included with this distribution, for copyright
and redistribution information.
Author:
Frank Cusack
<fcusack@fcusack.com>
I. Kerberos notes
This PAM module requires the MIT 1.1+ release of Kerberos, or the Cygnus
CNS distribution. It has not been tested against heimdal or any other
Kerberos distributions.
Unlike other PAM Kerberos 5 modules out there, this one does not
use any private Kerberos interfaces. Thus, you need only the
header files and libraries that are part of the Kerberos distribution.
II. OS notes
This software has been tested against Solaris 2.6. It should compile
against Linux (distributions?) with minimal (if any) changes. Reports
of OS [in]compatibilities are welcomed.
dtlogin on Solaris doesn't support xrealm logins (probably a good thing).
III. PAM notes/open issues
auth module:
When is pam_sm_setcred() ever called with flags other than PAM_ESTABLISH_CRED
or PAM_DELETE_CRED?
acct module:
I believe this to be complete.
session module:
This is complete (both functions just return success).
passwd module:
When is pam_sm_chauthtok() ever called with flags other than
PAM_UPDATE_AUTHTOK?
IV. Usage
Simply change /etc/pam.conf to include this module. Make sure to include
the acct category whenever you use the auth category, or .k5login will
not get checked.
You probably want to make this module "sufficient", before your unix
(or other) module(s).
V. Acknowledgements
Thanks to Naomaru Itoi <itoi@eecs.umich.edu>,
Curtis King <curtis.king@cul.ca>, and Derrick Brashear <shadow@dementia.org>,
all of whom have written and made available Kerberos 4/5 modules.
Although no code in this module is directly from these author's modules,
(except the get_user_info() routine in support.c; derived from whichever
of these authors originally wrote the first module the other 2 copied from),
it was extremely helpful to look over their code which aided in my design.

View File

@ -0,0 +1,16 @@
$FreeBSD$
Things for 1.1, in no particular order:
Check against Solaris 7, Solaris 8 beta. Check SEAM compatibility.
Check against Linux (Redhat, others?).
Check against HPUX.
Fix PAM flags checking.
Add more debugging for successful calls.
Move "entry" debugging up.
Check bounds on str* calls. [paranoia]
Get defaults from krb5.conf?
** Allow no-xrealm, this module typically used for local login **
** Add notes about runtime text relocation on Solaris **

View File

@ -0,0 +1,141 @@
/*
* compat_heimdal.c
*
* Heimdal compatability layer.
*
* $FreeBSD$
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <krb5.h>
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include "pam_krb5.h"
const char *
compat_princ_component(krb5_context context, krb5_principal princ, int n)
{
return princ->name.name_string.val[n];
}
void
compat_free_data_contents(krb5_context context, krb5_data *data)
{
krb5_xfree(data->data);
}
krb5_error_code
compat_cc_next_cred(krb5_context context, const krb5_ccache id,
krb5_cc_cursor *cursor, krb5_creds *creds)
{
return krb5_cc_next_cred(context, id, creds, cursor);
}
static krb5_error_code
heimdal_pam_prompter(krb5_context context, void *data, const char *banner, int
num_prompts, krb5_prompt prompts[])
{
int pam_prompts = num_prompts;
int pamret, i;
struct pam_message *msg;
struct pam_response *resp = NULL;
struct pam_conv *conv;
pam_handle_t *pamh = (pam_handle_t *) data;
if ((pamret = pam_get_item(pamh, PAM_CONV, (const void **) &conv)) != 0)
return KRB5KRB_ERR_GENERIC;
if (banner)
pam_prompts++;
msg = calloc(sizeof(struct pam_message) * pam_prompts, 1);
if (!msg)
return ENOMEM;
/* Now use pam_prompts as an index */
pam_prompts = 0;
if (banner) {
msg[pam_prompts].msg = malloc(strlen(banner) + 1);
if (!msg[pam_prompts].msg)
goto cleanup;
strcpy((char *) msg[pam_prompts].msg, banner);
msg[pam_prompts].msg_style = PAM_TEXT_INFO;
pam_prompts++;
}
for (i = 0; i < num_prompts; i++) {
msg[pam_prompts].msg = malloc(strlen(prompts[i].prompt) + 3);
if (!msg[pam_prompts].msg)
goto cleanup;
sprintf((char *) msg[pam_prompts].msg, "%s: ", prompts[i].prompt);
msg[pam_prompts].msg_style = prompts[i].hidden ? PAM_PROMPT_ECHO_OFF
: PAM_PROMPT_ECHO_ON;
pam_prompts++;
}
if ((pamret = conv->conv(pam_prompts, (const struct pam_message **) &msg,
&resp, conv->appdata_ptr)) != 0)
goto cleanup;
if (!resp)
goto cleanup;
/* Reuse pam_prompts as a starting index */
pam_prompts = 0;
if (banner)
pam_prompts++;
for (i = 0; i < num_prompts; i++, pam_prompts++) {
register int len;
if (!resp[pam_prompts].resp) {
pamret = PAM_AUTH_ERR;
goto cleanup;
}
len = strlen(resp[pam_prompts].resp); /* Help out the compiler */
if (len > prompts[i].reply->length) {
pamret = PAM_AUTH_ERR;
goto cleanup;
}
memcpy(prompts[i].reply->data, resp[pam_prompts].resp, len);
prompts[i].reply->length = len;
}
cleanup:
/* pam_prompts is correct at this point */
for (i = 0; i < pam_prompts; i++) {
if (msg[i].msg)
free((char *) msg[i].msg);
}
free(msg);
if (resp) {
for (i = 0; i < pam_prompts; i++) {
/*
* Note that PAM is underspecified wrt free()'ing resp[i].resp.
* It's not clear if I should free it, or if the application
* has to. Therefore most (all?) apps won't free() it, and I
* can't either, as I am not sure it was malloc()'d. All PAM
* implementations I've seen leak memory here. Not so bad, IFF
* you fork/exec for each PAM authentication (as is typical).
*/
#if 0
if (resp[i].resp)
free(resp[i].resp);
#endif /* 0 */
}
/* This does not lose resp[i].resp if the application saved a copy. */
free(resp);
}
return (pamret ? KRB5KRB_ERR_GENERIC : 0);
}
krb5_prompter_fct pam_prompter = heimdal_pam_prompter;

View File

@ -0,0 +1,191 @@
.\"
.\" $Id: pam_krb5.5,v 1.5 2000/01/05 00:59:56 fcusack Exp $
.\" $FreeBSD$
.TH pam_krb5 8 "15 Jan 1999"
.SH NAME
pam_krb5 \- Kerberos 5 PAM module
.SH SYNOPSIS
.LP
.B /usr/lib/pam_krb5.so
.LP
.SH DESCRIPTION
.IX "pam_krb5" "" "\fLpam_krb5\fP \(em Kerberos 5 PAM module"
.PP
The Kerberos 5 service module for PAM, typically
.BR /usr/lib/pam_krb5.so ,
provides functionality for three PAM categories:
authentication,
account management,
and password management.
It also provides null functions for session management.
The
.B pam_krb5.so
module is a shared object
that can be dynamically loaded to provide
the necessary functionality upon demand.
Its path is specified in the
.SM PAM
configuration file.
.SH Kerberos 5 Authentication Module
The Kerberos 5 authentication component
provides functions to verify the identity of a user.
(\f3pam_sm_authenticate(\|)\f1)
and to set user specific credentials
(\f3pam_sm_setcred(\|)\f1).
.B pam_sm_authenticate(\|)
converts the supplied username into a Kerberos principal,
by appending the default local realm name.
It also supports usernames with explicit realm names.
If a realm name is supplied, then upon a sucessful return, it
changes the username by mapping the principal name into a local username
(calling \f3krb5_aname_to_localname()\f1). This typically just means
the realm name is stripped.
.LP
It prompts the user for a password and obtains a new Kerberos TGT for
the principal. The TGT is verified by obtaining a service
ticket for the local host.
.LP
When prompting for the current password, the authentication
module will use the prompt "Password for <principal>: ".
.LP
The
.B pam_sm_setcred(\|)
function stores the newly acquired credentials in a credentials cache,
and sets the environment variable
.B KRB5CCNAME
appropriately.
The credentials cache should be destroyed by the user at logout with
.BR kdestroy (1) .
.LP
The following options may be passed to the authentication module:
.TP 15
.B debug
.BR syslog (3)
debugging information at
.SB LOG_DEBUG
level.
.TP
.B 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.
.TP
.B try_first_pass
This option is similar to the
.B use_first_pass
option, except that if the previously obtained password fails, the
user is prompted for another password.
.TP
.B forwardable
Obtain forwardable Kerberos credentials for the user.
.TP
.B no_ccache
Do not save the obtained credentials in a credentials cache. This is a
useful option if the authentication module is used for services such
as ftp or pop, where the user would not be able to destroy them. [This
is not a recommendation to use the module for those services.]
.TP
.B ccache=<name>
Use <name> as the credentials cache. <name> must be in the form
.IR type:residual .
The special tokens
.BR %u ,
to designate the decimal uid of the user;
and
.BR %p ,
to designate the current process id; can be used in <name>.
.SH Kerberos 5 Account Management Module
The Kerberos 5 account management component
provides a function to perform account management,
.BR pam_sm_acct_mgmt(\|) .
The function verifies that the authenticated principal is allowed
to login to the local user account by calling
.B krb5_kuserok()
(which checks the user's \&.k5login file).
.SH Kerberos 5 Password Management Module
The Kerberos 5 password management component
provides a function to change passwords
(\f3pam_sm_chauthtok(\|)\f1). The username supplied (the
user running the
.BR passwd (1)
command, or the username given as an argument) is mapped into
a Kerberos principal name, using the same technique as in
the authentication module. Note that if a realm name was
explicitly supplied during authentication, but not during
a password change, the mapping
done by the password management module may not result in the
same principal as was used for authentication.
.LP
Unlike when
changing a unix password, the password management module will
allow any user to change any principal's password (if the user knows
the principal's old password, of course). Also unlike unix, root
is always prompted for the principal's old password.
.LP
The password management module uses the same heuristics as
.BR kpasswd (1)
to determine how to contact the Kerberos password server.
.LP
The following options may be passed to the password management
module:
.TP 15
.B debug
.BR syslog (3)
debugging information at
.SB LOG_DEBUG
level.
.TP
.B use_first_pass
If the password management module is not the first in the stack,
and a previous module obtained the user's old password, that password is
used to authenticate the user. If this fails, the password
management
module returns failure without prompting the user for the old password.
If successful, the new password entered to the previous module is also
used as the new Kerberos password. If the new password fails,
the password management module returns failure without
prompting the user for a new password.
.TP
.B try_first_pass
This option is similar to the
.B use_first_pass
option, except that if the previously obtained old or new passwords fail,
the user is prompted for them.
.SH Kerberos 5 Session Management Module
The Kerberos 5 session management component
provides functions to initiate
(\f3pam_sm_open_session(\|)\f1)
and terminate
(\f3pam_sm_close_session(\|)\f1)
sessions. Since session management is not defined under Kerberos 5,
both of these functions simply return success. They are provided
only because of the naming conventions for PAM modules.
.SH ENVIRONMENT
.TP "\w'.SM KRB5CCNAME\ \ 'u"
.SM KRB5CCNAME
Location of the credentials cache.
.SH FILES
.TP "\w'/tmp/krb5cc_[uid]\ \ 'u"
/tmp/krb5cc_[uid]
default credentials cache ([uid] is the decimal UID of the user).
.TP
~/\&.k5login
file containing Kerberos principals that are allowed access.
.SH SEE ALSO
.BR kdestroy (1),
.BR passwd (1),
.BR pam (8),
.BR syslog (3),
.BR pam.conf (5).
.SH NOTES
Applications should not call
.B pam_authenticate()
more than once between calls to
.B pam_start()
and
.B pam_end()
when using the Kerberos 5 PAM module.

View File

@ -0,0 +1,23 @@
/*
* pam_krb5.h
*
* $Id: pam_krb5.h,v 1.5 1999/01/19 23:43:10 fcusack Exp $
* $FreeBSD$
*/
int get_user_info(pam_handle_t *, char *, int, char **);
int verify_krb_v5_tgt(krb5_context, krb5_ccache, char *, int);
void cleanup_cache(pam_handle_t *, void *, int);
krb5_prompter_fct pam_prompter;
const char *compat_princ_component(krb5_context, krb5_principal, int);
void compat_free_data_contents(krb5_context, krb5_data *);
krb5_error_code compat_cc_next_cred(krb5_context, const krb5_ccache,
krb5_cc_cursor *, krb5_creds *);
#ifndef ENCTYPE_DES_CBC_MD5
#define ENCTYPE_DES_CBC_MD5 ETYPE_DES_CBC_MD5
#endif

View File

@ -0,0 +1,83 @@
/*
* pam_krb5_acct.c
*
* PAM account management functions for pam_krb5
*
* $FreeBSD$
*/
static const char rcsid[] = "$Id: pam_krb5_acct.c,v 1.3 1999/01/19 21:26:44 fcusack Exp $";
#include <syslog.h> /* syslog */
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include <krb5.h>
#include <com_err.h>
#include "pam_krb5.h"
/* A useful logging macro */
#define DLOG(error_func, error_msg) \
if (debug) \
syslog(LOG_DEBUG, "pam_krb5: pam_sm_acct_mgmt(%s %s): %s: %s", \
service, name, error_func, error_msg)
/* Check authorization of user */
int
pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
krb5_error_code krbret;
krb5_context pam_context;
krb5_ccache ccache;
krb5_principal princ;
char *service, *name;
int debug = 0;
int i, pamret;
for (i = 0; i < argc; i++) {
if (strcmp(argv[i], "debug") == 0)
debug = 1;
}
/* Get username */
if (pam_get_item(pamh, PAM_USER, (const void **) &name)) {
return PAM_PERM_DENIED;;
}
/* Get service name */
(void) pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
if (!service)
service = "unknown";
DLOG("entry", "");
if (pam_get_data(pamh, "ccache", (const void **) &ccache)) {
/* User did not use krb5 to login */
DLOG("ccache", "not found");
return PAM_SUCCESS;
}
if ((krbret = krb5_init_context(&pam_context)) != 0) {
DLOG("krb5_init_context()", error_message(krbret));
return PAM_PERM_DENIED;;
}
if ((krbret = krb5_cc_get_principal(pam_context, ccache, &princ)) != 0) {
DLOG("krb5_cc_get_principal()", error_message(krbret));
pamret = PAM_PERM_DENIED;;
goto cleanup;
}
if (krb5_kuserok(pam_context, princ, name))
pamret = PAM_SUCCESS;
else
pamret = PAM_PERM_DENIED;
krb5_free_principal(pam_context, princ);
cleanup:
krb5_free_context(pam_context);
DLOG("exit", pamret ? "failure" : "success");
return pamret;
}

View File

@ -0,0 +1,505 @@
/*
* pam_krb5_auth.c
*
* PAM authentication management functions for pam_krb5
*
* $FreeBSD$
*/
static const char rcsid[] = "$Id: pam_krb5_auth.c,v 1.18 2000/01/04 08:44:08 fcusack Exp $";
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <limits.h> /* PATH_MAX */
#include <pwd.h> /* getpwnam */
#include <stdio.h> /* tmpnam */
#include <stdlib.h> /* malloc */
#include <strings.h> /* strchr */
#include <syslog.h> /* syslog */
#include <unistd.h> /* chown */
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include <krb5.h>
#include <com_err.h>
#include "pam_krb5.h"
extern krb5_cc_ops krb5_mcc_ops;
/* A useful logging macro */
#define DLOG(error_func, error_msg) \
if (debug) \
syslog(LOG_DEBUG, "pam_krb5: pam_sm_authenticate(%s %s): %s: %s", \
service, name, error_func, error_msg)
/* Authenticate a user via krb5 */
int
pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
const char **argv)
{
krb5_error_code krbret;
krb5_context pam_context;
krb5_creds creds;
krb5_principal princ;
krb5_ccache ccache, ccache_check;
krb5_get_init_creds_opt opts;
int pamret, i;
const char *name;
char *source_princ = NULL;
char *princ_name = NULL;
char *pass = NULL, *service = NULL;
char *prompt = NULL;
char cache_name[L_tmpnam + 8];
char lname[64]; /* local acct name */
struct passwd *pw;
uid_t ruid;
int debug = 0, try_first_pass = 0, use_first_pass = 0;
int forwardable = 0, reuse_ccache = 0, no_ccache = 0;
for (i = 0; i < argc; i++) {
if (strcmp(argv[i], "debug") == 0)
debug = 1;
else if (strcmp(argv[i], "try_first_pass") == 0)
try_first_pass = 1;
else if (strcmp(argv[i], "use_first_pass") == 0)
use_first_pass = 1;
else if (strcmp(argv[i], "forwardable") == 0)
forwardable = 1;
else if (strcmp(argv[i], "reuse_ccache") == 0)
reuse_ccache = 1;
else if (strcmp(argv[i], "no_ccache") == 0)
no_ccache = 1;
}
/* Get username */
if ((pamret = pam_get_user(pamh, &name, "login: ")) != PAM_SUCCESS) {
return PAM_SERVICE_ERR;
}
/* Get service name */
(void) pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
if (!service)
service = "unknown";
DLOG("entry", "");
if ((krbret = krb5_init_context(&pam_context)) != 0) {
DLOG("krb5_init_context()", error_message(krbret));
return PAM_SERVICE_ERR;
}
krb5_get_init_creds_opt_init(&opts);
memset(&creds, 0, sizeof(krb5_creds));
memset(cache_name, 0, sizeof(cache_name));
memset(lname, 0, sizeof(lname));
if (forwardable)
krb5_get_init_creds_opt_set_forwardable(&opts, 1);
/* For CNS */
if ((krbret = krb5_cc_register(pam_context, &krb5_mcc_ops, FALSE)) != 0) {
/* Solaris dtlogin doesn't call pam_end() on failure */
if (krbret != KRB5_CC_TYPE_EXISTS) {
DLOG("krb5_cc_register()", error_message(krbret));
pamret = PAM_SERVICE_ERR;
goto cleanup3;
}
}
/* Get principal name */
/* This case is for use mainly by su.
If non-root is authenticating as "root", use "source_user/root". */
if (!strcmp(name, "root") && (ruid = getuid()) != 0) {
pw = getpwuid(ruid);
if (pw != NULL)
source_princ = (char *)malloc(strlen(pw->pw_name) + 6);
if (source_princ)
sprintf(source_princ, "%s/root", pw->pw_name);
} else {
source_princ = strdup(name);
}
if (!source_princ) {
DLOG("malloc()", "failure");
pamret = PAM_BUF_ERR;
goto cleanup2;
}
if ((krbret = krb5_parse_name(pam_context, source_princ, &princ)) != 0) {
DLOG("krb5_parse_name()", error_message(krbret));
pamret = PAM_SERVICE_ERR;
goto cleanup3;
}
/* Now convert the principal name into something human readable */
if ((krbret = krb5_unparse_name(pam_context, princ, &princ_name)) != 0) {
DLOG("krb5_unparse_name()", error_message(krbret));
pamret = PAM_SERVICE_ERR;
goto cleanup2;
}
/* Get password */
prompt = malloc(16 + strlen(princ_name));
if (!prompt) {
DLOG("malloc()", "failure");
pamret = PAM_BUF_ERR;
goto cleanup2;
}
(void) sprintf(prompt, "Password for %s: ", princ_name);
if (try_first_pass || use_first_pass)
(void) pam_get_item(pamh, PAM_AUTHTOK, (const void **) &pass);
get_pass:
if (!pass) {
try_first_pass = 0;
if ((pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF,
&pass)) != 0) {
DLOG("get_user_info()", pam_strerror(pamh, pamret));
pamret = PAM_SERVICE_ERR;
goto cleanup2;
}
/* We have to free pass. */
if ((pamret = pam_set_item(pamh, PAM_AUTHTOK, pass)) != 0) {
DLOG("pam_set_item()", pam_strerror(pamh, pamret));
free(pass);
pamret = PAM_SERVICE_ERR;
goto cleanup2;
}
free(pass);
/* Now we get it back from the library. */
(void) pam_get_item(pamh, PAM_AUTHTOK, (const void **) &pass);
}
/* get a local account name for this principal */
if ((krbret = krb5_aname_to_localname(pam_context, princ,
sizeof(lname), lname)) == 0) {
DLOG("changing PAM_USER to", lname);
if ((pamret = pam_set_item(pamh, PAM_USER, lname)) != 0) {
DLOG("pam_set_item()", pam_strerror(pamh, pamret));
pamret = PAM_SERVICE_ERR;
goto cleanup2;
}
if ((pamret = pam_get_item(pamh, PAM_USER, (const void **) &name)
!= 0)) {
DLOG("pam_get_item()", pam_strerror(pamh, pamret));
pamret = PAM_SERVICE_ERR;
goto cleanup2;
}
} else {
DLOG("krb5_aname_to_localname()", error_message(krbret));
/* Not an error. */
}
/* Verify the local user exists (AFTER getting the password) */
pw = getpwnam(name);
if (!pw) {
DLOG("getpwnam()", lname);
pamret = PAM_USER_UNKNOWN;
goto cleanup2;
}
/* Get a TGT */
if ((krbret = krb5_get_init_creds_password(pam_context, &creds, princ,
pass, pam_prompter, pamh, 0, NULL, &opts)) != 0) {
DLOG("krb5_get_init_creds_password()", error_message(krbret));
if (try_first_pass && krbret == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
pass = NULL;
goto get_pass;
}
pamret = PAM_AUTH_ERR;
goto cleanup2;
}
/* Generate a unique cache_name */
strcpy(cache_name, "MEMORY:");
(void) tmpnam(&cache_name[7]);
if ((krbret = krb5_cc_resolve(pam_context, cache_name, &ccache)) != 0) {
DLOG("krb5_cc_resolve()", error_message(krbret));
pamret = PAM_SERVICE_ERR;
goto cleanup;
}
if ((krbret = krb5_cc_initialize(pam_context, ccache, princ)) != 0) {
DLOG("krb5_cc_initialize()", error_message(krbret));
pamret = PAM_SERVICE_ERR;
goto cleanup;
}
if ((krbret = krb5_cc_store_cred(pam_context, ccache, &creds)) != 0) {
DLOG("krb5_cc_store_cred()", error_message(krbret));
(void) krb5_cc_destroy(pam_context, ccache);
pamret = PAM_SERVICE_ERR;
goto cleanup;
}
/* Verify it */
if (verify_krb_v5_tgt(pam_context, ccache, service, debug) == -1) {
(void) krb5_cc_destroy(pam_context, ccache);
pamret = PAM_AUTH_ERR;
goto cleanup;
}
/* A successful authentication, store ccache for sm_setcred() */
if (!pam_get_data(pamh, "ccache", (const void **) &ccache_check)) {
DLOG("pam_get_data()", "ccache data already present");
(void) krb5_cc_destroy(pam_context, ccache);
pamret = PAM_AUTH_ERR;
goto cleanup;
}
if ((pamret = pam_set_data(pamh, "ccache", ccache, cleanup_cache)) != 0) {
DLOG("pam_set_data()", pam_strerror(pamh, pamret));
(void) krb5_cc_destroy(pam_context, ccache);
pamret = PAM_SERVICE_ERR;
goto cleanup;
}
cleanup:
krb5_free_cred_contents(pam_context, &creds);
cleanup2:
krb5_free_principal(pam_context, princ);
cleanup3:
if (prompt)
free(prompt);
if (princ_name)
free(princ_name);
if (source_princ)
free(source_princ);
krb5_free_context(pam_context);
DLOG("exit", pamret ? "failure" : "success");
return pamret;
}
/* redefine this for pam_sm_setcred() */
#undef DLOG
#define DLOG(error_func, error_msg) \
if (debug) \
syslog(LOG_DEBUG, "pam_krb5: pam_sm_setcred(%s %s): %s: %s", \
service, name, error_func, error_msg)
/* Called after a successful authentication. Set user credentials. */
int
pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,
const char **argv)
{
krb5_error_code krbret;
krb5_context pam_context;
krb5_principal princ;
krb5_creds creds;
krb5_ccache ccache_temp, ccache_perm;
krb5_cc_cursor cursor;
int i, pamret;
char *name, *service = NULL;
char *cache_name = NULL, *cache_env_name;
struct passwd *pw = NULL;
int debug = 0;
uid_t euid;
gid_t egid;
if (flags == PAM_REINITIALIZE_CRED)
return PAM_SUCCESS; /* XXX Incorrect behavior */
if (flags != PAM_ESTABLISH_CRED && flags != PAM_DELETE_CRED)
return PAM_SERVICE_ERR;
for (i = 0; i < argc; i++) {
if (strcmp(argv[i], "debug") == 0)
debug = 1;
else if (strcmp(argv[i], "no_ccache") == 0)
return PAM_SUCCESS;
else if (strstr(argv[i], "ccache=") == argv[i])
cache_name = (char *) &argv[i][7]; /* save for later */
}
/* Get username */
if (pam_get_item(pamh, PAM_USER, (const void **) &name)) {
return PAM_SERVICE_ERR;
}
/* Get service name */
(void) pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
if (!service)
service = "unknown";
DLOG("entry", "");
if ((krbret = krb5_init_context(&pam_context)) != 0) {
DLOG("krb5_init_context()", error_message(krbret));
return PAM_SERVICE_ERR;
}
euid = geteuid(); /* Usually 0 */
egid = getegid();
/* Retrieve the cache name */
if ((pamret = pam_get_data(pamh, "ccache", (const void **) &ccache_temp))
!= 0) {
/* User did not use krb5 to login */
DLOG("ccache", "not found");
pamret = PAM_SUCCESS;
goto cleanup3;
}
/* Get the uid. This should exist. */
pw = getpwnam(name);
if (!pw) {
DLOG("getpwnam()", name);
pamret = PAM_USER_UNKNOWN;
goto cleanup3;
}
/* Avoid following a symlink as root */
if (setegid(pw->pw_gid)) {
DLOG("setegid()", name); /* XXX should really log group name or id */
pamret = PAM_SERVICE_ERR;
goto cleanup3;
}
if (seteuid(pw->pw_uid)) {
DLOG("seteuid()", name);
pamret = PAM_SERVICE_ERR;
goto cleanup3;
}
/* Get the cache name */
if (!cache_name) {
cache_name = malloc(64); /* plenty big */
if (!cache_name) {
DLOG("malloc()", "failure");
pamret = PAM_BUF_ERR;
goto cleanup3;
}
sprintf(cache_name, "FILE:/tmp/krb5cc_%d", pw->pw_uid);
} else {
/* cache_name was supplied */
char *p = calloc(PATH_MAX + 10, 1); /* should be plenty */
char *q = cache_name;
if (!p) {
DLOG("malloc()", "failure");
pamret = PAM_BUF_ERR;
goto cleanup3;
}
cache_name = p;
/* convert %u and %p */
while (*q) {
if (*q == '%') {
q++;
if (*q == 'u') {
sprintf(p, "%d", pw->pw_uid);
p += strlen(p);
} else if (*q == 'p') {
sprintf(p, "%d", getpid());
p += strlen(p);
} else {
/* Not a special token */
*p++ = '%';
q--;
}
q++;
} else {
*p++ = *q++;
}
}
}
if ((krbret = krb5_cc_resolve(pam_context, cache_name, &ccache_perm))
!= 0) {
DLOG("krb5_cc_resolve()", error_message(krbret));
pamret = PAM_SERVICE_ERR;
goto cleanup3;
}
if (flags == PAM_ESTABLISH_CRED) {
/* Initialize the new ccache */
if ((krbret = krb5_cc_get_principal(pam_context, ccache_temp, &princ))
!= 0) {
DLOG("krb5_cc_get_principal()", error_message(krbret));
pamret = PAM_SERVICE_ERR;
goto cleanup3;
}
if ((krbret = krb5_cc_initialize(pam_context, ccache_perm, princ)) != 0) {
DLOG("krb5_cc_initialize()", error_message(krbret));
pamret = PAM_SERVICE_ERR;
goto cleanup2;
}
/* Prepare for iteration over creds */
if ((krbret = krb5_cc_start_seq_get(pam_context, ccache_temp, &cursor))
!= 0) {
DLOG("krb5_cc_start_seq_get()", error_message(krbret));
(void) krb5_cc_destroy(pam_context, ccache_perm);
pamret = PAM_SERVICE_ERR;
goto cleanup2;
}
/* Copy the creds (should be two of them) */
while ((krbret = compat_cc_next_cred(pam_context, ccache_temp,
&cursor, &creds) == 0)) {
if ((krbret = krb5_cc_store_cred(pam_context, ccache_perm,
&creds)) != 0) {
DLOG("krb5_cc_store_cred()", error_message(krbret));
(void) krb5_cc_destroy(pam_context, ccache_perm);
krb5_free_cred_contents(pam_context, &creds);
pamret = PAM_SERVICE_ERR;
goto cleanup2;
}
krb5_free_cred_contents(pam_context, &creds);
}
(void) krb5_cc_end_seq_get(pam_context, ccache_temp, &cursor);
if (strstr(cache_name, "FILE:") == cache_name) {
if (chown(&cache_name[5], pw->pw_uid, pw->pw_gid) == -1) {
DLOG("chown()", strerror(errno));
(void) krb5_cc_destroy(pam_context, ccache_perm);
pamret = PAM_SERVICE_ERR;
goto cleanup2;
}
if (chmod(&cache_name[5], (S_IRUSR|S_IWUSR)) == -1) {
DLOG("chmod()", strerror(errno));
(void) krb5_cc_destroy(pam_context, ccache_perm);
pamret = PAM_SERVICE_ERR;
goto cleanup2;
}
}
(void) krb5_cc_close(pam_context, ccache_perm);
cache_env_name = malloc(strlen(cache_name) + 12);
if (!cache_env_name) {
DLOG("malloc()", "failure");
(void) krb5_cc_destroy(pam_context, ccache_perm);
pamret = PAM_BUF_ERR;
goto cleanup2;
}
sprintf(cache_env_name, "KRB5CCNAME=%s", cache_name);
if ((pamret = pam_putenv(pamh, cache_env_name)) != 0) {
DLOG("pam_putenv()", pam_strerror(pamh, pamret));
(void) krb5_cc_destroy(pam_context, ccache_perm);
pamret = PAM_SERVICE_ERR;
goto cleanup2;
}
} else {
/* flag == PAM_DELETE_CRED */
if ((krbret = krb5_cc_destroy(pam_context, ccache_perm)) != 0) {
/* log error, but otherwise ignore it */
DLOG("krb5_cc_destroy()", error_message(krbret));
}
goto cleanup3;
}
cleanup2:
krb5_free_principal(pam_context, princ);
cleanup3:
krb5_free_context(pam_context);
DLOG("exit", pamret ? "failure" : "success");
(void) seteuid(euid);
(void) setegid(egid);
return pamret;
}

View File

@ -0,0 +1,200 @@
/*
* pam_krb5_pass.c
*
* PAM password management functions for pam_krb5
*
* $FreeBSD$
*/
static const char rcsid[] = "$Id: pam_krb5_pass.c,v 1.3 1999/01/19 23:43:11 fcusack Exp $";
#include <errno.h>
#include <stdio.h> /* sprintf */
#include <stdlib.h> /* malloc */
#include <syslog.h> /* syslog */
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include <krb5.h>
#include <com_err.h>
#include "pam_krb5.h"
/* A useful logging macro */
#define DLOG(error_func, error_msg) \
if (debug) \
syslog(LOG_DEBUG, "pam_krb5: pam_sm_chauthtok(%s %s): %s: %s", \
service, name, error_func, error_msg)
/* Change a user's password */
int
pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
krb5_error_code krbret;
krb5_context pam_context;
krb5_creds creds;
krb5_principal princ;
krb5_get_init_creds_opt opts;
int result_code;
krb5_data result_code_string, result_string;
int pamret, i;
char *name, *service = NULL, *pass = NULL, *pass2;
char *princ_name = NULL;
char *prompt = NULL;
int debug = 0;
int try_first_pass = 0, use_first_pass = 0;
if (!(flags & PAM_UPDATE_AUTHTOK))
return PAM_AUTHTOK_ERR;
for (i = 0; i < argc; i++) {
if (strcmp(argv[i], "debug") == 0)
debug = 1;
else if (strcmp(argv[i], "try_first_pass") == 0)
try_first_pass = 1;
else if (strcmp(argv[i], "use_first_pass") == 0)
use_first_pass = 1;
}
/* Get username */
if ((pam_get_item(pamh, PAM_USER, (const void **) &name)) != 0) {
return PAM_SERVICE_ERR;
}
/* Get service name */
(void) pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
if (!service)
service = "unknown";
DLOG("entry", "");
if ((krbret = krb5_init_context(&pam_context)) != 0) {
DLOG("krb5_init_context()", error_message(krbret));
return PAM_SERVICE_ERR;
}
if ((krbret = krb5_init_context(&pam_context)) != 0) {
DLOG("krb5_init_context()", error_message(krbret));
return PAM_SERVICE_ERR;
}
krb5_get_init_creds_opt_init(&opts);
memset(&creds, 0, sizeof(krb5_creds));
/* Get principal name */
if ((krbret = krb5_parse_name(pam_context, name, &princ)) != 0) {
DLOG("krb5_parse_name()", error_message(krbret));
pamret = PAM_USER_UNKNOWN;
goto cleanup3;
}
/* Now convert the principal name into something human readable */
if ((krbret = krb5_unparse_name(pam_context, princ, &princ_name)) != 0) {
DLOG("krb5_unparse_name()", error_message(krbret));
pamret = PAM_SERVICE_ERR;
goto cleanup2;
}
/* Get password */
prompt = malloc(16 + strlen(princ_name));
if (!prompt) {
DLOG("malloc()", "failure");
pamret = PAM_BUF_ERR;
goto cleanup2;
}
(void) sprintf(prompt, "Password for %s: ", princ_name);
if (try_first_pass || use_first_pass)
(void) pam_get_item(pamh, PAM_AUTHTOK, (const void **) &pass);
get_pass:
if (!pass) {
try_first_pass = 0;
if ((pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF,
&pass)) != 0) {
DLOG("get_user_info()", pam_strerror(pamh, pamret));
pamret = PAM_SERVICE_ERR;
goto cleanup2;
}
/* We have to free pass. */
if ((pamret = pam_set_item(pamh, PAM_AUTHTOK, pass)) != 0) {
DLOG("pam_set_item()", pam_strerror(pamh, pamret));
free(pass);
pamret = PAM_SERVICE_ERR;
goto cleanup2;
}
free(pass);
/* Now we get it back from the library. */
(void) pam_get_item(pamh, PAM_AUTHTOK, (const void **) &pass);
}
if ((krbret = krb5_get_init_creds_password(pam_context, &creds, princ,
pass, pam_prompter, pamh, 0, "kadmin/changepw", &opts)) != 0) {
DLOG("krb5_get_init_creds_password()", error_message(krbret));
if (try_first_pass && krbret == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
pass = NULL;
goto get_pass;
}
pamret = PAM_AUTH_ERR;
goto cleanup2;
}
/* Now get the new password */
free(prompt);
prompt = "Enter new password: ";
if ((pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF, &pass))
!= 0) {
DLOG("get_user_info()", pam_strerror(pamh, pamret));
prompt = NULL;
pamret = PAM_SERVICE_ERR;
goto cleanup;
}
prompt = "Enter it again: ";
if ((pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF, &pass2))
!= 0) {
DLOG("get_user_info()", pam_strerror(pamh, pamret));
prompt = NULL;
pamret = PAM_SERVICE_ERR;
goto cleanup;
}
prompt = NULL;
if (strcmp(pass, pass2) != 0) {
DLOG("strcmp()", "passwords not equal");
pamret = PAM_AUTHTOK_ERR;
goto cleanup;
}
/* Change it */
if ((krbret = krb5_change_password(pam_context, &creds, pass,
&result_code, &result_code_string, &result_string)) != 0) {
DLOG("krb5_change_password()", error_message(krbret));
pamret = PAM_AUTHTOK_ERR;
goto cleanup;
}
if (result_code) {
DLOG("krb5_change_password() (result_code)", "");
pamret = PAM_AUTHTOK_ERR;
goto cleanup;
}
if (result_string.data)
free(result_string.data);
if (result_code_string.data)
free(result_code_string.data);
cleanup:
krb5_free_cred_contents(pam_context, &creds);
cleanup2:
krb5_free_principal(pam_context, princ);
cleanup3:
if (prompt)
free(prompt);
if (princ_name)
free(princ_name);
krb5_free_context(pam_context);
DLOG("exit", pamret ? "failure" : "success");
return pamret;
}

View File

@ -0,0 +1,28 @@
/*
* pam_krb5_sess.c
*
* PAM session management functions for pam_krb5
* (null functions)
*
* $FreeBSD$
*/
static const char rcsid[] = "$Id: pam_krb5_sess.c,v 1.3 1999/01/19 20:49:44 fcusack Exp $";
#include <security/pam_appl.h>
#include <security/pam_modules.h>
/* Initiate session management */
int
pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
return PAM_SUCCESS;
}
/* Terminate session management */
int
pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
return PAM_SUCCESS;
}

View File

@ -0,0 +1,185 @@
/*
* support.c
*
* Support functions for pam_krb5
*
* $FreeBSD$
*/
static const char rcsid[] = "$Id: support.c,v 1.8 2000/01/04 09:50:03 fcusack Exp $";
#include <errno.h>
#include <stdio.h> /* BUFSIZ */
#include <stdlib.h> /* malloc */
#include <string.h> /* strncpy */
#include <syslog.h> /* syslog */
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include <krb5.h>
#include <com_err.h>
#include "pam_krb5.h"
/*
* Get info from the user. Disallow null responses (regardless of flags).
* response gets allocated and filled in on successful return. Caller
* is responsible for freeing it.
*/
int
get_user_info(pam_handle_t *pamh, char *prompt, int type, char **response)
{
int pamret;
struct pam_message msg;
const struct pam_message *pmsg;
struct pam_response *resp = NULL;
struct pam_conv *conv;
if ((pamret = pam_get_item(pamh, PAM_CONV, (const void **) &conv)) != 0)
return pamret;
/* set up conversation call */
pmsg = &msg;
msg.msg_style = type;
msg.msg = prompt;
if ((pamret = conv->conv(1, &pmsg, &resp, conv->appdata_ptr)) != 0)
return pamret;
/* Caller should ignore errors for non-response conversations */
if (!resp)
return PAM_CONV_ERR;
if (!(resp->resp && resp->resp[0])) {
free(resp);
return PAM_AUTH_ERR;
}
*response = resp->resp;
free(resp);
return pamret;
}
/*
* This routine with some modification is from the MIT V5B6 appl/bsd/login.c
* Modified by Sam Hartman <hartmans@mit.edu> to support PAM services
* for Debian.
*
* Verify the Kerberos ticket-granting ticket just retrieved for the
* user. If the Kerberos server doesn't respond, assume the user is
* trying to fake us out (since we DID just get a TGT from what is
* supposedly our KDC). If the host/<host> service is unknown (i.e.,
* the local keytab doesn't have it), and we cannot find another
* service we do have, let her in.
*
* Returns 1 for confirmation, -1 for failure, 0 for uncertainty.
*/
int
verify_krb_v5_tgt(krb5_context context, krb5_ccache ccache,
char * pam_service, int debug)
{
char phost[BUFSIZ];
char *services [3];
char **service;
krb5_error_code retval = -1;
krb5_principal princ;
krb5_keyblock * keyblock = 0;
krb5_data packet;
krb5_auth_context auth_context = NULL;
packet.data = 0;
/*
* If possible we want to try and verify the ticket we have
* received against a keytab. We will try multiple service
* principals, including at least the host principal and the PAM
* service principal. The host principal is preferred because access
* to that key is generally sufficient to compromise root, while the
* service key for this PAM service may be less carefully guarded.
* It is important to check the keytab first before the KDC so we do
* not get spoofed by a fake KDC.*/
services [0] = "host";
services [1] = pam_service;
services [2] = NULL;
for ( service = &services[0]; *service != NULL; service++ ) {
if ((retval = krb5_sname_to_principal(context, NULL, *service, KRB5_NT_SRV_HST,
&princ)) != 0) {
if (debug)
syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
"krb5_sname_to_principal()", error_message(retval));
return -1;
}
/* Extract the name directly. */
strncpy(phost, compat_princ_component(context, princ, 1), BUFSIZ);
phost[BUFSIZ - 1] = '\0';
/*
* Do we have service/<host> keys?
* (use default/configured keytab, kvno IGNORE_VNO to get the
* first match, and ignore enctype.)
*/
if ((retval = krb5_kt_read_service_key(context, NULL, princ, 0,
0, &keyblock)) != 0)
continue;
break;
}
if (retval != 0 ) { /* failed to find key */
/* Keytab or service key does not exist */
if (debug)
syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
"krb5_kt_read_service_key()", error_message(retval));
retval = 0;
goto cleanup;
}
if (keyblock)
krb5_free_keyblock(context, keyblock);
/* Talk to the kdc and construct the ticket. */
retval = krb5_mk_req(context, &auth_context, 0, *service, phost,
NULL, ccache, &packet);
if (auth_context) {
krb5_auth_con_free(context, auth_context);
auth_context = NULL; /* setup for rd_req */
}
if (retval) {
if (debug)
syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
"krb5_mk_req()", error_message(retval));
retval = -1;
goto cleanup;
}
/* Try to use the ticket. */
retval = krb5_rd_req(context, &auth_context, &packet, princ,
NULL, NULL, NULL);
if (retval) {
if (debug)
syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
"krb5_rd_req()", error_message(retval));
retval = -1;
} else {
retval = 1;
}
cleanup:
if (packet.data)
compat_free_data_contents(context, &packet);
krb5_free_principal(context, princ);
return retval;
}
/* Free the memory for cache_name. Called by pam_end() */
void
cleanup_cache(pam_handle_t *pamh, void *data, int pam_end_status)
{
krb5_context pam_context;
krb5_ccache ccache;
if (krb5_init_context(&pam_context))
return;
ccache = (krb5_ccache) data;
(void) krb5_cc_destroy(pam_context, ccache);
krb5_free_context(pam_context);
}

View File

@ -0,0 +1,39 @@
# Copyright 2001 Mark R V Murray
# 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
.PATH: ${PAMDIR}/modules/pam_nologin
LIB= pam_nologin
SHLIB_NAME= pam_nologin.so
SRCS= pam_nologin.c
CFLAGS+= -Wall
CFLAGS+= -I${PAMDIR}/libpam/include
INTERNALLIB= yes
INTERNALSTATICLIB=yes
.include <bsd.lib.mk>

View File

@ -0,0 +1,39 @@
# Copyright 2001 Mark R V Murray
# 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
.PATH: ${PAMDIR}/modules/pam_rootok
LIB= pam_rootok
SHLIB_NAME= pam_rootok.so
SRCS= pam_rootok.c
CFLAGS+= -Wall
CFLAGS+= -I${PAMDIR}/libpam/include
INTERNALLIB= yes
INTERNALSTATICLIB=yes
.include <bsd.lib.mk>

View File

@ -0,0 +1,39 @@
# Copyright 2001 Mark R V Murray
# 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
.PATH: ${PAMDIR}/modules/pam_wheel
LIB= pam_wheel
SHLIB_NAME= pam_wheel.so
SRCS= pam_wheel.c
CFLAGS+= -Wall
CFLAGS+= -I${PAMDIR}/libpam/include
INTERNALLIB= yes
INTERNALSTATICLIB=yes
.include <bsd.lib.mk>