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

📄 krb5_setpw.c

📁 samba-3.0.22.tar.gz 编译smb服务器的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    Unix SMB/CIFS implementation.   krb5 set password implementation   Copyright (C) Andrew Tridgell 2001   Copyright (C) Remus Koos 2001 (remuskoos@yahoo.com)      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 2 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, write to the Free Software   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include "includes.h"#ifdef HAVE_KRB5#define DEFAULT_KPASSWD_PORT	464#define KRB5_KPASSWD_VERS_CHANGEPW		1#define KRB5_KPASSWD_VERS_SETPW			0xff80#define KRB5_KPASSWD_VERS_SETPW_ALT		2#define KRB5_KPASSWD_ACCESSDENIED		5#define KRB5_KPASSWD_BAD_VERSION		6#define KRB5_KPASSWD_INITIAL_FLAG_NEEDED	7/* Those are defined by kerberos-set-passwd-02.txt and are probably  * not supported by M$ implementation */#define KRB5_KPASSWD_POLICY_REJECT		8#define KRB5_KPASSWD_BAD_PRINCIPAL		9#define KRB5_KPASSWD_ETYPE_NOSUPP		10/* This implements kerberos password change protocol as specified in  * kerb-chg-password-02.txt and kerberos-set-passwd-02.txt * as well as microsoft version of the protocol  * as specified in kerberos-set-passwd-00.txt */static DATA_BLOB encode_krb5_setpw(const char *principal, const char *password){        char* princ_part1 = NULL;	char* princ_part2 = NULL;	char* realm = NULL;	char* c;	char* princ;	ASN1_DATA req;	DATA_BLOB ret;	princ = SMB_STRDUP(principal);	if ((c = strchr_m(princ, '/')) == NULL) {	    c = princ; 	} else {	    *c = '\0';	    c++;	    princ_part1 = princ;	}	princ_part2 = c;	if ((c = strchr_m(c, '@')) != NULL) {	    *c = '\0';	    c++;	    realm = c;	}	memset(&req, 0, sizeof(req));		asn1_push_tag(&req, ASN1_SEQUENCE(0));	asn1_push_tag(&req, ASN1_CONTEXT(0));	asn1_write_OctetString(&req, password, strlen(password));	asn1_pop_tag(&req);	asn1_push_tag(&req, ASN1_CONTEXT(1));	asn1_push_tag(&req, ASN1_SEQUENCE(0));	asn1_push_tag(&req, ASN1_CONTEXT(0));	asn1_write_Integer(&req, 1);	asn1_pop_tag(&req);	asn1_push_tag(&req, ASN1_CONTEXT(1));	asn1_push_tag(&req, ASN1_SEQUENCE(0));	if (princ_part1) 	    asn1_write_GeneralString(&req, princ_part1);		asn1_write_GeneralString(&req, princ_part2);	asn1_pop_tag(&req);	asn1_pop_tag(&req);	asn1_pop_tag(&req);	asn1_pop_tag(&req);	asn1_push_tag(&req, ASN1_CONTEXT(2));	asn1_write_GeneralString(&req, realm);	asn1_pop_tag(&req);	asn1_pop_tag(&req);	ret = data_blob(req.data, req.length);	asn1_free(&req);	free(princ);	return ret;}	static krb5_error_code build_kpasswd_request(uint16 pversion,					   krb5_context context,					   krb5_auth_context auth_context,					   krb5_data *ap_req,					   const char *princ,					   const char *passwd,					   krb5_data *packet){	krb5_error_code ret;	krb5_data cipherpw;	krb5_data encoded_setpw;	krb5_replay_data replay;	char *p;	DATA_BLOB setpw;	ret = krb5_auth_con_setflags(context,				     auth_context,KRB5_AUTH_CONTEXT_DO_SEQUENCE);	if (ret) {		DEBUG(1,("krb5_auth_con_setflags failed (%s)\n",			 error_message(ret)));		return ret;	}	/* handle protocol differences in chpw and setpw */	if (pversion  == KRB5_KPASSWD_VERS_CHANGEPW)		setpw = data_blob(passwd, strlen(passwd));	else if (pversion == KRB5_KPASSWD_VERS_SETPW ||		 pversion == KRB5_KPASSWD_VERS_SETPW_ALT)		setpw = encode_krb5_setpw(princ, passwd);	else		return EINVAL;	encoded_setpw.data = (char *)setpw.data;	encoded_setpw.length = setpw.length;	ret = krb5_mk_priv(context, auth_context,			   &encoded_setpw, &cipherpw, &replay);		data_blob_free(&setpw); 	/*from 'encode_krb5_setpw(...)' */		if (ret) {		DEBUG(1,("krb5_mk_priv failed (%s)\n", error_message(ret)));		return ret;	}	packet->data = (char *)SMB_MALLOC(ap_req->length + cipherpw.length + 6);	if (!packet->data)		return -1;	/* see the RFC for details */	p = ((char *)packet->data) + 2;	RSSVAL(p, 0, pversion);	p += 2;	RSSVAL(p, 0, ap_req->length);	p += 2;	memcpy(p, ap_req->data, ap_req->length);	p += ap_req->length;	memcpy(p, cipherpw.data, cipherpw.length);	p += cipherpw.length;	packet->length = PTR_DIFF(p,packet->data);	RSSVAL(packet->data, 0, packet->length);		free(cipherpw.data);    /* from 'krb5_mk_priv(...)' */	return 0;}static const struct kpasswd_errors {	int result_code;	const char *error_string;} kpasswd_errors[] = {	{KRB5_KPASSWD_MALFORMED, "Malformed request error"},	{KRB5_KPASSWD_HARDERROR, "Server error"},	{KRB5_KPASSWD_AUTHERROR, "Authentication error"},	{KRB5_KPASSWD_SOFTERROR, "Password change rejected"},	{KRB5_KPASSWD_ACCESSDENIED, "Client does not have proper authorization"},	{KRB5_KPASSWD_BAD_VERSION, "Protocol version not supported"},	{KRB5_KPASSWD_INITIAL_FLAG_NEEDED, "Authorization ticket must have initial flag set"},	{KRB5_KPASSWD_POLICY_REJECT, "Password rejected due to policy requirements"},	{KRB5_KPASSWD_BAD_PRINCIPAL, "Target principal does not exist"},	{KRB5_KPASSWD_ETYPE_NOSUPP, "Unsupported encryption type"},	{0, NULL}};static krb5_error_code setpw_result_code_string(krb5_context context,						int result_code,						const char **code_string){        unsigned int idx = 0;	while (kpasswd_errors[idx].error_string != NULL) {		if (kpasswd_errors[idx].result_code ==                     result_code) {			*code_string = kpasswd_errors[idx].error_string;			return 0;		}		idx++;	}	*code_string = "Password change failed";        return (0);}static krb5_error_code parse_setpw_reply(krb5_context context, 					 krb5_auth_context auth_context,					 krb5_data *packet){	krb5_data ap_rep;	char *p;	int vnum, ret, res_code;	krb5_data cipherresult;	krb5_data clearresult;	krb5_ap_rep_enc_part *ap_rep_enc;	krb5_replay_data replay;		if (packet->length < 4) {		return KRB5KRB_AP_ERR_MODIFIED;	}		p = packet->data;		if (((char *)packet->data)[0] == 0x7e || ((char *)packet->data)[0] == 0x5e) {		/* it's an error packet. We should parse it ... */		DEBUG(1,("Got error packet 0x%x from kpasswd server\n",			 ((char *)packet->data)[0]));		return KRB5KRB_AP_ERR_MODIFIED;	}		if (RSVAL(p, 0) != packet->length) {		DEBUG(1,("Bad packet length (%d/%d) from kpasswd server\n",			 RSVAL(p, 0), packet->length));		return KRB5KRB_AP_ERR_MODIFIED;	}	p += 2;	vnum = RSVAL(p, 0); p += 2;	/* FIXME: According to standard there is only one type of reply */		if (vnum != KRB5_KPASSWD_VERS_SETPW && 	    vnum != KRB5_KPASSWD_VERS_SETPW_ALT && 	    vnum != KRB5_KPASSWD_VERS_CHANGEPW) {		DEBUG(1,("Bad vnum (%d) from kpasswd server\n", vnum));		return KRB5KDC_ERR_BAD_PVNO;	}		ap_rep.length = RSVAL(p, 0); p += 2;		if (p + ap_rep.length >= (char *)packet->data + packet->length) {		DEBUG(1,("ptr beyond end of packet from kpasswd server\n"));		return KRB5KRB_AP_ERR_MODIFIED;	}		if (ap_rep.length == 0) {		DEBUG(1,("got unencrypted setpw result?!\n"));		return KRB5KRB_AP_ERR_MODIFIED;	}	/* verify ap_rep */	ap_rep.data = p;	p += ap_rep.length;		ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc);	if (ret) {		DEBUG(1,("failed to rd setpw reply (%s)\n", error_message(ret)));		return KRB5KRB_AP_ERR_MODIFIED;	}		krb5_free_ap_rep_enc_part(context, ap_rep_enc);		cipherresult.data = p;	cipherresult.length = ((char *)packet->data + packet->length) - p;			ret = krb5_rd_priv(context, auth_context, &cipherresult, &clearresult,			   &replay);	if (ret) {		DEBUG(1,("failed to decrypt setpw reply (%s)\n", error_message(ret)));		return KRB5KRB_AP_ERR_MODIFIED;	}	if (clearresult.length < 2) {	        free(clearresult.data);		ret = KRB5KRB_AP_ERR_MODIFIED;		return KRB5KRB_AP_ERR_MODIFIED;	}		p = clearresult.data;		res_code = RSVAL(p, 0);		free(clearresult.data);	if ((res_code < KRB5_KPASSWD_SUCCESS) || 	    (res_code > KRB5_KPASSWD_ETYPE_NOSUPP)) {		return KRB5KRB_AP_ERR_MODIFIED;	}	if(res_code == KRB5_KPASSWD_SUCCESS)			return 0;	else {		const char *errstr;		setpw_result_code_string(context, res_code, &errstr);		DEBUG(1, ("Error changing password: %s\n", errstr));		switch(res_code) {			case KRB5_KPASSWD_ACCESSDENIED:				return KRB5KDC_ERR_BADOPTION;			case KRB5_KPASSWD_INITIAL_FLAG_NEEDED:				return KRB5KDC_ERR_BADOPTION;				/* return KV5M_ALT_METHOD; MIT-only define */			case KRB5_KPASSWD_ETYPE_NOSUPP:				return KRB5KDC_ERR_ETYPE_NOSUPP;			case KRB5_KPASSWD_BAD_PRINCIPAL:				return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;			case KRB5_KPASSWD_POLICY_REJECT:				return KRB5KDC_ERR_POLICY;			default:				return KRB5KRB_ERR_GENERIC;		}	}}static ADS_STATUS do_krb5_kpasswd_request(krb5_context context,					  const char *kdc_host,					  uint16 pversion,					  krb5_creds *credsp,					  const char *princ,					  const char *newpw){	krb5_auth_context auth_context = NULL;	krb5_data ap_req, chpw_req, chpw_rep;	int ret, sock;	socklen_t addr_len;	struct sockaddr remote_addr, local_addr;	krb5_address local_kaddr, remote_kaddr;	ret = krb5_mk_req_extended(context, &auth_context, AP_OPTS_USE_SUBKEY,				   NULL, credsp, &ap_req);	if (ret) {		DEBUG(1,("krb5_mk_req_extended failed (%s)\n", error_message(ret)));		return ADS_ERROR_KRB5(ret);	}		sock = open_udp_socket(kdc_host, DEFAULT_KPASSWD_PORT);	if (sock == -1) {

⌨️ 快捷键说明

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