/*
* 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 1990 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. Furthermore if you modify this software you must label
* your software as modified software and not distribute it in such a
* fashion that it might be confused with the original M.I.T. software.
* 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.
*
*
* Initialize a credentials cache.
*/
#include <osconf.h>
#include <kerberosv5/krb5.h>
#include <kerberosv5/com_err.h>
#include <assert.h>
#include <stdio.h>
#include <syslog.h>
#include <strings.h>
#include <errno.h>
#include <libintl.h>
#include <smbsrv/libsmbns.h>
#include <smbns_krb.h>
static void smb_krb5_cfg_free_list(char **);
static char **smb_krb5_dup_servers(const char **, uint32_t);
/*
* Initialization routine for smb_krb5_cfg_t. See libsmbns.h for for info.
*/
{
return (EINVAL);
return (rc);
if (rc != 0) {
return (rc);
}
&cfg->kc_orig_drealm);
}
return (ENOMEM);
}
return (0);
}
/*
* Commit changes to krb5.conf upon request and release any allocated
* memory.
*/
{
int i;
return (0);
if (commit) {
return (EINVAL);
return (rc);
} else {
}
}
return (0);
}
/*
* Reconfigure the admin_server/kpasswd_server and the list of KDCs
* for the Kerberos realm that corresponds to the joined AD domain.
*
* If the existing krb5.conf doesn't contain any KDC entries, it probably
* means that admins would like Solaris Kerberos to find KDCs all by itself
* via DNS SRV RR lookups. In that case, no updates will be performed on the
* kdc entries.
*/
void
{
return;
return;
"smb_krb5_reconfig: unable to prioritize KDC(s)");
if (rc != 0) {
"smb_krb5_reconfig[%s]: initialization failed",
return;
}
if (rc != 0) {
"smb_krb5_reconfig[%s]: failed to update "
}
"kdc", &kdcs1);
if (rc != 0) {
"smbns_krb: failed to obtain KDC entries from %s",
/* commit master server changes only */
return;
}
/* No updates if KDCs are not defined. */
if (rc != 0) {
"smbns_krb: failed to update KDC entries");
}
}
/* commit both master server and kdc(s) changes */
}
/*
* Configure default realm.
*/
{
char *path;
path = smb_krb5_cfg_getpath();
return (rc);
return (rc);
}
return (rc);
}
return (0);
}
{
char *errval;
int verrcode;
return (EINVAL);
return (rc);
}
return (rc);
}
/*
* Populates the following relation-value pair in the
* [domain_realm] section of krb5.conf.
*
* .<AD domain> = <REALM>
* .<local DNS suffix> = <REALM>
*/
cfg->kc_fqdomain);
if ((rc = k5_profile_add_domain_mapping(
"failed to add domain-realm mappings for %s",
return (rc);
}
return (rc);
}
if (verrcode != K5_PROFILE_VAL_SUCCESS)
return (0);
}
/*
* the list of KDC entries.
* If not then try to auto-recover from the misconfiguration. Retries for at
* most SMB_KRB5_CFG_VALID_RETRIES number of times.
*/
{
int i, verrcode;
return (EINVAL);
for (i = 0; i < SMB_KRB5_CFG_VALID_RETRIES; i++) {
return (rc);
}
switch (verrcode) {
case K5_PROFILE_VAL_SUCCESS:
if (done) {
return (0);
}
if (!update_kdcs) {
if ((rc = k5_profile_add_realm_entry(
"failed to add KDC entries for %s",
return (rc);
}
}
if (!update_master) {
return (rc);
}
}
if (!cfg->kc_default)
break;
&drealm);
break;
/*FALLTHROUGH*/
if ((rc = k5_profile_set_libdefaults(
"failed to change default realm "
"from %s to %s",
} else {
"failed to set default realm to %s",
}
return (rc);
}
break;
case K5_PROFILE_VAL_NO_REALM:
if (rc != 0) {
"failed to remove %s realm from %s",
return (rc);
}
"failed to add %s realm to %s",
return (rc);
}
break;
/*
* Populates the following relation-value pair in the
* [domain_realm] section of krb5.conf.
*
* .<fqdn> = <REALM>
*/
cfg->kc_fqdomain);
if ((rc = k5_profile_add_domain_mapping(
"failed to add domain_realm entries for %s",
return (rc);
}
break;
if ((rc = k5_profile_add_realm_entry(
"failed to add KDC entries for %s",
return (rc);
}
break;
len)) != 0) {
return (rc);
}
break;
if ((rc = k5_profile_add_domain_mapping(
"failed to add domain_realm entries for %s",
return (rc);
}
break;
}
/*
* An error message will be generated outside the loop only if
* max retries is reached. Hence, the memory allocated
* for errval in the last iteration should not be released here.
*/
if (i + 1 != SMB_KRB5_CFG_VALID_RETRIES) {
}
}
} else {
verrcode);
}
/* deallocate the memory allocated for errval from the last iteration */
return (EINVAL);
}
/*
* Overwrite the value of kpasswd server and the value of admin server
* in krb5.conf.
*/
static errcode_t
{
return (EINVAL);
return (rc);
}
return (rc);
}
return (0);
}
char *
smb_krb5_cfg_getpath(void)
{
char *path;
return (path);
}
static void
{
int i;
return;
}
/*
* Obtain and cache an initial TGT ticket for the specified principal.
* TGT ticket can be obtained given the username and password or service
* principal name with a NULL password. In the latter case, keys for the
* specified service principal will be looked up from the local keytab
* prior to performing the KRB-AS exchange.
*
* For kinit to work in multiple realms environment, the principal name must be
* in this format: <username>@<REALM>
*
* The validate flag determines if validation of specified principal is
* performed.
*
* Returns 0 on success. Otherwise, returns -1.
*/
static int
{
return (0);
/*
* From this point on, we can goto cleanup because the key variables
* are initialized.
*/
if (rc) {
action = "smbns_krb: initializing context";
goto cleanup;
}
if (rc != 0) {
action = "smbns_krb: resolve default credentials cache";
goto cleanup;
}
/* Use specified name */
if (rc != 0) {
action = "smbns_krb: parsing principal name";
goto cleanup;
}
if (principal_passwd != NULL) {
action = "smbns_krb: getting initial credentials";
} else {
action = "smbns_krb: getting initial credentials via keytab";
goto cleanup;
}
if (rc != 0) {
if (rc == KRB5KRB_AP_ERR_BAD_INTEGRITY)
errmsg = "Password incorrect or key out of sync";
goto cleanup;
}
if (rc != 0) {
action = "smbns_krb: initializing cache";
goto cleanup;
}
if (rc != 0) {
action = "smbns_krb: storing credentials";
goto cleanup;
}
/* SUCCESS! */
if (rc != 0) {
else
}
}
if (me)
if (cc)
if (ctx)
return ((rc == 0) ? 0 : -1);
}
/*
* Obtain and cache an initial TGT ticket for the specified principal.
*
* Force kinit on the specified principal without validating the cache.
*/
int
{
}
/*
* Obtain and cache an initial TGT ticket for the specified principal.
*
* Validate the cache for the specified principal.
* Skip the Kerberos initial authentication if there is already a
* ccache for the specified principal.
*/
int
{
}
/*
* Invoke krb5_get_error_message() to generate a richer error message if
* a Kerberos context is established. Otherwise, a generic error message is
* logged.
*/
void
const char *fmt, ...)
{
const char *krbmsg;
if (loghd == 0)
else
}
/*
* smb_krb5_domain2realm
*
* Converts domain name into realm.
* Caller needs to free the memory returned for the realm.
*/
char *
{
char *realm;
return (NULL);
(void) smb_strupr(realm);
return (realm);
}
static char **
{
int i;
return (NULL);
return (NULL);
for (i = 0; i < count; i++) {
return (NULL);
}
}
return (dup);
}
/*
* Determine whether the specified ccache exists or not.
*/
{
}
/*
* Set SMB_KRB5_CCACHE4SYS as the default ccache.
*/
int
smb_krb5_ccache_init(void)
{
return (smb_krb5_ccache_set(SMB_KRB5_CCACHE4SYS));
}
/*
* Ensure the directory for the Kerberos ccache file exists and construct
* the path with the specified filename and set KRB5CCNAME environment variable
* accordingly.
*/
int
{
return (-1);
}
return (-1);
}
return (0);
}
/*
* Blow away the specified ccache.
*
* If the path argument is set to SMB_KRB5_USE_DEFAULT_CCACHE, this function
* will derive the actual path based on KRB5CCNAME value.
*/
void
{
if (path == SMB_KRB5_USE_DEFAULT_CCACHE)
}
/*
* Remove both the user and computer ccache files.
*/
void
{
}
/*
* If the path argument is set to SMB_KRB5_USE_DEFAULT_CCACHE, this
* function will derive the actual path based on KRB5CCNAME value.
* Ticket lifetime is not validated in this function as Kerberos mechanism
* will automatically renew an expired tickets.
*/
{
char *cached_principal;
if (path == SMB_KRB5_USE_DEFAULT_CCACHE)
if (!smb_krb5_ccache_exist(path))
return (B_FALSE);
"Kerberos context initialization failed");
return (B_FALSE);
}
"resolve default credentials cache");
return (B_FALSE);
}
"unable to obtain default client principal");
return (B_FALSE);
}
"Fail to convert Kerbeoros principal to string");
return (B_FALSE);
}
return (valid);
}