Merge pull request #138 from abartlet/lorikeet-heimdal-for-upstream
Samba Cross-realm support patches from metze These patches were posted to heimdal-discuss by metze, and there were no objections there.
This commit is contained in:
		
							
								
								
									
										1067
									
								
								doc/standardisation/rfc6806.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1067
									
								
								doc/standardisation/rfc6806.txt
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										44
									
								
								kdc/fast.c
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								kdc/fast.c
									
									
									
									
									
								
							| @@ -244,8 +244,9 @@ _kdc_fast_mk_error(krb5_context context, | ||||
| 		   const KDC_REQ_BODY *req_body, | ||||
| 		   krb5_error_code outer_error, | ||||
| 		   const char *e_text, | ||||
| 		   krb5_principal error_client, | ||||
| 		   krb5_principal error_server, | ||||
| 		   const PrincipalName *error_client_name, | ||||
| 		   const Realm *error_client_realm, | ||||
| 		   time_t *csec, int *cusec, | ||||
| 		   krb5_data *error_msg) | ||||
| { | ||||
| @@ -264,15 +265,16 @@ _kdc_fast_mk_error(krb5_context context, | ||||
| 	     | ||||
| 	/* first add the KRB-ERROR to the fast errors */ | ||||
|  | ||||
| 	ret = krb5_mk_error(context, | ||||
| 			    outer_error, | ||||
| 			    e_text, | ||||
| 			    NULL, | ||||
| 			    error_client, | ||||
| 			    error_server, | ||||
| 			    NULL, | ||||
| 			    NULL, | ||||
| 			    &e_data); | ||||
| 	ret = krb5_mk_error_ext(context, | ||||
| 				outer_error, | ||||
| 				e_text, | ||||
| 				NULL, | ||||
| 				error_server, | ||||
| 				error_client_name, | ||||
| 				error_client_realm, | ||||
| 				NULL, | ||||
| 				NULL, | ||||
| 				&e_data); | ||||
| 	if (ret) | ||||
| 	    return ret; | ||||
|  | ||||
| @@ -285,7 +287,8 @@ _kdc_fast_mk_error(krb5_context context, | ||||
| 	} | ||||
|  | ||||
| 	if (/* hide_principal */ 0) { | ||||
| 	    error_client = NULL; | ||||
| 	    error_client_name = NULL; | ||||
| 	    error_client_realm = NULL; | ||||
| 	    error_server = NULL; | ||||
| 	    e_text = NULL; | ||||
| 	} | ||||
| @@ -325,15 +328,16 @@ _kdc_fast_mk_error(krb5_context context, | ||||
| 	    krb5_abortx(context, "internal asn.1 error"); | ||||
|     } | ||||
|      | ||||
|     ret = krb5_mk_error(context, | ||||
| 			outer_error, | ||||
| 			e_text, | ||||
| 			(e_data.length ? &e_data : NULL), | ||||
| 			error_client, | ||||
| 			error_server, | ||||
| 			csec, | ||||
| 			cusec, | ||||
| 			error_msg); | ||||
|     ret = krb5_mk_error_ext(context, | ||||
| 			    outer_error, | ||||
| 			    e_text, | ||||
| 			    (e_data.length ? &e_data : NULL), | ||||
| 			    error_server, | ||||
| 			    error_client_name, | ||||
| 			    error_client_realm, | ||||
| 			    csec, | ||||
| 			    cusec, | ||||
| 			    error_msg); | ||||
|     krb5_data_free(&e_data); | ||||
|  | ||||
|     return ret; | ||||
|   | ||||
| @@ -1712,6 +1712,31 @@ _kdc_as_rep(kdc_request_t r, | ||||
| 	kdc_log(context, config, 5, "client %s does not have secrets at this KDC, need to proxy", | ||||
| 		r->client_name); | ||||
| 	goto out; | ||||
|     } else if (ret == HDB_ERR_WRONG_REALM) { | ||||
| 	char *fixed_client_name = NULL; | ||||
|  | ||||
| 	ret = krb5_unparse_name(context, r->client->entry.principal, | ||||
| 				&fixed_client_name); | ||||
| 	if (ret) { | ||||
| 	    goto out; | ||||
| 	} | ||||
|  | ||||
| 	kdc_log(context, config, 0, "WRONG_REALM - %s -> %s", | ||||
| 		r->client_name, fixed_client_name); | ||||
| 	free(fixed_client_name); | ||||
|  | ||||
| 	ret = _kdc_fast_mk_error(context, r, | ||||
| 				 &error_method, | ||||
| 				 r->armor_crypto, | ||||
| 				 &req->req_body, | ||||
| 				 KRB5_KDC_ERR_WRONG_REALM, | ||||
| 				 NULL, | ||||
| 				 r->server_princ, | ||||
| 				 NULL, | ||||
| 				 &r->client->entry.principal->realm, | ||||
| 				 NULL, NULL, | ||||
| 				 reply); | ||||
| 	goto out; | ||||
|     } else if(ret){ | ||||
| 	const char *msg = krb5_get_error_message(context, ret); | ||||
| 	kdc_log(context, config, 0, "UNKNOWN -- %s: %s", r->client_name, msg); | ||||
| @@ -2193,13 +2218,15 @@ out: | ||||
|     /* | ||||
|      * In case of a non proxy error, build an error message. | ||||
|      */ | ||||
|     if(ret != 0 && ret != HDB_ERR_NOT_FOUND_HERE) { | ||||
|     if(ret != 0 && ret != HDB_ERR_NOT_FOUND_HERE && reply->length == 0) { | ||||
| 	ret = _kdc_fast_mk_error(context, r, | ||||
| 				 &error_method, | ||||
| 				 r->armor_crypto, | ||||
| 				 &req->req_body, | ||||
| 				 ret, r->e_text, | ||||
| 				 r->client_princ, r->server_princ, | ||||
| 				 r->server_princ, | ||||
| 				 &r->client_princ->name, | ||||
| 				 &r->client_princ->realm, | ||||
| 				 NULL, NULL, | ||||
| 				 reply); | ||||
| 	if (ret) | ||||
|   | ||||
| @@ -1121,15 +1121,14 @@ need_referral(krb5_context context, krb5_kdc_configuration *config, | ||||
|  | ||||
|     if (server->name.name_string.len == 1) | ||||
| 	name = server->name.name_string.val[0]; | ||||
|     else if (server->name.name_string.len == 3 && | ||||
| 	     strcasecmp("E3514235-4B06-11D1-AB04-00C04FC2DCD2", server->name.name_string.val[0]) == 0) { | ||||
|     else if (server->name.name_string.len == 3) { | ||||
| 	/* | ||||
| 	  This is used to give referrals for the | ||||
| 	  E3514235-4B06-11D1-AB04-00C04FC2DCD2/NTDSGUID/DNSDOMAIN | ||||
| 	  SPN form, which is used for inter-domain communication in AD | ||||
| 	 */ | ||||
| 	name = server->name.name_string.val[2]; | ||||
| 	kdc_log(context, config, 0, "Giving 3 part DRSUAPI referral for %s", name); | ||||
| 	kdc_log(context, config, 0, "Giving 3 part referral for %s", name); | ||||
| 	*realms = malloc(sizeof(char *)*2); | ||||
| 	if (*realms == NULL) { | ||||
| 	    krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); | ||||
| @@ -1648,6 +1647,32 @@ server_lookup: | ||||
|     if(ret == HDB_ERR_NOT_FOUND_HERE) { | ||||
| 	kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp); | ||||
| 	goto out; | ||||
|     } else if (ret == HDB_ERR_WRONG_REALM) { | ||||
| 	if (ref_realm) | ||||
| 	    free(ref_realm); | ||||
| 	ref_realm = strdup(server->entry.principal->realm); | ||||
| 	if (ref_realm == NULL) { | ||||
| 	    ret = ENOMEM; | ||||
| 	    goto out; | ||||
| 	} | ||||
|  | ||||
| 	kdc_log(context, config, 5, | ||||
| 		"Returning a referral to realm %s for " | ||||
| 		"server %s.", | ||||
| 		ref_realm, spn); | ||||
| 	krb5_free_principal(context, sp); | ||||
| 	sp = NULL; | ||||
| 	free(spn); | ||||
| 	spn = NULL; | ||||
| 	ret = krb5_make_principal(context, &sp, r, KRB5_TGS_NAME, | ||||
| 				  ref_realm, NULL); | ||||
| 	if (ret) | ||||
| 	    goto out; | ||||
| 	ret = krb5_unparse_name(context, sp, &spn); | ||||
| 	if (ret) | ||||
| 	    goto out; | ||||
|  | ||||
| 	goto server_lookup; | ||||
|     } else if(ret){ | ||||
| 	const char *new_rlm, *msg; | ||||
| 	Realm req_rlm; | ||||
| @@ -2457,6 +2482,7 @@ out: | ||||
| 				 NULL, | ||||
| 				 NULL, | ||||
| 				 ret, NULL, | ||||
| 				 NULL, | ||||
| 				 NULL, NULL, | ||||
| 				 csec, cusec, | ||||
| 				 data); | ||||
|   | ||||
| @@ -101,6 +101,13 @@ _kdc_db_fetch(krb5_context context, | ||||
| 	config->db[i]->hdb_close(context, config->db[i]); | ||||
|  | ||||
| 	switch (ret) { | ||||
| 	case HDB_ERR_WRONG_REALM: | ||||
| 	    /* | ||||
| 	     * the ent->entry.principal just contains hints for the client | ||||
| 	     * to retry. This is important for enterprise principal routing | ||||
| 	     * between trusts. | ||||
| 	     */ | ||||
| 	    /* fall through */ | ||||
| 	case 0: | ||||
| 	    if (db) | ||||
| 		*db = config->db[i]; | ||||
|   | ||||
| @@ -44,17 +44,43 @@ _gk_wrap_iov(OM_uint32 * minor_status, | ||||
| 	     gss_iov_buffer_desc *iov, | ||||
| 	     int iov_count) | ||||
| { | ||||
|   const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; | ||||
|   krb5_context context; | ||||
|     const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; | ||||
|     krb5_context context; | ||||
|     OM_uint32 ret; | ||||
|     krb5_keyblock *key; | ||||
|     krb5_keytype keytype; | ||||
|  | ||||
|   GSSAPI_KRB5_INIT (&context); | ||||
|     GSSAPI_KRB5_INIT (&context); | ||||
|  | ||||
|   if (ctx->more_flags & IS_CFX) | ||||
|       return _gssapi_wrap_cfx_iov(minor_status, ctx, context, | ||||
| 				  conf_req_flag, conf_state, | ||||
| 				  iov, iov_count); | ||||
|     if (ctx->more_flags & IS_CFX) | ||||
|         return _gssapi_wrap_cfx_iov(minor_status, ctx, context, | ||||
| 				    conf_req_flag, conf_state, | ||||
| 				    iov, iov_count); | ||||
|  | ||||
|     return GSS_S_FAILURE; | ||||
|     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); | ||||
|     ret = _gsskrb5i_get_token_key(ctx, context, &key); | ||||
|     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); | ||||
|     if (ret) { | ||||
| 	*minor_status = ret; | ||||
| 	return GSS_S_FAILURE; | ||||
|     } | ||||
|     krb5_enctype_to_keytype(context, key->keytype, &keytype); | ||||
|  | ||||
|     switch (keytype) { | ||||
|     case KEYTYPE_ARCFOUR: | ||||
|     case KEYTYPE_ARCFOUR_56: | ||||
| 	ret = _gssapi_wrap_iov_arcfour(minor_status, ctx, context, | ||||
| 				       conf_req_flag, conf_state, | ||||
| 				       iov, iov_count, key); | ||||
| 	break; | ||||
|  | ||||
|     default: | ||||
| 	ret = GSS_S_FAILURE; | ||||
| 	break; | ||||
|     } | ||||
|  | ||||
|     krb5_free_keyblock(context, key); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| OM_uint32 GSSAPI_CALLCONV | ||||
| @@ -67,6 +93,9 @@ _gk_unwrap_iov(OM_uint32 *minor_status, | ||||
| { | ||||
|     const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; | ||||
|     krb5_context context; | ||||
|     OM_uint32 ret; | ||||
|     krb5_keytype keytype; | ||||
|     krb5_keyblock *key; | ||||
|  | ||||
|     GSSAPI_KRB5_INIT (&context); | ||||
|  | ||||
| @@ -74,7 +103,30 @@ _gk_unwrap_iov(OM_uint32 *minor_status, | ||||
| 	return _gssapi_unwrap_cfx_iov(minor_status, ctx, context, | ||||
| 				      conf_state, qop_state, iov, iov_count); | ||||
|  | ||||
|     return GSS_S_FAILURE; | ||||
|     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); | ||||
|     ret = _gsskrb5i_get_token_key(ctx, context, &key); | ||||
|     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); | ||||
|     if (ret) { | ||||
| 	*minor_status = ret; | ||||
| 	return GSS_S_FAILURE; | ||||
|     } | ||||
|     krb5_enctype_to_keytype(context, key->keytype, &keytype); | ||||
|  | ||||
|     switch (keytype) { | ||||
|     case KEYTYPE_ARCFOUR: | ||||
|     case KEYTYPE_ARCFOUR_56: | ||||
| 	ret = _gssapi_unwrap_iov_arcfour(minor_status, ctx, context, | ||||
| 					 conf_state, qop_state, | ||||
| 					 iov, iov_count, key); | ||||
| 	break; | ||||
|  | ||||
|     default: | ||||
| 	ret = GSS_S_FAILURE; | ||||
| 	break; | ||||
|     } | ||||
|  | ||||
|     krb5_free_keyblock(context, key); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| OM_uint32 GSSAPI_CALLCONV | ||||
| @@ -88,6 +140,9 @@ _gk_wrap_iov_length(OM_uint32 * minor_status, | ||||
| { | ||||
|     const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; | ||||
|     krb5_context context; | ||||
|     OM_uint32 ret; | ||||
|     krb5_keytype keytype; | ||||
|     krb5_keyblock *key; | ||||
|  | ||||
|     GSSAPI_KRB5_INIT (&context); | ||||
|  | ||||
| @@ -96,5 +151,28 @@ _gk_wrap_iov_length(OM_uint32 * minor_status, | ||||
| 					   conf_req_flag, qop_req, conf_state, | ||||
| 					   iov, iov_count); | ||||
|  | ||||
|     return GSS_S_FAILURE; | ||||
|     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); | ||||
|     ret = _gsskrb5i_get_token_key(ctx, context, &key); | ||||
|     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); | ||||
|     if (ret) { | ||||
| 	*minor_status = ret; | ||||
| 	return GSS_S_FAILURE; | ||||
|     } | ||||
|     krb5_enctype_to_keytype(context, key->keytype, &keytype); | ||||
|  | ||||
|     switch (keytype) { | ||||
|     case KEYTYPE_ARCFOUR: | ||||
|     case KEYTYPE_ARCFOUR_56: | ||||
| 	ret = _gssapi_wrap_iov_length_arcfour(minor_status, ctx, context, | ||||
| 					      conf_req_flag, qop_req, conf_state, | ||||
| 					      iov, iov_count); | ||||
| 	break; | ||||
|  | ||||
|     default: | ||||
| 	ret = GSS_S_FAILURE; | ||||
| 	break; | ||||
|     } | ||||
|  | ||||
|     krb5_free_keyblock(context, key); | ||||
|     return ret; | ||||
| } | ||||
|   | ||||
| @@ -69,7 +69,7 @@ | ||||
|  | ||||
| static krb5_error_code | ||||
| arcfour_mic_key(krb5_context context, krb5_keyblock *key, | ||||
| 		void *cksum_data, size_t cksum_size, | ||||
| 		const void *cksum_data, size_t cksum_size, | ||||
| 		void *key6_data, size_t key6_size) | ||||
| { | ||||
|     krb5_error_code ret; | ||||
| @@ -112,30 +112,73 @@ arcfour_mic_key(krb5_context context, krb5_keyblock *key, | ||||
|  | ||||
|  | ||||
| static krb5_error_code | ||||
| arcfour_mic_cksum(krb5_context context, | ||||
| 		  krb5_keyblock *key, unsigned usage, | ||||
| 		  u_char *sgn_cksum, size_t sgn_cksum_sz, | ||||
| 		  const u_char *v1, size_t l1, | ||||
| 		  const void *v2, size_t l2, | ||||
| 		  const void *v3, size_t l3) | ||||
| arcfour_mic_cksum_iov(krb5_context context, | ||||
| 		      krb5_keyblock *key, unsigned usage, | ||||
| 		      u_char *sgn_cksum, size_t sgn_cksum_sz, | ||||
| 		      const u_char *v1, size_t l1, | ||||
| 		      const void *v2, size_t l2, | ||||
| 		      const gss_iov_buffer_desc *iov, | ||||
| 		      int iov_count, | ||||
| 		      const gss_iov_buffer_desc *padding) | ||||
| { | ||||
|     Checksum CKSUM; | ||||
|     u_char *ptr; | ||||
|     size_t len; | ||||
|     size_t ofs = 0; | ||||
|     int i; | ||||
|     krb5_crypto crypto; | ||||
|     krb5_error_code ret; | ||||
|  | ||||
|     assert(sgn_cksum_sz == 8); | ||||
|  | ||||
|     len = l1 + l2 + l3; | ||||
|     len = l1 + l2; | ||||
|  | ||||
|     for (i=0; i < iov_count; i++) { | ||||
| 	switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { | ||||
| 	case GSS_IOV_BUFFER_TYPE_DATA: | ||||
| 	case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: | ||||
| 	    break; | ||||
| 	default: | ||||
| 	    continue; | ||||
| 	} | ||||
|  | ||||
| 	len += iov[i].buffer.length; | ||||
|     } | ||||
|  | ||||
|     if (padding) { | ||||
| 	len += padding->buffer.length; | ||||
|     } | ||||
|  | ||||
|     ptr = malloc(len); | ||||
|     if (ptr == NULL) | ||||
| 	return ENOMEM; | ||||
|  | ||||
|     memcpy(ptr, v1, l1); | ||||
|     memcpy(ptr + l1, v2, l2); | ||||
|     memcpy(ptr + l1 + l2, v3, l3); | ||||
|     memcpy(ptr + ofs, v1, l1); | ||||
|     ofs += l1; | ||||
|     memcpy(ptr + ofs, v2, l2); | ||||
|     ofs += l2; | ||||
|  | ||||
|     for (i=0; i < iov_count; i++) { | ||||
| 	switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { | ||||
| 	case GSS_IOV_BUFFER_TYPE_DATA: | ||||
| 	case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: | ||||
| 	    break; | ||||
| 	default: | ||||
| 	    continue; | ||||
| 	} | ||||
|  | ||||
| 	memcpy(ptr + ofs, | ||||
| 	       iov[i].buffer.value, | ||||
| 	       iov[i].buffer.length); | ||||
| 	ofs += iov[i].buffer.length; | ||||
|     } | ||||
|  | ||||
|     if (padding) { | ||||
| 	memcpy(ptr + ofs, | ||||
| 	       padding->buffer.value, | ||||
| 	       padding->buffer.length); | ||||
| 	ofs += padding->buffer.length; | ||||
|     } | ||||
|  | ||||
|     ret = krb5_crypto_init(context, key, 0, &crypto); | ||||
|     if (ret) { | ||||
| @@ -149,6 +192,7 @@ arcfour_mic_cksum(krb5_context context, | ||||
| 			       0, | ||||
| 			       ptr, len, | ||||
| 			       &CKSUM); | ||||
|     memset(ptr, 0, len); | ||||
|     free(ptr); | ||||
|     if (ret == 0) { | ||||
| 	memcpy(sgn_cksum, CKSUM.checksum.data, sgn_cksum_sz); | ||||
| @@ -159,6 +203,26 @@ arcfour_mic_cksum(krb5_context context, | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static krb5_error_code | ||||
| arcfour_mic_cksum(krb5_context context, | ||||
| 		  krb5_keyblock *key, unsigned usage, | ||||
| 		  u_char *sgn_cksum, size_t sgn_cksum_sz, | ||||
| 		  const u_char *v1, size_t l1, | ||||
| 		  const void *v2, size_t l2, | ||||
| 		  const void *v3, size_t l3) | ||||
| { | ||||
|     gss_iov_buffer_desc iov; | ||||
|  | ||||
|     iov.type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; | ||||
|     iov.buffer.value = rk_UNCONST(v3); | ||||
|     iov.buffer.length = l3; | ||||
|  | ||||
|     return arcfour_mic_cksum_iov(context, key, usage, | ||||
| 				 sgn_cksum, sgn_cksum_sz, | ||||
| 				 v1, l1, v2, l2, | ||||
| 				 &iov, 1, NULL); | ||||
| } | ||||
|  | ||||
|  | ||||
| OM_uint32 | ||||
| _gssapi_get_mic_arcfour(OM_uint32 * minor_status, | ||||
| @@ -760,3 +824,562 @@ _gssapi_wrap_size_arcfour(OM_uint32 *minor_status, | ||||
|  | ||||
|     return GSS_S_COMPLETE; | ||||
| } | ||||
|  | ||||
| OM_uint32 | ||||
| _gssapi_wrap_iov_length_arcfour(OM_uint32 *minor_status, | ||||
| 				gsskrb5_ctx ctx, | ||||
| 				krb5_context context, | ||||
| 				int conf_req_flag, | ||||
| 				gss_qop_t qop_req, | ||||
| 				int *conf_state, | ||||
| 				gss_iov_buffer_desc *iov, | ||||
| 				int iov_count) | ||||
| { | ||||
|     OM_uint32 major_status; | ||||
|     size_t data_len = 0; | ||||
|     int i; | ||||
|     gss_iov_buffer_desc *header = NULL; | ||||
|     gss_iov_buffer_desc *padding = NULL; | ||||
|     gss_iov_buffer_desc *trailer = NULL; | ||||
|  | ||||
|     *minor_status = 0; | ||||
|  | ||||
|     for (i = 0; i < iov_count; i++) { | ||||
| 	switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) { | ||||
| 	case GSS_IOV_BUFFER_TYPE_EMPTY: | ||||
| 	    break; | ||||
| 	case GSS_IOV_BUFFER_TYPE_DATA: | ||||
| 	    data_len += iov[i].buffer.length; | ||||
| 	    break; | ||||
| 	case GSS_IOV_BUFFER_TYPE_HEADER: | ||||
| 	    if (header != NULL) { | ||||
| 		*minor_status = EINVAL; | ||||
| 		return GSS_S_FAILURE; | ||||
| 	    } | ||||
| 	    header = &iov[i]; | ||||
| 	    break; | ||||
| 	case GSS_IOV_BUFFER_TYPE_TRAILER: | ||||
| 	    if (trailer != NULL) { | ||||
| 		*minor_status = EINVAL; | ||||
| 		return GSS_S_FAILURE; | ||||
| 	    } | ||||
| 	    trailer = &iov[i]; | ||||
| 	    break; | ||||
| 	case GSS_IOV_BUFFER_TYPE_PADDING: | ||||
| 	    if (padding != NULL) { | ||||
| 		*minor_status = EINVAL; | ||||
| 		return GSS_S_FAILURE; | ||||
| 	    } | ||||
| 	    padding = &iov[i]; | ||||
| 	    break; | ||||
| 	case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: | ||||
| 	    break; | ||||
| 	default: | ||||
| 	    *minor_status = EINVAL; | ||||
| 	    return GSS_S_FAILURE; | ||||
| 	} | ||||
|     } | ||||
|  | ||||
|     major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer); | ||||
|     if (major_status != GSS_S_COMPLETE) { | ||||
| 	    return major_status; | ||||
|     } | ||||
|  | ||||
|     if (IS_DCE_STYLE(ctx)) { | ||||
| 	size_t len = GSS_ARCFOUR_WRAP_TOKEN_SIZE; | ||||
| 	size_t total_len; | ||||
| 	_gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); | ||||
| 	header->buffer.length = total_len; | ||||
|     } else { | ||||
| 	size_t len; | ||||
| 	size_t total_len; | ||||
| 	if (padding) { | ||||
| 	    data_len += 1; /* padding */ | ||||
| 	} | ||||
| 	len = data_len + GSS_ARCFOUR_WRAP_TOKEN_SIZE; | ||||
| 	_gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); | ||||
| 	header->buffer.length = total_len - data_len; | ||||
|     } | ||||
|  | ||||
|     if (trailer) { | ||||
| 	trailer->buffer.length = 0; | ||||
|     } | ||||
|  | ||||
|     if (padding) { | ||||
| 	padding->buffer.length = 1; | ||||
|     } | ||||
|  | ||||
|     return GSS_S_COMPLETE; | ||||
| } | ||||
|  | ||||
| OM_uint32 | ||||
| _gssapi_wrap_iov_arcfour(OM_uint32 *minor_status, | ||||
| 			 gsskrb5_ctx ctx, | ||||
| 			 krb5_context context, | ||||
| 			 int conf_req_flag, | ||||
| 			 int *conf_state, | ||||
| 			 gss_iov_buffer_desc *iov, | ||||
| 			 int iov_count, | ||||
| 			 krb5_keyblock *key) | ||||
| { | ||||
|     OM_uint32 major_status, junk; | ||||
|     gss_iov_buffer_desc *header, *padding, *trailer; | ||||
|     krb5_error_code kret; | ||||
|     int32_t seq_number; | ||||
|     u_char Klocaldata[16], k6_data[16], *p, *p0; | ||||
|     size_t make_len = 0; | ||||
|     size_t header_len = 0; | ||||
|     size_t data_len = 0; | ||||
|     krb5_keyblock Klocal; | ||||
|     int i; | ||||
|  | ||||
|     header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); | ||||
|     padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); | ||||
|     trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); | ||||
|  | ||||
|     major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer); | ||||
|     if (major_status != GSS_S_COMPLETE) { | ||||
| 	return major_status; | ||||
|     } | ||||
|  | ||||
|     for (i = 0; i < iov_count; i++) { | ||||
| 	switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { | ||||
| 	case GSS_IOV_BUFFER_TYPE_DATA: | ||||
| 	    break; | ||||
| 	default: | ||||
| 	    continue; | ||||
| 	} | ||||
|  | ||||
| 	data_len += iov[i].buffer.length; | ||||
|     } | ||||
|  | ||||
|     if (padding) { | ||||
| 	data_len += 1; | ||||
|     } | ||||
|  | ||||
|     if (IS_DCE_STYLE(ctx)) { | ||||
| 	size_t unwrapped_len; | ||||
| 	unwrapped_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE; | ||||
| 	_gssapi_encap_length(unwrapped_len, | ||||
| 			     &make_len, | ||||
| 			     &header_len, | ||||
| 			     GSS_KRB5_MECHANISM); | ||||
|     } else { | ||||
| 	size_t unwrapped_len; | ||||
| 	unwrapped_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE + data_len; | ||||
| 	_gssapi_encap_length(unwrapped_len, | ||||
| 			     &make_len, | ||||
| 			     &header_len, | ||||
| 			     GSS_KRB5_MECHANISM); | ||||
| 	header_len -= data_len; | ||||
|     } | ||||
|  | ||||
|     if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE) { | ||||
| 	major_status = _gk_allocate_buffer(minor_status, header, | ||||
| 					   header_len); | ||||
| 	if (major_status != GSS_S_COMPLETE) | ||||
| 	    goto failure; | ||||
|     } else if (header->buffer.length < header_len) { | ||||
| 	*minor_status = KRB5_BAD_MSIZE; | ||||
| 	major_status = GSS_S_FAILURE; | ||||
| 	goto failure; | ||||
|     } else { | ||||
| 	header->buffer.length = header_len; | ||||
|     } | ||||
|  | ||||
|     if (padding) { | ||||
| 	if (GSS_IOV_BUFFER_FLAGS(padding->type) & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE) { | ||||
| 	    major_status = _gk_allocate_buffer(minor_status, padding, 1); | ||||
| 	    if (major_status != GSS_S_COMPLETE) | ||||
| 		goto failure; | ||||
| 	} else if (padding->buffer.length < 1) { | ||||
| 	    *minor_status = KRB5_BAD_MSIZE; | ||||
| 	    major_status = GSS_S_FAILURE; | ||||
| 	    goto failure; | ||||
| 	} else { | ||||
| 	    padding->buffer.length = 1; | ||||
| 	} | ||||
| 	memset(padding->buffer.value, 1, 1); | ||||
|     } | ||||
|  | ||||
|     if (trailer) { | ||||
| 	trailer->buffer.length = 0; | ||||
| 	trailer->buffer.value = NULL; | ||||
|     } | ||||
|  | ||||
|     p0 = _gssapi_make_mech_header(header->buffer.value, | ||||
| 				  make_len, | ||||
| 				  GSS_KRB5_MECHANISM); | ||||
|     p = p0; | ||||
|  | ||||
|     *p++ = 0x02; /* TOK_ID */ | ||||
|     *p++ = 0x01; | ||||
|     *p++ = 0x11; /* SGN_ALG */ | ||||
|     *p++ = 0x00; | ||||
|     if (conf_req_flag) { | ||||
| 	*p++ = 0x10; /* SEAL_ALG */ | ||||
| 	*p++ = 0x00; | ||||
|     } else { | ||||
| 	*p++ = 0xff; /* SEAL_ALG */ | ||||
| 	*p++ = 0xff; | ||||
|     } | ||||
|     *p++ = 0xff; /* Filler */ | ||||
|     *p++ = 0xff; | ||||
|  | ||||
|     p = NULL; | ||||
|  | ||||
|     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); | ||||
|     krb5_auth_con_getlocalseqnumber(context, | ||||
| 				    ctx->auth_context, | ||||
| 				    &seq_number); | ||||
|     _gsskrb5_encode_be_om_uint32(seq_number, p0 + 8); | ||||
|  | ||||
|     krb5_auth_con_setlocalseqnumber(context, | ||||
| 				    ctx->auth_context, | ||||
| 				    ++seq_number); | ||||
|     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); | ||||
|  | ||||
|     memset(p0 + 8 + 4, | ||||
|            (ctx->more_flags & LOCAL) ? 0 : 0xff, | ||||
|            4); | ||||
|  | ||||
|     krb5_generate_random_block(p0 + 24, 8); /* fill in Confounder */ | ||||
|  | ||||
|     /* Sign Data */ | ||||
|     kret = arcfour_mic_cksum_iov(context, | ||||
| 				 key, KRB5_KU_USAGE_SEAL, | ||||
| 				 p0 + 16, 8, /* SGN_CKSUM */ | ||||
| 				 p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */ | ||||
| 				 p0 + 24, 8, /* Confounder */ | ||||
| 				 iov, iov_count, /* Data + SignOnly */ | ||||
| 				 padding); /* padding */ | ||||
|     if (kret) { | ||||
| 	*minor_status = kret; | ||||
| 	major_status = GSS_S_FAILURE; | ||||
| 	goto failure; | ||||
|     } | ||||
|  | ||||
|     Klocal.keytype = key->keytype; | ||||
|     Klocal.keyvalue.data = Klocaldata; | ||||
|     Klocal.keyvalue.length = sizeof(Klocaldata); | ||||
|  | ||||
|     for (i = 0; i < 16; i++) { | ||||
| 	Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0; | ||||
|     } | ||||
|     kret = arcfour_mic_key(context, &Klocal, | ||||
| 			   p0 + 8, 4, /* SND_SEQ */ | ||||
| 			   k6_data, sizeof(k6_data)); | ||||
|     memset(Klocaldata, 0, sizeof(Klocaldata)); | ||||
|     if (kret) { | ||||
| 	*minor_status = kret; | ||||
| 	major_status = GSS_S_FAILURE; | ||||
| 	goto failure; | ||||
|     } | ||||
|  | ||||
|     if (conf_req_flag) { | ||||
| 	EVP_CIPHER_CTX rc4_key; | ||||
|  | ||||
| 	EVP_CIPHER_CTX_init(&rc4_key); | ||||
| 	EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); | ||||
|  | ||||
| 	/* Confounder */ | ||||
| 	EVP_Cipher(&rc4_key, p0 + 24, p0 + 24, 8); | ||||
|  | ||||
| 	/* Seal Data */ | ||||
| 	for (i=0; i < iov_count; i++) { | ||||
| 	    switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { | ||||
| 	    case GSS_IOV_BUFFER_TYPE_DATA: | ||||
| 		break; | ||||
| 	    default: | ||||
| 		continue; | ||||
| 	    } | ||||
|  | ||||
| 	    EVP_Cipher(&rc4_key, iov[i].buffer.value, | ||||
| 		       iov[i].buffer.value, iov[i].buffer.length); | ||||
| 	} | ||||
|  | ||||
| 	/* Padding */ | ||||
| 	if (padding) { | ||||
| 	    EVP_Cipher(&rc4_key, padding->buffer.value, | ||||
| 		       padding->buffer.value, padding->buffer.length); | ||||
| 	} | ||||
|  | ||||
| 	EVP_CIPHER_CTX_cleanup(&rc4_key); | ||||
|     } | ||||
|     memset(k6_data, 0, sizeof(k6_data)); | ||||
|  | ||||
|     kret = arcfour_mic_key(context, key, | ||||
| 			   p0 + 16, 8, /* SGN_CKSUM */ | ||||
| 			   k6_data, sizeof(k6_data)); | ||||
|     if (kret) { | ||||
| 	*minor_status = kret; | ||||
| 	major_status = GSS_S_FAILURE; | ||||
|     } | ||||
|  | ||||
|     { | ||||
| 	EVP_CIPHER_CTX rc4_key; | ||||
|  | ||||
| 	EVP_CIPHER_CTX_init(&rc4_key); | ||||
| 	EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); | ||||
| 	EVP_Cipher(&rc4_key, p0 + 8, p0 + 8, 8); /* SND_SEQ */ | ||||
| 	EVP_CIPHER_CTX_cleanup(&rc4_key); | ||||
|  | ||||
| 	memset(k6_data, 0, sizeof(k6_data)); | ||||
|     } | ||||
|  | ||||
|     if (conf_state) | ||||
| 	*conf_state = conf_req_flag; | ||||
|  | ||||
|     *minor_status = 0; | ||||
|     return GSS_S_COMPLETE; | ||||
|  | ||||
| failure: | ||||
|  | ||||
|     gss_release_iov_buffer(&junk, iov, iov_count); | ||||
|  | ||||
|     return major_status; | ||||
| } | ||||
|  | ||||
| OM_uint32 | ||||
| _gssapi_unwrap_iov_arcfour(OM_uint32 *minor_status, | ||||
| 			   gsskrb5_ctx ctx, | ||||
| 			   krb5_context context, | ||||
| 			   int *pconf_state, | ||||
| 			   gss_qop_t *pqop_state, | ||||
| 			   gss_iov_buffer_desc *iov, | ||||
| 			   int iov_count, | ||||
| 			   krb5_keyblock *key) | ||||
| { | ||||
|     OM_uint32 major_status; | ||||
|     gss_iov_buffer_desc *header, *padding, *trailer; | ||||
|     krb5_keyblock Klocal; | ||||
|     uint8_t Klocaldata[16]; | ||||
|     uint8_t k6_data[16], snd_seq[8], Confounder[8]; | ||||
|     uint8_t cksum_data[8]; | ||||
|     uint8_t *_p = NULL; | ||||
|     const uint8_t *p, *p0; | ||||
|     size_t verify_len = 0; | ||||
|     uint32_t seq_number; | ||||
|     size_t hlen = 0; | ||||
|     int conf_state; | ||||
|     int cmp; | ||||
|     size_t i; | ||||
|     krb5_error_code kret; | ||||
|     OM_uint32 ret; | ||||
|  | ||||
|     if (pconf_state != NULL) { | ||||
| 	*pconf_state = 0; | ||||
|     } | ||||
|     if (pqop_state != NULL) { | ||||
| 	*pqop_state = 0; | ||||
|     } | ||||
|  | ||||
|     header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); | ||||
|     padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); | ||||
|     trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); | ||||
|  | ||||
|     /* Check if the packet is correct */ | ||||
|     major_status = _gk_verify_buffers(minor_status, | ||||
| 				  ctx, | ||||
| 				  header, | ||||
| 				  padding, | ||||
| 				  trailer); | ||||
|     if (major_status != GSS_S_COMPLETE) { | ||||
| 	return major_status; | ||||
|     } | ||||
|  | ||||
|     if (padding != NULL && padding->buffer.length != 1) { | ||||
| 	*minor_status = EINVAL; | ||||
| 	return GSS_S_FAILURE; | ||||
|     } | ||||
|  | ||||
|     if (IS_DCE_STYLE(context)) { | ||||
| 	verify_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE + | ||||
| 		     GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE; | ||||
| 	if (header->buffer.length > verify_len) { | ||||
| 	    return GSS_S_BAD_MECH; | ||||
| 	} | ||||
|     } else { | ||||
| 	verify_len = header->buffer.length; | ||||
|     } | ||||
|     _p = header->buffer.value; | ||||
|  | ||||
|     ret = _gssapi_verify_mech_header(&_p, | ||||
| 				     verify_len, | ||||
| 				     GSS_KRB5_MECHANISM); | ||||
|     if (ret) { | ||||
| 	return ret; | ||||
|     } | ||||
|     p0 = _p; | ||||
|  | ||||
|     /* length of mech header */ | ||||
|     hlen = (p0 - (uint8_t *)header->buffer.value); | ||||
|     hlen += GSS_ARCFOUR_WRAP_TOKEN_SIZE; | ||||
|  | ||||
|     if (hlen > header->buffer.length) { | ||||
| 	return GSS_S_BAD_MECH; | ||||
|     } | ||||
|  | ||||
|     p = p0; | ||||
|  | ||||
|     if (memcmp(p, "\x02\x01", 2) != 0) | ||||
| 	return GSS_S_BAD_SIG; | ||||
|     p += 2; | ||||
|     if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */ | ||||
| 	return GSS_S_BAD_SIG; | ||||
|     p += 2; | ||||
|  | ||||
|     if (memcmp (p, "\x10\x00", 2) == 0) | ||||
| 	conf_state = 1; | ||||
|     else if (memcmp (p, "\xff\xff", 2) == 0) | ||||
| 	conf_state = 0; | ||||
|     else | ||||
| 	return GSS_S_BAD_SIG; | ||||
|  | ||||
|     p += 2; | ||||
|     if (memcmp (p, "\xff\xff", 2) != 0) | ||||
| 	return GSS_S_BAD_MIC; | ||||
|     p = NULL; | ||||
|  | ||||
|     kret = arcfour_mic_key(context, | ||||
| 			   key, | ||||
| 			   p0 + 16, /* SGN_CKSUM */ | ||||
| 			   8,       /* SGN_CKSUM_LEN */ | ||||
| 			   k6_data, | ||||
| 			   sizeof(k6_data)); | ||||
|     if (kret) { | ||||
| 	*minor_status = kret; | ||||
| 	return GSS_S_FAILURE; | ||||
|     } | ||||
|  | ||||
|     { | ||||
| 	EVP_CIPHER_CTX rc4_key; | ||||
|  | ||||
| 	EVP_CIPHER_CTX_init(&rc4_key); | ||||
| 	EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); | ||||
| 	EVP_Cipher(&rc4_key, snd_seq, p0 + 8, 8); /* SND_SEQ */ | ||||
| 	EVP_CIPHER_CTX_cleanup(&rc4_key); | ||||
|  | ||||
| 	memset(k6_data, 0, sizeof(k6_data)); | ||||
|     } | ||||
|  | ||||
|     _gsskrb5_decode_be_om_uint32(snd_seq, &seq_number); | ||||
|  | ||||
|     if (ctx->more_flags & LOCAL) { | ||||
| 	cmp = memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4); | ||||
|     } else { | ||||
| 	cmp = memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4); | ||||
|     } | ||||
|     if (cmp != 0) { | ||||
| 	*minor_status = 0; | ||||
| 	return GSS_S_BAD_MIC; | ||||
|     } | ||||
|  | ||||
|     if (ctx->more_flags & LOCAL) { | ||||
| 	cmp = memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4); | ||||
|     } else { | ||||
| 	cmp = memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4); | ||||
|     } | ||||
|     if (cmp != 0) { | ||||
| 	*minor_status = 0; | ||||
| 	return GSS_S_BAD_MIC; | ||||
|     } | ||||
|  | ||||
|     /* keyblock */ | ||||
|     Klocal.keytype = key->keytype; | ||||
|     Klocal.keyvalue.data = Klocaldata; | ||||
|     Klocal.keyvalue.length = sizeof(Klocaldata); | ||||
|  | ||||
|     for (i = 0; i < 16; i++) { | ||||
| 	Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0; | ||||
|     } | ||||
|  | ||||
|     kret = arcfour_mic_key(context, | ||||
| 			   &Klocal, | ||||
| 			   snd_seq, | ||||
| 			   4, | ||||
| 			   k6_data, sizeof(k6_data)); | ||||
|     memset(Klocaldata, 0, sizeof(Klocaldata)); | ||||
|     if (kret) { | ||||
| 	*minor_status = kret; | ||||
| 	return GSS_S_FAILURE; | ||||
|     } | ||||
|  | ||||
|     if (conf_state == 1) { | ||||
| 	EVP_CIPHER_CTX rc4_key; | ||||
|  | ||||
| 	EVP_CIPHER_CTX_init(&rc4_key); | ||||
| 	EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); | ||||
|  | ||||
| 	/* Confounder */ | ||||
| 	EVP_Cipher(&rc4_key, Confounder, p0 + 24, 8); | ||||
|  | ||||
| 	/* Data */ | ||||
| 	for (i = 0; i < iov_count; i++) { | ||||
| 	    switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { | ||||
| 	    case GSS_IOV_BUFFER_TYPE_DATA: | ||||
| 		break; | ||||
| 	    default: | ||||
| 		continue; | ||||
| 	    } | ||||
|  | ||||
| 	    EVP_Cipher(&rc4_key, iov[i].buffer.value, | ||||
| 		       iov[i].buffer.value, iov[i].buffer.length); | ||||
| 	} | ||||
|  | ||||
| 	/* Padding */ | ||||
| 	if (padding) { | ||||
| 	    EVP_Cipher(&rc4_key, padding->buffer.value, | ||||
| 		       padding->buffer.value, padding->buffer.length); | ||||
| 	} | ||||
|  | ||||
| 	EVP_CIPHER_CTX_cleanup(&rc4_key); | ||||
|     } else { | ||||
| 	/* Confounder */ | ||||
| 	memcpy(Confounder, p0 + 24, 8); | ||||
|     } | ||||
|     memset(k6_data, 0, sizeof(k6_data)); | ||||
|  | ||||
|     /* Prepare the buffer for signing */ | ||||
|     kret = arcfour_mic_cksum_iov(context, | ||||
| 				 key, KRB5_KU_USAGE_SEAL, | ||||
| 				 cksum_data, sizeof(cksum_data), | ||||
| 				 p0, 8, | ||||
| 				 Confounder, sizeof(Confounder), | ||||
| 				 iov, iov_count, | ||||
| 				 padding); | ||||
|     if (kret) { | ||||
| 	*minor_status = kret; | ||||
| 	return GSS_S_FAILURE; | ||||
|     } | ||||
|  | ||||
|     cmp = memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */ | ||||
|     if (cmp != 0) { | ||||
| 	*minor_status = 0; | ||||
| 	return GSS_S_BAD_MIC; | ||||
|     } | ||||
|  | ||||
|     if (padding) { | ||||
| 	size_t plen; | ||||
|  | ||||
| 	ret = _gssapi_verify_pad(&padding->buffer, 1, &plen); | ||||
| 	if (ret) { | ||||
| 	    *minor_status = 0; | ||||
| 	    return ret; | ||||
| 	} | ||||
|     } | ||||
|  | ||||
|     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); | ||||
|     ret = _gssapi_msg_order_check(ctx->order, seq_number); | ||||
|     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); | ||||
|     if (ret != 0) { | ||||
| 	return ret; | ||||
|     } | ||||
|  | ||||
|     if (pconf_state) { | ||||
| 	*pconf_state = conf_state; | ||||
|     } | ||||
|  | ||||
|     *minor_status = 0; | ||||
|     return GSS_S_COMPLETE; | ||||
| } | ||||
|   | ||||
| @@ -190,6 +190,9 @@ _gssapi_verify_pad(gss_buffer_t wrapped_token, | ||||
|     size_t padlength; | ||||
|     int i; | ||||
|  | ||||
|     if (wrapped_token->length < 1) | ||||
| 	return GSS_S_BAD_MECH; | ||||
|  | ||||
|     pad = (u_char *)wrapped_token->value + wrapped_token->length - 1; | ||||
|     padlength = *pad; | ||||
|  | ||||
|   | ||||
| @@ -28,5 +28,6 @@ error_code NO_WRITE_SUPPORT,	"HDB backend doesn't contain write support" | ||||
| error_code NOT_FOUND_HERE,	"The secret for this entry is not replicated to this database" | ||||
| error_code MISUSE,		"Incorrect use of the API" | ||||
| error_code KVNO_NOT_FOUND,	"Entry key version number not found" | ||||
| error_code WRONG_REALM,		"The principal exists in another realm." | ||||
|  | ||||
| end | ||||
|   | ||||
| @@ -2330,6 +2330,17 @@ krb5_init_creds_step(krb5_context context, | ||||
| 		ret = krb5_principal_set_realm(context, | ||||
| 					       ctx->cred.client, | ||||
| 					       *ctx->error.crealm); | ||||
| 		if (ret) | ||||
| 		    goto out; | ||||
|  | ||||
| 		if (krb5_principal_is_krbtgt(context, ctx->cred.server)) { | ||||
| 		    ret = krb5_init_creds_set_service(context, ctx, NULL); | ||||
| 		    if (ret) | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 		free_AS_REQ(&ctx->as_req); | ||||
| 		memset(&ctx->as_req, 0, sizeof(ctx->as_req)); | ||||
|  | ||||
| 		ctx->used_pa_types = 0; | ||||
| 	    } else if (ret == KRB5KDC_ERR_KEY_EXP && ctx->runflags.change_password == 0 && ctx->prompter) { | ||||
| @@ -2379,6 +2390,15 @@ krb5_init_creds_step(krb5_context context, | ||||
| 	} | ||||
|     } | ||||
|  | ||||
|     if (ctx->as_req.req_body.cname == NULL) { | ||||
| 	ret = init_as_req(context, ctx->flags, &ctx->cred, | ||||
| 			  ctx->addrs, ctx->etypes, &ctx->as_req); | ||||
| 	if (ret) { | ||||
| 	    free_init_creds_ctx(context, ctx); | ||||
| 	    return ret; | ||||
| 	} | ||||
|     } | ||||
|  | ||||
|     if (ctx->as_req.padata) { | ||||
| 	free_METHOD_DATA(ctx->as_req.padata); | ||||
| 	free(ctx->as_req.padata); | ||||
|   | ||||
| @@ -440,6 +440,7 @@ EXPORTS | ||||
| 	krb5_make_principal | ||||
| 	krb5_max_sockaddr_size | ||||
| 	krb5_mk_error | ||||
| 	krb5_mk_error_ext | ||||
| 	krb5_mk_priv | ||||
| 	krb5_mk_rep | ||||
| 	krb5_mk_req | ||||
|   | ||||
| @@ -34,15 +34,16 @@ | ||||
| #include "krb5_locl.h" | ||||
|  | ||||
| KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL | ||||
| krb5_mk_error(krb5_context context, | ||||
| 	      krb5_error_code error_code, | ||||
| 	      const char *e_text, | ||||
| 	      const krb5_data *e_data, | ||||
| 	      const krb5_principal client, | ||||
| 	      const krb5_principal server, | ||||
| 	      time_t *client_time, | ||||
| 	      int *client_usec, | ||||
| 	      krb5_data *reply) | ||||
| krb5_mk_error_ext(krb5_context context, | ||||
| 		  krb5_error_code error_code, | ||||
| 		  const char *e_text, | ||||
| 		  const krb5_data *e_data, | ||||
| 		  const krb5_principal server, | ||||
| 		  const PrincipalName *client_name, | ||||
| 		  const Realm *client_realm, | ||||
| 		  time_t *client_time, | ||||
| 		  int *client_usec, | ||||
| 		  krb5_data *reply) | ||||
| { | ||||
|     const char *e_text2 = NULL; | ||||
|     KRB_ERROR msg; | ||||
| @@ -78,10 +79,8 @@ krb5_mk_error(krb5_context context, | ||||
| 	static char unspec[] = "<unspecified realm>"; | ||||
| 	msg.realm = unspec; | ||||
|     } | ||||
|     if(client){ | ||||
| 	msg.crealm = &client->realm; | ||||
| 	msg.cname = &client->name; | ||||
|     } | ||||
|     msg.crealm = rk_UNCONST(client_realm); | ||||
|     msg.cname = rk_UNCONST(client_name); | ||||
|  | ||||
|     ASN1_MALLOC_ENCODE(KRB_ERROR, reply->data, reply->length, &msg, &len, ret); | ||||
|     if (e_text2) | ||||
| @@ -92,3 +91,27 @@ krb5_mk_error(krb5_context context, | ||||
| 	krb5_abortx(context, "internal error in ASN.1 encoder"); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL | ||||
| krb5_mk_error(krb5_context context, | ||||
| 	      krb5_error_code error_code, | ||||
| 	      const char *e_text, | ||||
| 	      const krb5_data *e_data, | ||||
| 	      const krb5_principal client, | ||||
| 	      const krb5_principal server, | ||||
| 	      time_t *client_time, | ||||
| 	      int *client_usec, | ||||
| 	      krb5_data *reply) | ||||
| { | ||||
|     const PrincipalName *client_name = NULL; | ||||
|     const Realm *client_realm = NULL; | ||||
|  | ||||
|     if (client) { | ||||
| 	client_realm = &client->realm; | ||||
| 	client_name = &client->name; | ||||
|     } | ||||
|  | ||||
|     return krb5_mk_error_ext(context, error_code, e_text, e_data, | ||||
| 			     server, client_name, client_realm, | ||||
| 			     client_time, client_usec, reply); | ||||
| } | ||||
|   | ||||
| @@ -595,11 +595,12 @@ verify_logonname(krb5_context context, | ||||
| 		 krb5_const_principal principal) | ||||
| { | ||||
|     krb5_error_code ret; | ||||
|     krb5_principal p2; | ||||
|     uint32_t time1, time2; | ||||
|     krb5_storage *sp; | ||||
|     uint16_t len; | ||||
|     char *s; | ||||
|     char *s = NULL; | ||||
|     char *principal_string = NULL; | ||||
|     char *logon_string = NULL; | ||||
|  | ||||
|     sp = krb5_storage_from_readonly_mem((const char *)data->data + logon_name->offset_lo, | ||||
| 					logon_name->buffersize); | ||||
| @@ -670,31 +671,36 @@ verify_logonname(krb5_context context, | ||||
| 	    return ret; | ||||
| 	} | ||||
| 	u8len += 1; /* Add space for NUL */ | ||||
| 	s = malloc(u8len); | ||||
| 	if (s == NULL) { | ||||
| 	logon_string = malloc(u8len); | ||||
| 	if (logon_string == NULL) { | ||||
| 	    free(ucs2); | ||||
| 	    return krb5_enomem(context); | ||||
| 	} | ||||
| 	ret = wind_ucs2utf8(ucs2, ucs2len, s, &u8len); | ||||
| 	ret = wind_ucs2utf8(ucs2, ucs2len, logon_string, &u8len); | ||||
| 	free(ucs2); | ||||
| 	if (ret) { | ||||
| 	    free(s); | ||||
| 	    free(logon_string); | ||||
| 	    krb5_set_error_message(context, ret, "Failed to convert to UTF-8"); | ||||
| 	    return ret; | ||||
| 	} | ||||
|     } | ||||
|     ret = krb5_parse_name_flags(context, s, | ||||
| 				KRB5_PRINCIPAL_PARSE_NO_REALM | | ||||
| 				KRB5_PRINCIPAL_PARSE_ENTERPRISE, &p2); | ||||
|     free(s); | ||||
|     if (ret) | ||||
|     ret = krb5_unparse_name_flags(context, principal, | ||||
| 				  KRB5_PRINCIPAL_UNPARSE_NO_REALM | | ||||
| 				  KRB5_PRINCIPAL_UNPARSE_DISPLAY, | ||||
| 				  &principal_string); | ||||
|     if (ret) { | ||||
| 	free(logon_string); | ||||
| 	return ret; | ||||
|  | ||||
|     if (krb5_principal_compare_any_realm(context, principal, p2) != TRUE) { | ||||
| 	ret = EINVAL; | ||||
| 	krb5_set_error_message(context, ret, "PAC logon name mismatch"); | ||||
|     } | ||||
|     krb5_free_principal(context, p2); | ||||
|  | ||||
|     ret = strcmp(logon_string, principal_string); | ||||
|     if (ret != 0) { | ||||
| 	ret = EINVAL; | ||||
| 	krb5_set_error_message(context, ret, "PAC logon name [%s] mismatch principal name [%s]", | ||||
| 			       logon_string, principal_string); | ||||
|     } | ||||
|     free(logon_string); | ||||
|     free(principal_string); | ||||
|     return ret; | ||||
| out: | ||||
|     return ret; | ||||
|   | ||||
| @@ -433,6 +433,7 @@ HEIMDAL_KRB5_2.0 { | ||||
| 		krb5_make_principal; | ||||
| 		krb5_max_sockaddr_size; | ||||
| 		krb5_mk_error; | ||||
| 		krb5_mk_error_ext; | ||||
| 		krb5_mk_priv; | ||||
| 		krb5_mk_rep; | ||||
| 		krb5_mk_req; | ||||
|   | ||||
| @@ -23,6 +23,7 @@ $(libheimntlm_la_OBJECTS): $(srcdir)/version-script.map | ||||
|  | ||||
| libheimntlm_la_LIBADD = \ | ||||
| 	../krb5/libkrb5.la \ | ||||
| 	$(top_builddir)/lib/wind/libwind.la \ | ||||
| 	$(LIB_hcrypto) \ | ||||
| 	$(LIBADD_roken) | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Andrew Bartlett
					Andrew Bartlett