krb5_setcred.c revision 1dac1dbeded98196daeb327ed4397f184bc87342
/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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 <krb5.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <com_err.h>
#include "utils.h"
#include "krb5_repository.h"
#define PAMTXD "SUNW_OST_SYSOSPAM"
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);
const krb5_creds *);
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;
int result;
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 (result);
}
return (PAM_SYSTEM_ERR);
}
} else {
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,
};
/* User must have passed pam_authenticate() */
"PAM-KRB5 (setcred): unable to "
"setcreds, not authenticated!");
return (PAM_CRED_UNAVAIL);
}
/* 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_ESTABLISH_CRED - Create a new cred cache if one doesnt exist,
* else refresh the existing one.
* PAM_REINITIALIZE_CRED - destroy current cred cache and create a new one
* PAM_REFRESH_CRED - update the existing cred cache (default action)
*/
static krb5_error_code
int flag)
{
char *client_name = NULL;
typedef struct _cred_node {
struct _cred_node *next;
} cred_node;
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 "
if ((retval == KRB5_FCC_NOFILE) &&
/*
* Create a fresh ccache, and store the credentials
* we got from pam_authenticate()
*/
"PAM-KRB5 (setcred): krb5_cc_initialize "
"failed: %s",
goto cleanup_creds;
"PAM-KRB5 (setcred): krb5_cc_store_cred "
"failed: %s",
goto cleanup_creds;
}
} else if (retval) {
/*
* 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)",
} else if (flag & PAM_REINITIALIZE_CRED) {
/*
* This destroys the credential cache, and stores a new
* krbtgt with updated startime, endtime and renewable
* lifetime.
*/
"PAM-KRB5 (setcred): krb5_get_credentials",
"_renew(reinitialize) failed: %s",
/* perhaps the tgt lifetime has expired */
goto cleanup_creds;
goto cleanup_creds;
}
}
} else {
/*
* Creds already exist, update them if possible.
* We got here either with the ESTABLISH or REFRESH flag.
*
* The credential cache does exist, and we are going to
* read in each cred, looking for our own. When we find
* a matching credential, we will update it, and store it.
* Any nonmatching credentials are stored as is.
*
* Rules:
* TGT must exist in cache to get to this point.
* if flag == ESTABLISH
* refresh it if possible, else overwrite
* with new TGT, other tickets in cache remain
* unchanged.
* else if flag == REFRESH
* refresh it if possible, else return error.
* - Will not work if "R" flag is not set in
* original cred, we dont want to 2nd guess the
* intention of the person who created the
* existing TGT.
*
*/
goto cleanup_creds;
/* if two creds match, we just update the first */
/*
* Mark it as found, don't store it
* in the list or else it will be
* stored twice later.
*/
found = 1;
} else {
/*
* Add a new node to the list
* of creds that must be replaced
* in the cache later.
*/
sizeof (cred_node));
goto cleanup_creds;
}
if (cred_list_head == NULL) {
} else {
}
if (retval)
goto cleanup_creds;
}
}
goto cleanup_creds;
/*
* If we found a matching cred, renew it.
* This destroys the credential cache, if and only
* if it passes.
*/
if (found &&
"PAM-KRB5 (setcred): krb5_get_credentials"
"_renew(update) 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. If we were trying to
* establish new creds, add them to the cache.
*/
goto cleanup_creds;
goto cleanup_creds;
}
}
/*
* If no matching creds were found, we must
* initialize the cache before we can store stuff
* in it.
*/
if (!found) {
goto cleanup_creds;
}
}
/* now store all the other tickets */
if (retval) {
"PAM-KRB5(setcred): krb5_cc_store_cred() "
"failed: %s",
goto cleanup_creds;
}
}
}
/* Cleanup the list of creds read from the cache if necessary */
/* Free the contents and the cred structure itself */
}
/*
* Credential update was successful!
*
* combination, if its a FILE based ccache.
*/
*tmpname = '\0';
"PAM-KRB5 (setcred): Unable to "
username);
goto error;
}
!(filepath+1)) {
"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
"PAM-KRB5 (setcred): kwarn_add_warning"
" failed: ktkt_warnd(1M) down?");
}
}
if (renewed_cred != NULL)
if (client_name != NULL)
return (retval);
}
static krb5_boolean
const krb5_creds *creds)
{
}
/*
* Delete the user's credentials for this session
*/
static int
{
return (PAM_SUCCESS);
"PAM-KRB5 (setcred): deleting user's "
"credentials (initcreds)");
}
return (PAM_SUCCESS);
}