/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <libintl.h>
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <pwd.h>
#include <syslog.h>
#include <libintl.h>
#include <k5-int.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <com_err.h>
#include "utils.h"
#include "krb5_repository.h"
extern void krb5_cleanup(pam_handle_t *, void *, int);
static int attempt_refresh_cred(krb5_module_data_t *, char *, int);
static int attempt_delete_initcred(krb5_module_data_t *);
krb5_principal, int);
extern uint_t kwarn_add_warning(char *, int);
extern uint_t kwarn_del_warning(char *);
/*
* pam_sm_setcred
*/
int
int flags,
int argc,
const char **argv)
{
int i;
int err = 0;
int debug = 0;
for (i = 0; i < argc; i++) {
debug = 1;
}
if (debug)
"PAM-KRB5 (setcred): start: nowarn = %d, flags = 0x%x",
/* make sure flags are valid */
if (flags &&
!(flags & PAM_ESTABLISH_CRED) &&
!(flags & PAM_REINITIALIZE_CRED) &&
!(flags & PAM_REFRESH_CRED) &&
!(flags & PAM_DELETE_CRED) &&
!(flags & PAM_SILENT)) {
"PAM-KRB5 (setcred): illegal flag %d", flags);
goto out;
}
return (PAM_USER_UNKNOWN);
if (debug) {
"PAM-KRB5 (setcred): kmd get failed, kmd=0x%p",
kmd);
}
/*
* User doesn't need to authenticate for PAM_REFRESH_CRED
* or for PAM_DELETE_CRED
*/
"PAM-KRB5 (setcred): inst kmd structure");
return (PAM_BUF_ERR);
/*
* Need to initialize auth_status here to
* PAM_AUTHINFO_UNAVAIL else there is a false positive
* of PAM_SUCCESS.
*/
return (PAM_SYSTEM_ERR);
}
} else {
/*
* This could mean that we are not the account authority
* for the authenticated user. Therefore we should
* return PAM_IGNORE in order to not affect the
* login process of said user.
*/
err = PAM_IGNORE;
goto out;
}
} else { /* pam_get_data success */
if (debug) {
"PAM-KRB5 (setcred): kmd structure"
" gotten but is NULL for user %s", user);
}
goto out;
}
if (debug)
"PAM-KRB5 (setcred): kmd auth_status: %s",
/*
* pam_auth has set status to ignore, so we also return ignore
*/
err = PAM_IGNORE;
goto out;
}
}
/*
* User must have passed pam_authenticate()
* in order to use PAM_ESTABLISH_CRED or PAM_REINITIALIZE_CRED
*/
"PAM-KRB5 (setcred): unable to "
"setcreds, not authenticated!");
return (PAM_CRED_UNAVAIL);
}
/*
* We cannot assume that kmd->kcontext being non-NULL
* means it is valid. Other pam_krb5 mods may have
* freed it but not reset it to NULL.
* Log a message when debugging to track down memory
* leaks.
*/
"PAM-KRB5 (setcred): kcontext != NULL, "
"possible memory leak.");
/*
* Use the authenticated and validated user, if applicable.
*/
/*
* If auth was short-circuited we will not have anything to
* renew, so just return here.
*/
if (debug)
"PAM-KRB5 (setcred): wrong"
"repository found (%s), returning "
return (PAM_IGNORE);
}
if (debug)
"PAM-KRB5 (setcred): "
"Principal %s already "
"authenticated, "
"cannot setcred",
return (PAM_SUCCESS);
}
}
}
if (flags & PAM_REINITIALIZE_CRED)
else if (flags & PAM_REFRESH_CRED)
else if (flags & PAM_DELETE_CRED)
else {
/*
* Default case: PAM_ESTABLISH_CRED
*/
}
if (err != PAM_SUCCESS)
"PAM-KRB5 (setcred): pam_setcred failed "
out:
/*
* free 'kcontext' field if it is allocated,
* kcontext is local to the operation being performed
* not considered global to the entire pam module.
*/
}
/*
* 'kmd' is not freed here, it is handled in krb5_cleanup
*/
if (debug)
"PAM-KRB5 (setcred): end: %s",
return (err);
}
static int
char *user,
int flag)
{
0,
};
/* Create a new context here. */
"PAM-KRB5 (setcred): unable to "
"initialize krb5 context");
return (PAM_SYSTEM_ERR);
}
return (PAM_SYSTEM_ERR);
}
2*MAXHOSTNAMELEN)) != 0) {
return (code);
}
return (PAM_SYSTEM_ERR);
}
return (PAM_SYSTEM_ERR);
}
if (code) {
"PAM-KRB5(setcred): krb5_renew_tgt() "
return (PAM_CRED_ERR);
} else {
return (PAM_SUCCESS);
}
}
/*
* This code will update the credential matching "server" in the user's
* credential cache. The flag may be set to one of:
* PAM_REINITIALIZE_CRED/PAM_ESTABLISH_CRED - If we have new credentials then
* create a new cred cache with these credentials else return failure.
* PAM_REFRESH_CRED - If we have new credentials then create a new cred cache
* with these credentials else attempt to renew the credentials.
*
* Note for any of the flags that if a new credential does exist from the
* previous auth pass then this will overwrite any existing credentials in the
* credential cache.
*/
static krb5_error_code
int flag)
{
if ((flag != PAM_REFRESH_CRED) &&
(flag != PAM_REINITIALIZE_CRED) &&
(flag != PAM_ESTABLISH_CRED))
return (KRB5KRB_ERR_GENERIC);
/* this is needed only for the ktkt_warnd */
return (retval);
"PAM-KRB5 (setcred): krb5_copy_principal "
"failed: %s",
goto cleanup_creds;
}
/* obtain ticket & session key */
"PAM-KRB5 (setcred): User not in cred "
/*
* We got here either with the ESTABLISH | REINIT | REFRESH flag and
* auth_status returns SUCCESS or REFRESH and auth_status failure.
*
* Rules:
* - If the prior auth pass was successful then store the new
* credentials in the cache, regardless of which flag.
*
* - Else if REFRESH flag is used and there are no new
* credentials then attempt to refresh the existing credentials.
*
* - Note, refresh will not work if "R" flag is not set in
* original credential. We don't want to 2nd guess the
* intention of the person who created the existing credential.
*/
/*
* Create a fresh ccache, and store the credentials
* we got from pam_authenticate()
*/
"PAM-KRB5 (setcred): krb5_cc_initialize "
"failed: %s",
"PAM-KRB5 (setcred): krb5_cc_store_cred "
"failed: %s",
}
/*
* If we only wanted to refresh the creds but failed
* due to expiration, lack of "R" flag, or other
* problems, return an error.
*/
"PAM-KRB5 (setcred): "
"krb5_get_credentials"
"_renew(update) failed: %s",
}
}
} else {
/*
* We failed to get the user's credentials.
* This might be due to permission error on the cache,
* or maybe we are looking in the wrong cache file!
*/
"PAM-KRB5 (setcred): Cannot find creds"
" for %s (%s)",
}
/*
* Credential update was successful!
*
* combination, if its a FILE based ccache.
*/
"PAM-KRB5 (setcred): Out of memory");
goto error;
}
*tmpname = '\0';
"PAM-KRB5 (setcred): Unable to "
username);
goto error;
}
"%s=FILE:/tmp/krb5cc_%d", KRB5_ENV_CCNAME,
goto error;
}
/*
* We MUST copy this to the heap for the putenv
* to work!
*/
goto error;
} else {
goto error;
}
}
}
/*
* We know at this point that kmd->env must start
* with the literal string "FILE:". Set filepath
* character string to point to ":"
*/
/*
* Now check if first char after ":" is null char
*/
"PAM-KRB5 (setcred): Invalid pathname "
"for credential cache of user `%s'",
username);
goto error;
}
"PAM-KRB5 (setcred): chown to user "
"`%s' failed for FILE=%s",
}
}
}
if (retval == 0) {
else
if (kwarn_del_warning(client_name) != 0) {
"PAM-KRB5 (setcred): kwarn_del_warning"
" failed: ktkt_warnd(1M) down?");
}
"PAM-KRB5 (setcred): kwarn_add_warning"
" failed: ktkt_warnd(1M) down?");
}
}
if (renewed_cred != NULL)
if (client_name != NULL)
if (username)
return (retval);
}
/*
* Delete the user's credentials for this session
*/
static int
{
return (PAM_SUCCESS);
"PAM-KRB5 (setcred): deleting user's "
"credentials (initcreds)");
}
return (PAM_SUCCESS);
}