mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Whe requesting a keytab the salt used is the NORMAL type (for backwards and AD compatibility), however since we added alias support we need to search for the krbCanonicalName in preference, hen nothing is specified, and for the requested principal name when a getkeytab operation is performed. This is so that the correct salt can be applied. (Windows AD uses some peculiar aliases for some special accounts to generate the salt). Signed-off-by: Simo Sorce <simo@redhat.com> Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
289 lines
8.7 KiB
C
289 lines
8.7 KiB
C
/** BEGIN COPYRIGHT BLOCK
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Additional permission under GPLv3 section 7:
|
|
*
|
|
* In the following paragraph, "GPL" means the GNU General Public
|
|
* License, version 3 or any later version, and "Non-GPL Code" means
|
|
* code that is governed neither by the GPL nor a license
|
|
* compatible with the GPL.
|
|
*
|
|
* You may link the code of this Program with Non-GPL Code and convey
|
|
* linked combinations including the two, provided that such Non-GPL
|
|
* Code only links to the code of this Program through those well
|
|
* defined interfaces identified in the file named EXCEPTION found in
|
|
* the source code files (the "Approved Interfaces"). The files of
|
|
* Non-GPL Code may instantiate templates or use macros or inline
|
|
* functions from the Approved Interfaces without causing the resulting
|
|
* work to be covered by the GPL. Only the copyright holders of this
|
|
* Program may make changes or additions to the list of Approved
|
|
* Interfaces.
|
|
*
|
|
* Authors:
|
|
* Simo Sorce <ssorce@redhat.com>
|
|
*
|
|
* Copyright (C) 2007-2010 Red Hat, Inc.
|
|
* All rights reserved.
|
|
* END COPYRIGHT BLOCK **/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
|
|
#include <dirsrv/slapi-plugin.h>
|
|
#include <lber.h>
|
|
#include <time.h>
|
|
|
|
#include <endian.h>
|
|
|
|
#include "ipapwd.h"
|
|
#include "util.h"
|
|
#include "ipa_krb5.h"
|
|
|
|
/* krbTicketFlags */
|
|
#define KTF_DISALLOW_POSTDATED 0x00000001
|
|
#define KTF_DISALLOW_FORWARDABLE 0x00000002
|
|
#define KTF_DISALLOW_TGT_BASED 0x00000004
|
|
#define KTF_DISALLOW_RENEWABLE 0x00000008
|
|
#define KTF_DISALLOW_PROXIABLE 0x00000010
|
|
#define KTF_DISALLOW_DUP_SKEY 0x00000020
|
|
#define KTF_DISALLOW_ALL_TIX 0x00000040
|
|
#define KTF_REQUIRES_PRE_AUTH 0x00000080
|
|
#define KTF_REQUIRES_HW_AUTH 0x00000100
|
|
#define KTF_REQUIRES_PWCHANGE 0x00000200
|
|
#define KTF_DISALLOW_SVR 0x00001000
|
|
#define KTF_PWCHANGE_SERVICE 0x00002000
|
|
|
|
/* ascii hex output of bytes in "in"
|
|
* out len is 32 (preallocated)
|
|
* in len is 16 */
|
|
static const char hexchars[] = "0123456789ABCDEF";
|
|
static void hexbuf(char *out, const uint8_t *in)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
out[i*2] = hexchars[in[i] >> 4];
|
|
out[i*2+1] = hexchars[in[i] & 0x0f];
|
|
}
|
|
}
|
|
|
|
void ipapwd_keyset_free(struct ipapwd_keyset **pkset)
|
|
{
|
|
struct ipapwd_keyset *kset = *pkset;
|
|
int i;
|
|
|
|
if (!kset) return;
|
|
|
|
for (i = 0; i < kset->num_keys; i++) {
|
|
free(kset->keys[i].key_data_contents[0]);
|
|
free(kset->keys[i].key_data_contents[1]);
|
|
}
|
|
free(kset->keys);
|
|
free(kset);
|
|
*pkset = NULL;
|
|
}
|
|
|
|
Slapi_Value **ipapwd_encrypt_encode_key(struct ipapwd_krbcfg *krbcfg,
|
|
struct ipapwd_data *data,
|
|
char *preferred_principal,
|
|
int num_encsalts,
|
|
krb5_key_salt_tuple *encsalts,
|
|
char **errMesg)
|
|
{
|
|
krb5_context krbctx;
|
|
char *krbPrincipalName = NULL;
|
|
int kvno;
|
|
struct berval *bval = NULL;
|
|
Slapi_Value **svals = NULL;
|
|
krb5_principal princ = NULL;
|
|
krb5_error_code krberr;
|
|
krb5_data pwd = { 0 };
|
|
struct ipapwd_keyset *kset = NULL;
|
|
|
|
krbctx = krbcfg->krbctx;
|
|
|
|
svals = (Slapi_Value **)calloc(2, sizeof(Slapi_Value *));
|
|
if (!svals) {
|
|
LOG_OOM();
|
|
return NULL;
|
|
}
|
|
|
|
kvno = ipapwd_get_cur_kvno(data->target);
|
|
|
|
if (preferred_principal) {
|
|
krbPrincipalName = slapi_ch_strdup(preferred_principal);
|
|
} else {
|
|
krbPrincipalName = slapi_entry_attr_get_charptr(data->target,
|
|
"krbCanonicalName");
|
|
if (!krbPrincipalName) {
|
|
krbPrincipalName = slapi_entry_attr_get_charptr(data->target,
|
|
"krbPrincipalName");
|
|
}
|
|
if (!krbPrincipalName) {
|
|
*errMesg = "no krbPrincipalName present in this entry\n";
|
|
LOG_FATAL("%s", *errMesg);
|
|
goto enc_error;
|
|
}
|
|
}
|
|
|
|
krberr = krb5_parse_name(krbctx, krbPrincipalName, &princ);
|
|
if (krberr) {
|
|
LOG_FATAL("krb5_parse_name failed [%s]\n",
|
|
krb5_get_error_message(krbctx, krberr));
|
|
goto enc_error;
|
|
}
|
|
|
|
if (data->password) {
|
|
pwd.data = (char *)data->password;
|
|
pwd.length = strlen(data->password);
|
|
}
|
|
|
|
kset = malloc(sizeof(struct ipapwd_keyset));
|
|
if (!kset) {
|
|
LOG_OOM();
|
|
goto enc_error;
|
|
}
|
|
|
|
/* this encoding assumes all keys have the same kvno */
|
|
/* major-vno = 1 and minor-vno = 1 */
|
|
kset->major_vno = 1;
|
|
kset->minor_vno = 1;
|
|
/* increment kvno (will be 1 if this is a new entry) */
|
|
kvno += 1;
|
|
kset->mkvno = krbcfg->mkvno;
|
|
|
|
krberr = ipa_krb5_generate_key_data(krbctx, princ,
|
|
pwd, kvno, krbcfg->kmkey,
|
|
num_encsalts, encsalts,
|
|
&kset->num_keys, &kset->keys);
|
|
if (krberr != 0) {
|
|
LOG_FATAL("generating kerberos keys failed [%s]\n",
|
|
krb5_get_error_message(krbctx, krberr));
|
|
goto enc_error;
|
|
}
|
|
|
|
krberr = ber_encode_krb5_key_data(kset->keys, kset->num_keys,
|
|
kset->mkvno, &bval);
|
|
if (krberr != 0) {
|
|
LOG_FATAL("encoding krb5_key_data failed\n");
|
|
goto enc_error;
|
|
}
|
|
|
|
svals[0] = slapi_value_new_berval(bval);
|
|
if (!svals[0]) {
|
|
LOG_FATAL("Converting berval to Slapi_Value\n");
|
|
goto enc_error;
|
|
}
|
|
|
|
ipapwd_keyset_free(&kset);
|
|
krb5_free_principal(krbctx, princ);
|
|
slapi_ch_free_string(&krbPrincipalName);
|
|
ber_bvfree(bval);
|
|
return svals;
|
|
|
|
enc_error:
|
|
*errMesg = "key encryption/encoding failed\n";
|
|
if (kset) ipapwd_keyset_free(&kset);
|
|
krb5_free_principal(krbctx, princ);
|
|
slapi_ch_free_string(&krbPrincipalName);
|
|
if (bval) ber_bvfree(bval);
|
|
free(svals);
|
|
return NULL;
|
|
}
|
|
|
|
int ipapwd_gen_hashes(struct ipapwd_krbcfg *krbcfg,
|
|
struct ipapwd_data *data, char *userpw,
|
|
int is_krb, int is_smb, int is_ipant, Slapi_Value ***svals,
|
|
char **nthash, Slapi_Value ***ntvals,
|
|
char **errMesg)
|
|
{
|
|
int rc;
|
|
|
|
*svals = NULL;
|
|
*nthash = NULL;
|
|
*errMesg = NULL;
|
|
|
|
if (is_krb) {
|
|
|
|
*svals = ipapwd_encrypt_encode_key(krbcfg, data, NULL,
|
|
krbcfg->num_pref_encsalts,
|
|
krbcfg->pref_encsalts,
|
|
errMesg);
|
|
|
|
if (!*svals) {
|
|
/* errMesg should have been set in encrypt_encode_key() */
|
|
LOG_FATAL("key encryption/encoding failed\n");
|
|
rc = LDAP_OPERATIONS_ERROR;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if (is_smb || is_ipant) {
|
|
char nt[33];
|
|
uint8_t nt_key[16];
|
|
int ret;
|
|
|
|
if (krbcfg->allow_nt_hash) {
|
|
ret = encode_nt_key(userpw, nt_key);
|
|
if (ret) {
|
|
*errMesg = "Failed to generate NT/LM hashes\n";
|
|
LOG_FATAL("%s", *errMesg);
|
|
rc = LDAP_OPERATIONS_ERROR;
|
|
goto done;
|
|
}
|
|
|
|
hexbuf(nt, nt_key);
|
|
nt[32] = '\0';
|
|
*nthash = slapi_ch_strdup(nt);
|
|
} else {
|
|
memset(nt_key, 0, 16);
|
|
}
|
|
|
|
if (is_ipant) {
|
|
*ntvals = (Slapi_Value **)calloc(2, sizeof(Slapi_Value *));
|
|
if (!*ntvals) {
|
|
LOG_OOM();
|
|
rc = LDAP_OPERATIONS_ERROR;
|
|
goto done;
|
|
}
|
|
(*ntvals)[0] = slapi_value_new();
|
|
if (slapi_value_set((*ntvals)[0], nt_key, 16) == NULL) {
|
|
rc = LDAP_OPERATIONS_ERROR;
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
|
|
rc = LDAP_SUCCESS;
|
|
|
|
done:
|
|
|
|
/* when error, free possibly allocated output parameters */
|
|
if (rc) {
|
|
ipapwd_free_slapi_value_array(svals);
|
|
ipapwd_free_slapi_value_array(ntvals);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|