mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-17 10:26:15 +00:00
Clean up this module very extensively. Fix the logging, the coding
standards and the option handling. This module is now much more easy to maintain as a part of the FreeBSD tree.
This commit is contained in:
parent
530ebf8e0a
commit
3938427761
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=81477
@ -1,195 +0,0 @@
|
||||
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.
|
||||
|
||||
|
@ -26,8 +26,7 @@
|
||||
|
||||
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
|
||||
SRCS= pam_krb5.c
|
||||
DPADD= ${LIBKRB5} ${LIBGSSAPI} ${LIBASN1} ${LIBCRYPTO} ${LIBCRYPT} \
|
||||
${LIBCOM_ERR} ${LIBROKEN}
|
||||
LDADD= -lkrb5 -lgssapi -lasn1 -lcrypto -lcrypt -lcom_err \
|
||||
|
@ -1,72 +0,0 @@
|
||||
$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?
|
||||
It would be fairly easy to support 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.
|
||||
|
@ -1,16 +0,0 @@
|
||||
$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 **
|
||||
|
@ -1,133 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
heimdal_pam_prompter(krb5_context context, void *data, const char *name,
|
||||
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;
|
1100
lib/libpam/modules/pam_krb5/pam_krb5.c
Normal file
1100
lib/libpam/modules/pam_krb5/pam_krb5.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,21 +0,0 @@
|
||||
/*
|
||||
* 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 *);
|
||||
|
||||
#ifndef ENCTYPE_DES_CBC_MD5
|
||||
#define ENCTYPE_DES_CBC_MD5 ETYPE_DES_CBC_MD5
|
||||
#endif
|
||||
|
||||
|
@ -1,83 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
}
|
||||
|
@ -1,475 +0,0 @@
|
||||
/*
|
||||
* 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 *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;
|
||||
|
||||
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 */
|
||||
if ((krbret = krb5_parse_name(pam_context, name, &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);
|
||||
}
|
||||
|
||||
/* Verify the local user exists (AFTER getting the password) */
|
||||
if (strchr(name, '@')) {
|
||||
/* get a local account name for this principal */
|
||||
if ((krbret = krb5_aname_to_localname(pam_context, princ,
|
||||
sizeof(lname), lname)) != 0) {
|
||||
DLOG("krb5_aname_to_localname()", error_message(krbret));
|
||||
pamret = PAM_USER_UNKNOWN;
|
||||
goto cleanup2;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
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)
|
||||
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) {
|
||||
DLOG("pam_get_data()", pam_strerror(pamh, pamret));
|
||||
pamret = PAM_CRED_UNAVAIL;
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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_resolve(pam_context, cache_name, &ccache_perm))
|
||||
!= 0) {
|
||||
DLOG("krb5_cc_resolve()", error_message(krbret));
|
||||
pamret = PAM_SERVICE_ERR;
|
||||
goto cleanup2;
|
||||
}
|
||||
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 = krb5_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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -1,200 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
@ -1,28 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
@ -1,185 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user