⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 digest.c

📁 samba最新软件
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (c) 2006 - 2007 Kungliga Tekniska H鰃skolan * (Royal Institute of Technology, Stockholm, Sweden).  * 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, this list of conditions and the following disclaimer.  * * 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. Neither the name of the Institute nor the names of its contributors  *    may be used to endorse or promote products derived from this software  *    without specific prior written permission.  * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``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 INSTITUTE OR CONTRIBUTORS 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.  */#include "kdc_locl.h"#include <hex.h>RCSID("$Id: digest.c 22374 2007-12-28 18:36:52Z lha $");#define MS_CHAP_V2	0x20#define CHAP_MD5	0x10#define DIGEST_MD5	0x08#define NTLM_V2		0x04#define NTLM_V1_SESSION	0x02#define NTLM_V1		0x01const struct units _kdc_digestunits[] = {	{"ms-chap-v2",		1U << 5},	{"chap-md5",		1U << 4},	{"digest-md5",		1U << 3},	{"ntlm-v2",		1U << 2},	{"ntlm-v1-session",	1U << 1},	{"ntlm-v1",		1U << 0},	{NULL,	0}};static krb5_error_codeget_digest_key(krb5_context context,	       krb5_kdc_configuration *config,	       hdb_entry_ex *server,	       krb5_crypto *crypto){    krb5_error_code ret;    krb5_enctype enctype;    Key *key;        ret = _kdc_get_preferred_key(context,				 config,				 server,				 "digest-service",				 &enctype,				 &key);    if (ret)	return ret;    return krb5_crypto_init(context, &key->key, 0, crypto);}/* * */static char *get_ntlm_targetname(krb5_context context,		    hdb_entry_ex *client){    char *targetname, *p;    targetname = strdup(krb5_principal_get_realm(context,						 client->entry.principal));    if (targetname == NULL)	return NULL;    p = strchr(targetname, '.');    if (p)	*p = '\0';    strupr(targetname);    return targetname;}static krb5_error_codefill_targetinfo(krb5_context context,		char *targetname,		hdb_entry_ex *client,		krb5_data *data){    struct ntlm_targetinfo ti;    krb5_error_code ret;    struct ntlm_buf d;    krb5_principal p;    const char *str;    memset(&ti, 0, sizeof(ti));    ti.domainname = targetname;    p = client->entry.principal;    str = krb5_principal_get_comp_string(context, p, 0);    if (str != NULL && 	(strcmp("host", str) == 0 || 	 strcmp("ftp", str) == 0 ||	 strcmp("imap", str) == 0 ||	 strcmp("pop", str) == 0 ||	 strcmp("smtp", str)))    {	str = krb5_principal_get_comp_string(context, p, 1);	ti.dnsservername = rk_UNCONST(str);    }        ret = heim_ntlm_encode_targetinfo(&ti, 1, &d);    if (ret)	return ret;    data->data = d.data;    data->length = d.length;    return 0;}static const unsigned char ms_chap_v2_magic1[39] = {    0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,    0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,    0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,    0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74};static const unsigned char ms_chap_v2_magic2[41] = {    0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,    0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,    0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,    0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,    0x6E};static const unsigned char ms_rfc3079_magic1[27] = {    0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,    0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,    0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79};/* * */static krb5_error_codeget_password_entry(krb5_context context,		   krb5_kdc_configuration *config,		   const char *username,		   char **password){    krb5_principal clientprincipal;    krb5_error_code ret;    hdb_entry_ex *user;    HDB *db;    /* get username */    ret = krb5_parse_name(context, username, &clientprincipal);    if (ret)	return ret;    ret = _kdc_db_fetch(context, config, clientprincipal,			HDB_F_GET_CLIENT, &db, &user);    krb5_free_principal(context, clientprincipal);    if (ret)	return ret;    ret = hdb_entry_get_password(context, db, &user->entry, password);    if (ret || password == NULL) {	if (ret == 0) {	    ret = EINVAL;	    krb5_set_error_string(context, "password missing");	}	memset(user, 0, sizeof(*user));    }    _kdc_free_ent (context, user);    return ret;}/* * */krb5_error_code_kdc_do_digest(krb5_context context, 	       krb5_kdc_configuration *config,	       const DigestREQ *req, krb5_data *reply,	       const char *from, struct sockaddr *addr){    krb5_error_code ret = 0;    krb5_ticket *ticket = NULL;    krb5_auth_context ac = NULL;    krb5_keytab id = NULL;    krb5_crypto crypto = NULL;    DigestReqInner ireq;    DigestRepInner r;    DigestREP rep;    krb5_flags ap_req_options;    krb5_data buf;    size_t size;    krb5_storage *sp = NULL;    Checksum res;    hdb_entry_ex *server = NULL, *user = NULL;    hdb_entry_ex *client = NULL;    char *client_name = NULL, *password = NULL;    krb5_data serverNonce;    if(!config->enable_digest) {	kdc_log(context, config, 0, 		"Rejected digest request (disabled) from %s", from);	return KRB5KDC_ERR_POLICY;    }    krb5_data_zero(&buf);    krb5_data_zero(reply);    krb5_data_zero(&serverNonce);    memset(&ireq, 0, sizeof(ireq));    memset(&r, 0, sizeof(r));    memset(&rep, 0, sizeof(rep));    kdc_log(context, config, 0, "Digest request from %s", from);    ret = krb5_kt_resolve(context, "HDB:", &id);    if (ret) {	kdc_log(context, config, 0, "Can't open database for digest");	goto out;    }    ret = krb5_rd_req(context, 		      &ac,		      &req->apReq,		      NULL,		      id,		      &ap_req_options,		      &ticket);    if (ret)	goto out;    /* check the server principal in the ticket matches digest/R@R */    {	krb5_principal principal = NULL;	const char *p, *r;	ret = krb5_ticket_get_server(context, ticket, &principal);	if (ret)	    goto out;	ret = EINVAL;	krb5_set_error_string(context, "Wrong digest server principal used");	p = krb5_principal_get_comp_string(context, principal, 0);	if (p == NULL) {	    krb5_free_principal(context, principal);	    goto out;	}	if (strcmp(p, KRB5_DIGEST_NAME) != 0) {	    krb5_free_principal(context, principal);	    goto out;	}	p = krb5_principal_get_comp_string(context, principal, 1);	if (p == NULL) {	    krb5_free_principal(context, principal);	    goto out;	}	r = krb5_principal_get_realm(context, principal);	if (r == NULL) {	    krb5_free_principal(context, principal);	    goto out;	}	if (strcmp(p, r) != 0) {	    krb5_free_principal(context, principal);	    goto out;	}	krb5_clear_error_string(context);	ret = _kdc_db_fetch(context, config, principal,			    HDB_F_GET_SERVER, NULL, &server);	if (ret)	    goto out;	krb5_free_principal(context, principal);    }    /* check the client is allowed to do digest auth */    {	krb5_principal principal = NULL;	ret = krb5_ticket_get_client(context, ticket, &principal);	if (ret)	    goto out;	ret = krb5_unparse_name(context, principal, &client_name);	if (ret) {	    krb5_free_principal(context, principal);	    goto out;	}	ret = _kdc_db_fetch(context, config, principal,			    HDB_F_GET_CLIENT, NULL, &client);	krb5_free_principal(context, principal);	if (ret)	    goto out;	if (client->entry.flags.allow_digest == 0) {	    kdc_log(context, config, 0, 		    "Client %s tried to use digest "		    "but is not allowed to", 		    client_name);	    krb5_set_error_string(context, 				  "Client is not permitted to use digest");	    ret = KRB5KDC_ERR_POLICY;	    goto out;	}    }    /* unpack request */    {	krb5_keyblock *key;	ret = krb5_auth_con_getremotesubkey(context, ac, &key);	if (ret)	    goto out;	if (key == NULL) {	    krb5_set_error_string(context, "digest: remote subkey not found");	    ret = EINVAL;	    goto out;	}	ret = krb5_crypto_init(context, key, 0, &crypto);	krb5_free_keyblock (context, key);	if (ret)	    goto out;    }    ret = krb5_decrypt_EncryptedData(context, crypto, KRB5_KU_DIGEST_ENCRYPT,				     &req->innerReq, &buf);    krb5_crypto_destroy(context, crypto);    crypto = NULL;    if (ret)	goto out;	       ret = decode_DigestReqInner(buf.data, buf.length, &ireq, NULL);    krb5_data_free(&buf);    if (ret) {	krb5_set_error_string(context, "Failed to decode digest inner request");	goto out;    }    kdc_log(context, config, 0, "Valid digest request from %s (%s)", 	    client_name, from);    /*     * Process the inner request     */    switch (ireq.element) {    case choice_DigestReqInner_init: {	unsigned char server_nonce[16], identifier;	RAND_pseudo_bytes(&identifier, sizeof(identifier));	RAND_pseudo_bytes(server_nonce, sizeof(server_nonce));	server_nonce[0] = kdc_time & 0xff;	server_nonce[1] = (kdc_time >> 8) & 0xff;	server_nonce[2] = (kdc_time >> 16) & 0xff;	server_nonce[3] = (kdc_time >> 24) & 0xff;	r.element = choice_DigestRepInner_initReply;	hex_encode(server_nonce, sizeof(server_nonce), &r.u.initReply.nonce);	if (r.u.initReply.nonce == NULL) {	    krb5_set_error_string(context, "Failed to decode server nonce");	    ret = ENOMEM;	    goto out;	}	sp = krb5_storage_emem();	if (sp == NULL) {	    ret = ENOMEM;	    krb5_set_error_string(context, "out of memory");	    goto out;	}	ret = krb5_store_stringz(sp, ireq.u.init.type);	if (ret) {	    krb5_clear_error_string(context);	    goto out;	}	if (ireq.u.init.channel) {	    char *s;	    asprintf(&s, "%s-%s:%s", r.u.initReply.nonce,		     ireq.u.init.channel->cb_type,		     ireq.u.init.channel->cb_binding);	    if (s == NULL) {		krb5_set_error_string(context, "Failed to allocate "				      "channel binding");		ret = ENOMEM;		goto out;	    }	    free(r.u.initReply.nonce);	    r.u.initReply.nonce = s;	}		ret = krb5_store_stringz(sp, r.u.initReply.nonce);	if (ret) {	    krb5_clear_error_string(context);	    goto out;	}	if (strcasecmp(ireq.u.init.type, "CHAP") == 0) {	    r.u.initReply.identifier = 		malloc(sizeof(*r.u.initReply.identifier));	    if (r.u.initReply.identifier == NULL) {		krb5_set_error_string(context, "out of memory");		ret = ENOMEM;		goto out;	    }	    asprintf(r.u.initReply.identifier, "%02X", identifier & 0xff);	    if (*r.u.initReply.identifier == NULL) {		krb5_set_error_string(context, "out of memory");		ret = ENOMEM;		goto out;	    }	} else	    r.u.initReply.identifier = NULL;	if (ireq.u.init.hostname) {	    ret = krb5_store_stringz(sp, *ireq.u.init.hostname);	    if (ret) {		krb5_clear_error_string(context);		goto out;	    }	}	ret = krb5_storage_to_data(sp, &buf);	if (ret) {	    krb5_clear_error_string(context);	    goto out;	}	ret = get_digest_key(context, config, server, &crypto);	if (ret)	    goto out;	ret = krb5_create_checksum(context,				   crypto,				   KRB5_KU_DIGEST_OPAQUE,				   0,				   buf.data,				   buf.length,				   &res);	krb5_crypto_destroy(context, crypto);	crypto = NULL;	krb5_data_free(&buf);	if (ret)	    goto out;		ASN1_MALLOC_ENCODE(Checksum, buf.data, buf.length, &res, &size, ret);	free_Checksum(&res);	if (ret) {	    krb5_set_error_string(context, "Failed to encode "				  "checksum in digest request");	    goto out;	}	if (size != buf.length)	    krb5_abortx(context, "ASN1 internal error");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -