Beispiel #1
0
BOOL prs_werror(const char *name, prs_struct *ps, int depth, WERROR *status)
{
	char *q = prs_mem_get(ps, sizeof(uint32));
	if (q == NULL)
		return False;

	if (UNMARSHALLING(ps)) {
		if (ps->bigendian_data)
			*status = W_ERROR(RIVAL(q,0));
		else
			*status = W_ERROR(IVAL(q,0));
	} else {
		if (ps->bigendian_data)
			RSIVAL(q,0,W_ERROR_V(*status));
		else
			SIVAL(q,0,W_ERROR_V(*status));
	}

	DEBUG(5,("%s%04x %s: %s\n", tab_depth(depth), ps->data_offset, name, 
		 dos_errstr(*status)));

	ps->data_offset += sizeof(uint32);

	return True;
}
Beispiel #2
0
 int buffer_next_uint32(xrtp_buffer_t * buf, uint32 * ret){

    if(buf->pos + sizeof(uint32) > buf->len){

       return 0;
    }

    if(HOST_ORDER == BIGEND_ORDER)
    {
       buffer_log(("buffer_next_uint32: BE (%u) at buf[%d]@%d\n", *ret, buf->pos, (int)(buf->data)));
       *ret = RIVAL(buf->data, buf->pos);
    }
    else
    {
       buffer_log(("buffer_next_uint32: LE (%u) at buf[%d]@%d\n", *ret, buf->pos, (int)(buf->data)));
       *ret = IVAL(buf->data, buf->pos);
    }
       
    if(HOST_ORDER != buf->byte_order)
    {
       buffer_log(("buffer_next_uint32: HE (%u) at buf[%d]@%d\n", *ret, buf->pos, (int)(buf->data)));
       _buffer_swap32(*ret);
    }

    buf->pos += sizeof(uint32);

    return sizeof(uint32);
 }
Beispiel #3
0
BOOL prs_ntstatus(const char *name, prs_struct *ps, int depth, NTSTATUS *status)
{
	char *q = prs_mem_get(ps, sizeof(uint32));
	if (q == NULL)
		return False;

	if (UNMARSHALLING(ps)) {
		if (ps->bigendian_data)
			*status = NT_STATUS(RIVAL(q,0));
		else
			*status = NT_STATUS(IVAL(q,0));
	} else {
		if (ps->bigendian_data)
			RSIVAL(q,0,NT_STATUS_V(*status));
		else
			SIVAL(q,0,NT_STATUS_V(*status));
	}

	DEBUG(5,("%s%04x %s: %s\n", tab_depth(depth), ps->data_offset, name, 
		 get_nt_error_msg(*status)));

	ps->data_offset += sizeof(uint32);

	return True;
}
Beispiel #4
0
bool prs_dcerpc_status(const char *name, prs_struct *ps, int depth, NTSTATUS *status)
{
	char *q = prs_mem_get(ps, sizeof(uint32));
	if (q == NULL)
		return False;

	if (UNMARSHALLING(ps)) {
		if (ps->bigendian_data)
			*status = NT_STATUS(RIVAL(q,0));
		else
			*status = NT_STATUS(IVAL(q,0));
	} else {
		if (ps->bigendian_data)
			RSIVAL(q,0,NT_STATUS_V(*status));
		else
			SIVAL(q,0,NT_STATUS_V(*status));
	}

	DEBUGADD(5,("%s%04x %s: %s\n", tab_depth(5,depth), ps->data_offset, name,
		 dcerpc_errstr(talloc_tos(), NT_STATUS_V(*status))));

	ps->data_offset += sizeof(uint32);

	return True;
}
Beispiel #5
0
/*
  work out if a packet is complete for protocols that use a 32 bit network byte
  order length
*/
_PUBLIC_ NTSTATUS packet_full_request_u32(void *private_data, DATA_BLOB blob, size_t *size)
{
	if (blob.length < 4) {
		return STATUS_MORE_ENTRIES;
	}
	*size = 4 + RIVAL(blob.data, 0);
	if (*size > blob.length) {
		return STATUS_MORE_ENTRIES;
	}
	return NT_STATUS_OK;
}
Beispiel #6
0
static NTSTATUS smbXsrv_tcon_local_key_to_id(TDB_DATA key, uint32_t *id)
{
	if (id == NULL) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (key.dsize != SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE) {
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}

	*id = RIVAL(key.dptr, 0);

	return NT_STATUS_OK;
}
Beispiel #7
0
/* this function is due to be replaced */
void initrpcreply(char *inbuf, char *q)
{
	uint32 callid;

	SCVAL(q, 0, 5); q++; /* RPC version 5 */
	SCVAL(q, 0, 0); q++; /* minor version 0 */
	SCVAL(q, 0, 2); q++; /* RPC response packet */
	SCVAL(q, 0, 3); q++; /* first frag + last frag */
	RSIVAL(q, 0, 0x10000000); q += 4; /* packed data representation */
	RSSVAL(q, 0, 0); q += 2; /* fragment length, fill in later */
	SSVAL(q, 0, 0); q += 2; /* authentication length */
	callid = RIVAL(inbuf, 12);
	RSIVAL(q, 0, callid); q += 4; /* call identifier - match incoming RPC */
	SIVAL(q, 0, 0x18); q += 4; /* allocation hint (no idea) */
	SSVAL(q, 0, 0); q += 2; /* presentation context identifier */
	SCVAL(q, 0, 0); q++; /* cancel count */
	SCVAL(q, 0, 0); q++; /* reserved */
}
Beispiel #8
0
/*
 * These functions are for use in the deprecated
 * gensec_socket code (public because SPNEGO must
 * use them for recursion)
 */
NTSTATUS gensec_unwrap_packets(struct gensec_security *gensec_security,
					TALLOC_CTX *mem_ctx,
					const DATA_BLOB *in,
					DATA_BLOB *out,
					size_t *len_processed)
{
	if (!gensec_security->ops->unwrap_packets) {
		DATA_BLOB wrapped;
		NTSTATUS nt_status;
		size_t packet_size;
		if (in->length < 4) {
			/* Missing the header we already had! */
			DEBUG(0, ("Asked to unwrap packet of bogus length!  How did we get the short packet?!\n"));
			return NT_STATUS_INVALID_PARAMETER;
		}

		packet_size = RIVAL(in->data, 0);

		wrapped = data_blob_const(in->data + 4, packet_size);

		if (wrapped.length > (in->length - 4)) {
			DEBUG(0, ("Asked to unwrap packed of bogus length %d > %d!  How did we get this?!\n",
				  (int)wrapped.length, (int)(in->length - 4)));
			return NT_STATUS_INTERNAL_ERROR;
		}

		nt_status = gensec_unwrap(gensec_security,
					  mem_ctx,
					  &wrapped, out);
		if (!NT_STATUS_IS_OK(nt_status)) {
			return nt_status;
		}

		*len_processed = packet_size + 4;
		return nt_status;
	}
	return gensec_security->ops->unwrap_packets(gensec_security, mem_ctx, in, out,
						    len_processed);
}
Beispiel #9
0
BOOL prs_uint32s(BOOL charmode, const char *name, prs_struct *ps, int depth, uint32 *data32s, int len)
{
	int i;
	char *q = prs_mem_get(ps, len * sizeof(uint32));
	if (q == NULL)
		return False;

	if (UNMARSHALLING(ps)) {
		if (ps->bigendian_data) {
			for (i = 0; i < len; i++)
				data32s[i] = RIVAL(q, 4*i);
		} else {
			for (i = 0; i < len; i++)
				data32s[i] = IVAL(q, 4*i);
		}
	} else {
		if (ps->bigendian_data) {
			for (i = 0; i < len; i++)
				RSIVAL(q, 4*i, data32s[i]);
		} else {
			for (i = 0; i < len; i++)
				SIVAL(q, 4*i, data32s[i]);
		}
	}

	DEBUG(5,("%s%04x %s: ", tab_depth(depth), ps->data_offset, name));
	if (charmode)
		print_asc(5, (unsigned char*)data32s, 4*len);
	else {
		for (i = 0; i < len; i++)
			DEBUG(5,("%08x ", data32s[i]));
	}
    DEBUG(5,("\n"));

	ps->data_offset += (len * sizeof(uint32));

	return True;
}
Beispiel #10
0
/*
 * These functions are for use in the deprecated
 * gensec_socket code (public because SPNEGO must
 * use them for recursion)
 */
NTSTATUS gensec_packet_full_request(struct gensec_security *gensec_security,
				    DATA_BLOB blob, size_t *size)
{
	if (gensec_security->ops->packet_full_request) {
		return gensec_security->ops->packet_full_request(gensec_security,
								 blob, size);
	}
	if (gensec_security->ops->unwrap_packets) {
		if (blob.length) {
			*size = blob.length;
			return NT_STATUS_OK;
		}
		return STATUS_MORE_ENTRIES;
	}

	if (blob.length < 4) {
		return STATUS_MORE_ENTRIES;
	}
	*size = 4 + RIVAL(blob.data, 0);
	if (*size > blob.length) {
		return STATUS_MORE_ENTRIES;
	}
	return NT_STATUS_OK;
}
Beispiel #11
0
BOOL prs_uint32(const char *name, prs_struct *ps, int depth, uint32 *data32)
{
	char *q = prs_mem_get(ps, sizeof(uint32));
	if (q == NULL)
		return False;

	if (UNMARSHALLING(ps)) {
		if (ps->bigendian_data)
			*data32 = RIVAL(q,0);
		else
			*data32 = IVAL(q,0);
	} else {
		if (ps->bigendian_data)
			RSIVAL(q,0,*data32);
		else
			SIVAL(q,0,*data32);
	}

	DEBUG(5,("%s%04x %s: %08x\n", tab_depth(depth), ps->data_offset, name, *data32));

	ps->data_offset += sizeof(uint32);

	return True;
}
Beispiel #12
0
/* this performs a SASL/gssapi bind
   we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl
   is very dependent on correctly configured DNS whereas
   this routine is much less fragile
   see RFC2078 and RFC2222 for details
*/
static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name)
{
	uint32_t minor_status;
	gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
	gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
	gss_OID mech_type = GSS_C_NULL_OID;
	gss_buffer_desc output_token, input_token;
	uint32_t req_flags, ret_flags;
	int conf_state;
	struct berval cred;
	struct berval *scred = NULL;
	int i=0;
	int gss_rc, rc;
	uint8_t *p;
	uint32_t max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED;
	uint8_t wrap_type = ADS_SASLWRAP_TYPE_PLAIN;
	ADS_STATUS status;
	struct ads_saslwrap *wrap = &ads->ldap_wrap_data;

	input_token.value = NULL;
	input_token.length = 0;

	status = ads_init_gssapi_cred(ads, &gss_cred);
	if (!ADS_ERR_OK(status)) {
		goto failed;
	}

	/*
	 * Note: here we always ask the gssapi for sign and seal
	 *       as this is negotiated later after the mutal
	 *       authentication
	 */
	req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;

	for (i=0; i < MAX_GSS_PASSES; i++) {
		gss_rc = gss_init_sec_context(&minor_status,
					  gss_cred,
					  &context_handle,
					  serv_name,
					  mech_type,
					  req_flags,
					  0,
					  NULL,
					  &input_token,
					  NULL,
					  &output_token,
					  &ret_flags,
					  NULL);
		if (scred) {
			ber_bvfree(scred);
			scred = NULL;
		}
		if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
			status = ADS_ERROR_GSS(gss_rc, minor_status);
			goto failed;
		}

		cred.bv_val = (char *)output_token.value;
		cred.bv_len = output_token.length;

		rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, 
				      &scred);
		if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
			status = ADS_ERROR(rc);
			goto failed;
		}

		if (output_token.value) {
			gss_release_buffer(&minor_status, &output_token);
		}

		if (scred) {
			input_token.value = scred->bv_val;
			input_token.length = scred->bv_len;
		} else {
			input_token.value = NULL;
			input_token.length = 0;
		}

		if (gss_rc == 0) break;
	}

	gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
			    &conf_state,NULL);
	if (scred) {
		ber_bvfree(scred);
		scred = NULL;
	}
	if (gss_rc) {
		status = ADS_ERROR_GSS(gss_rc, minor_status);
		goto failed;
	}

	p = (uint8_t *)output_token.value;

#if 0
	file_save("sasl_gssapi.dat", output_token.value, output_token.length);
#endif

	if (p) {
		wrap_type = CVAL(p,0);
		SCVAL(p,0,0);
		max_msg_size = RIVAL(p,0);
	}

	gss_release_buffer(&minor_status, &output_token);

	if (!(wrap_type & wrap->wrap_type)) {
		/*
		 * the server doesn't supports the wrap
		 * type we want :-(
		 */
		DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n",
			wrap->wrap_type, wrap_type));
		DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n"));
		status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
		goto failed;
	}

	/* 0x58 is the minimum windows accepts */
	if (max_msg_size < 0x58) {
		max_msg_size = 0x58;
	}

	output_token.length = 4;
	output_token.value = SMB_MALLOC(output_token.length);
	if (!output_token.value) {
		output_token.length = 0;
		status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
		goto failed;
	}
	p = (uint8_t *)output_token.value;

	RSIVAL(p,0,max_msg_size);
	SCVAL(p,0,wrap->wrap_type);

	/*
	 * we used to add sprintf("dn:%s", ads->config.bind_path) here.
	 * but using ads->config.bind_path is the wrong! It should be
	 * the DN of the user object!
	 *
	 * w2k3 gives an error when we send an incorrect DN, but sending nothing
	 * is ok and matches the information flow used in GSS-SPNEGO.
	 */

	gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
			&output_token, /* used as *input* here. */
			&conf_state,
			&input_token); /* Used as *output* here. */
	if (gss_rc) {
		status = ADS_ERROR_GSS(gss_rc, minor_status);
		output_token.length = 0;
		SAFE_FREE(output_token.value);
		goto failed;
	}

	/* We've finished with output_token. */
	SAFE_FREE(output_token.value);
	output_token.length = 0;

	cred.bv_val = (char *)input_token.value;
	cred.bv_len = input_token.length;

	rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, 
			      &scred);
	gss_release_buffer(&minor_status, &input_token);
	status = ADS_ERROR(rc);
	if (!ADS_ERR_OK(status)) {
		goto failed;
	}

	if (wrap->wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
		gss_rc = gss_wrap_size_limit(&minor_status, context_handle,
					     (wrap->wrap_type == ADS_SASLWRAP_TYPE_SEAL),
					     GSS_C_QOP_DEFAULT,
					     max_msg_size, &wrap->out.max_unwrapped);
		if (gss_rc) {
			status = ADS_ERROR_GSS(gss_rc, minor_status);
			goto failed;
		}

		wrap->out.sig_size = max_msg_size - wrap->out.max_unwrapped;
		wrap->in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */
		wrap->in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
		status = ads_setup_sasl_wrapping(wrap->wrap_private_data, ads->ldap.ld,
						 &ads_sasl_gssapi_ops,
						 context_handle);
		if (!ADS_ERR_OK(status)) {
			DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
				ads_errstr(status)));
			goto failed;
		}
		/* make sure we don't free context_handle */
		context_handle = GSS_C_NO_CONTEXT;
	}

failed:
	if (gss_cred != GSS_C_NO_CREDENTIAL)
		gss_release_cred(&minor_status, &gss_cred);
	if (context_handle != GSS_C_NO_CONTEXT)
		gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);

	if(scred)
		ber_bvfree(scred);
	return status;
}
Beispiel #13
0
static krb5_error_code parse_setpw_reply(krb5_context context,
					 bool use_tcp,
					 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;
	unsigned int msg_length = packet->length;


	if (packet->length < (use_tcp ? 8 : 4)) {
		return KRB5KRB_AP_ERR_MODIFIED;
	}
	
	p = (char *)packet->data;
	/*
	** see if it is an error
	*/
	if (krb5_is_krb_error(packet)) {

		ret = handle_krberror_packet(context, packet);
		if (ret) {
			return ret;
		}
	}

	
	/* tcp... */
	if (use_tcp) {
		msg_length -= 4;
		if (RIVAL(p, 0) != msg_length) {
			DEBUG(1,("Bad TCP packet length (%d/%d) from kpasswd server\n",
			RIVAL(p, 0), msg_length));
			return KRB5KRB_AP_ERR_MODIFIED;
		}

		p += 4;
	}
	
	if (RSVAL(p, 0) != msg_length) {
		DEBUG(1,("Bad packet length (%d/%d) from kpasswd server\n",
			 RSVAL(p, 0), msg_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 = (char *)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 (%d)\n", errstr, res_code));

		return kpasswd_err_to_krb5_err(res_code);
	}
}
Beispiel #14
0
bool receive_getdc_response(TALLOC_CTX *mem_ctx,
			    struct sockaddr_storage *dc_ss,
			    const char *domain_name,
			    uint32_t *nt_version,
			    const char **dc_name,
			    struct netlogon_samlogon_response **_r)
{
	struct packet_struct *packet;
	const char *my_mailslot = NULL;
	struct in_addr dc_ip;
	DATA_BLOB blob;
	struct netlogon_samlogon_response r;
	union dgram_message_body p;
	enum ndr_err_code ndr_err;
	NTSTATUS status;

	const char *returned_dc = NULL;
	const char *returned_domain = NULL;

	if (dc_ss->ss_family != AF_INET) {
		return false;
	}

	dc_ip = ((struct sockaddr_in *)dc_ss)->sin_addr;

	my_mailslot = mailslot_name(mem_ctx, dc_ip);
	if (!my_mailslot) {
		return false;
	}

	packet = receive_unexpected(DGRAM_PACKET, 0, my_mailslot);

	if (packet == NULL) {
		DEBUG(5, ("Did not receive packet for %s\n", my_mailslot));
		return False;
	}

	DEBUG(5, ("Received packet for %s\n", my_mailslot));

	blob = data_blob_const(packet->packet.dgram.data,
			       packet->packet.dgram.datasize);

	if (blob.length < 4) {
		DEBUG(0,("invalid length: %d\n", (int)blob.length));
		return false;
	}

	if (RIVAL(blob.data,0) != DGRAM_SMB) {
		DEBUG(0,("invalid packet\n"));
		return false;
	}

	blob.data += 4;
	blob.length -= 4;

	ndr_err = ndr_pull_union_blob_all(&blob, mem_ctx, &p, DGRAM_SMB,
		       (ndr_pull_flags_fn_t)ndr_pull_dgram_smb_packet);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		DEBUG(0,("failed to parse packet\n"));
		return false;
	}

	if (p.smb.smb_command != SMB_TRANSACTION) {
		DEBUG(0,("invalid smb_command: %d\n", p.smb.smb_command));
		return false;
	}

	if (DEBUGLEVEL >= 10) {
		NDR_PRINT_DEBUG(dgram_smb_packet, &p);
	}

	blob = p.smb.body.trans.data;

	ZERO_STRUCT(r);

	status = pull_netlogon_samlogon_response(&blob, mem_ctx, &r);
	if (!NT_STATUS_IS_OK(status)) {
		return false;
	}

	map_netlogon_samlogon_response(&r);

	/* do we still need this ? */
	*nt_version = r.ntver;

	returned_domain = r.data.nt5_ex.domain;
	returned_dc = r.data.nt5_ex.pdc_name;

	if (!strequal(returned_domain, domain_name)) {
		DEBUG(3, ("GetDC: Expected domain %s, got %s\n",
			  domain_name, returned_domain));
		return false;
	}

	*dc_name = talloc_strdup(mem_ctx, returned_dc);
	if (!*dc_name) {
		return false;
	}

	if (**dc_name == '\\')	*dc_name += 1;
	if (**dc_name == '\\')	*dc_name += 1;

	if (_r) {
		*_r = (struct netlogon_samlogon_response *)talloc_memdup(
			mem_ctx, &r, sizeof(struct netlogon_samlogon_response));
		if (!*_r) {
			return false;
		}
	}

	DEBUG(10, ("GetDC gave name %s for domain %s\n",
		   *dc_name, returned_domain));

	return True;
}
Beispiel #15
0
static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, 
				     TALLOC_CTX *out_mem_ctx,
				     struct tevent_context *ev,
				     const DATA_BLOB in, DATA_BLOB *out)
{
	struct gensec_gssapi_state *gensec_gssapi_state
		= talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
	NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
	OM_uint32 maj_stat, min_stat;
	OM_uint32 min_stat2;
	gss_buffer_desc input_token = { 0, NULL };
	gss_buffer_desc output_token = { 0, NULL };

	gss_OID gss_oid_p = NULL;
	OM_uint32 time_req = 0;
	OM_uint32 time_rec = 0;
	struct timeval tv;

	time_req = gensec_setting_int(gensec_security->settings,
				      "gensec_gssapi", "requested_life_time",
				      time_req);

	input_token.length = in.length;
	input_token.value = in.data;

	switch (gensec_gssapi_state->sasl_state) {
	case STAGE_GSS_NEG:
	{
		switch (gensec_security->gensec_role) {
		case GENSEC_CLIENT:
		{
#ifdef SAMBA4_USES_HEIMDAL
			struct gsskrb5_send_to_kdc send_to_kdc;
			krb5_error_code ret;
#endif

			nt_status = gensec_gssapi_client_creds(gensec_security, ev);
			if (!NT_STATUS_IS_OK(nt_status)) {
				return nt_status;
			}

#ifdef SAMBA4_USES_HEIMDAL
			send_to_kdc.func = smb_krb5_send_and_recv_func;
			send_to_kdc.ptr = ev;

			min_stat = gsskrb5_set_send_to_kdc(&send_to_kdc);
			if (min_stat) {
				DEBUG(1,("gensec_gssapi_update: gsskrb5_set_send_to_kdc failed\n"));
				return NT_STATUS_INTERNAL_ERROR;
			}
#endif
			maj_stat = gss_init_sec_context(&min_stat, 
							gensec_gssapi_state->client_cred->creds,
							&gensec_gssapi_state->gssapi_context, 
							gensec_gssapi_state->server_name, 
							gensec_gssapi_state->gss_oid,
							gensec_gssapi_state->gss_want_flags, 
							time_req,
							gensec_gssapi_state->input_chan_bindings,
							&input_token, 
							&gss_oid_p,
							&output_token, 
							&gensec_gssapi_state->gss_got_flags, /* ret flags */
							&time_rec);
			if (gss_oid_p) {
				gensec_gssapi_state->gss_oid = gss_oid_p;
			}

#ifdef SAMBA4_USES_HEIMDAL
			send_to_kdc.func = smb_krb5_send_and_recv_func;
			send_to_kdc.ptr = NULL;

			ret = gsskrb5_set_send_to_kdc(&send_to_kdc);
			if (ret) {
				DEBUG(1,("gensec_gssapi_update: gsskrb5_set_send_to_kdc failed\n"));
				return NT_STATUS_INTERNAL_ERROR;
			}
#endif
			break;
		}
		case GENSEC_SERVER:
		{
			maj_stat = gss_accept_sec_context(&min_stat, 
							  &gensec_gssapi_state->gssapi_context, 
							  gensec_gssapi_state->server_cred->creds,
							  &input_token, 
							  gensec_gssapi_state->input_chan_bindings,
							  &gensec_gssapi_state->client_name, 
							  &gss_oid_p,
							  &output_token, 
							  &gensec_gssapi_state->gss_got_flags, 
							  &time_rec,
							  &gensec_gssapi_state->delegated_cred_handle);
			if (gss_oid_p) {
				gensec_gssapi_state->gss_oid = gss_oid_p;
			}
			break;
		}
		default:
			return NT_STATUS_INVALID_PARAMETER;
			
		}

		gensec_gssapi_state->gss_exchange_count++;

		if (maj_stat == GSS_S_COMPLETE) {
			*out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
			gss_release_buffer(&min_stat2, &output_token);
			
			if (gensec_gssapi_state->gss_got_flags & GSS_C_DELEG_FLAG &&
			    gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
				DEBUG(5, ("gensec_gssapi: credentials were delegated\n"));
			} else {
				DEBUG(5, ("gensec_gssapi: NO credentials were delegated\n"));
			}

			tv = timeval_current_ofs(time_rec, 0);
			gensec_gssapi_state->expire_time = timeval_to_nttime(&tv);

			/* We may have been invoked as SASL, so there
			 * is more work to do */
			if (gensec_gssapi_state->sasl) {
				gensec_gssapi_state->sasl_state = STAGE_SASL_SSF_NEG;
				return NT_STATUS_MORE_PROCESSING_REQUIRED;
			} else {
				gensec_gssapi_state->sasl_state = STAGE_DONE;

				if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
					DEBUG(5, ("GSSAPI Connection will be cryptographically sealed\n"));
				} else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
					DEBUG(5, ("GSSAPI Connection will be cryptographically signed\n"));
				} else {
					DEBUG(5, ("GSSAPI Connection will have no cryptographic protection\n"));
				}

				return NT_STATUS_OK;
			}
		} else if (maj_stat == GSS_S_CONTINUE_NEEDED) {
			*out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
			gss_release_buffer(&min_stat2, &output_token);
			
			return NT_STATUS_MORE_PROCESSING_REQUIRED;
		} else if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
			gss_cred_id_t creds = NULL;
			gss_name_t name;
			gss_buffer_desc buffer;
			OM_uint32 lifetime = 0;
			gss_cred_usage_t usage;
			const char *role = NULL;
			DEBUG(0, ("GSS %s Update(krb5)(%d) Update failed, credentials expired during GSSAPI handshake!\n",
				  role,
				  gensec_gssapi_state->gss_exchange_count));

			
			switch (gensec_security->gensec_role) {
			case GENSEC_CLIENT:
				creds = gensec_gssapi_state->client_cred->creds;
				role = "client";
				break;
			case GENSEC_SERVER:
				creds = gensec_gssapi_state->server_cred->creds;
				role = "server";
				break;
			}

			maj_stat = gss_inquire_cred(&min_stat, 
						    creds,
						    &name, &lifetime, &usage, NULL);

			if (maj_stat == GSS_S_COMPLETE) {
				const char *usage_string = NULL;
				switch (usage) {
				case GSS_C_BOTH:
					usage_string = "GSS_C_BOTH";
					break;
				case GSS_C_ACCEPT:
					usage_string = "GSS_C_ACCEPT";
					break;
				case GSS_C_INITIATE:
					usage_string = "GSS_C_INITIATE";
					break;
				}
				maj_stat = gss_display_name(&min_stat, name, &buffer, NULL);
				if (maj_stat) {
					buffer.value = NULL;
					buffer.length = 0;
				}
				if (lifetime > 0) {
					DEBUG(0, ("GSSAPI gss_inquire_cred indicates expiry of %*.*s in %u sec for %s\n", 
						  (int)buffer.length, (int)buffer.length, (char *)buffer.value, 
						  lifetime, usage_string));
				} else {
					DEBUG(0, ("GSSAPI gss_inquire_cred indicates %*.*s has already expired for %s\n", 
						  (int)buffer.length, (int)buffer.length, (char *)buffer.value, 
						  usage_string));
				}
				gss_release_buffer(&min_stat, &buffer);
				gss_release_name(&min_stat, &name);
			} else if (maj_stat != GSS_S_COMPLETE) {
				DEBUG(0, ("inquiry of credential lifefime via GSSAPI gss_inquire_cred failed: %s\n",
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
			}
			return NT_STATUS_INVALID_PARAMETER;
		} else if (smb_gss_oid_equal(gensec_gssapi_state->gss_oid,
					     gss_mech_krb5)) {
			switch (min_stat) {
			case KRB5KRB_AP_ERR_TKT_NYV:
				DEBUG(1, ("Error with ticket to contact %s: possible clock skew between us and the KDC or target server: %s\n",
					  gensec_gssapi_state->target_principal,
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_TIME_DIFFERENCE_AT_DC; /* Make SPNEGO ignore us, we can't go any further here */
			case KRB5KRB_AP_ERR_TKT_EXPIRED:
				DEBUG(1, ("Error with ticket to contact %s: ticket is expired, possible clock skew between us and the KDC or target server: %s\n",
					  gensec_gssapi_state->target_principal,
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
			case KRB5_KDC_UNREACH:
				DEBUG(3, ("Cannot reach a KDC we require in order to obtain a ticket to %s: %s\n",
					  gensec_gssapi_state->target_principal,
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_NO_LOGON_SERVERS; /* Make SPNEGO ignore us, we can't go any further here */
			case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
				DEBUG(3, ("Server %s is not registered with our KDC: %s\n",
					  gensec_gssapi_state->target_principal,
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
			case KRB5KRB_AP_ERR_MSG_TYPE:
				/* garbage input, possibly from the auto-mech detection */
				return NT_STATUS_INVALID_PARAMETER;
			default:
				DEBUG(1, ("GSS %s Update(krb5)(%d) Update failed: %s\n",
					  gensec_security->gensec_role == GENSEC_CLIENT ? "client" : "server",
					  gensec_gssapi_state->gss_exchange_count,
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_LOGON_FAILURE;
			}
		} else {
			DEBUG(1, ("GSS %s Update(%d) failed: %s\n",
				  gensec_security->gensec_role == GENSEC_CLIENT ? "client" : "server",
				  gensec_gssapi_state->gss_exchange_count,
				  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
			return NT_STATUS_LOGON_FAILURE;
		}
		break;
	}

	/* These last two stages are only done if we were invoked as SASL */
	case STAGE_SASL_SSF_NEG:
	{
		switch (gensec_security->gensec_role) {
		case GENSEC_CLIENT:
		{
			uint8_t maxlength_proposed[4]; 
			uint8_t maxlength_accepted[4]; 
			uint8_t security_supported;
			int conf_state;
			gss_qop_t qop_state;
			input_token.length = in.length;
			input_token.value = in.data;

			/* As a client, we have just send a
			 * zero-length blob to the server (after the
			 * normal GSSAPI exchange), and it has replied
			 * with it's SASL negotiation */
			
			maj_stat = gss_unwrap(&min_stat, 
					      gensec_gssapi_state->gssapi_context, 
					      &input_token,
					      &output_token, 
					      &conf_state,
					      &qop_state);
			if (GSS_ERROR(maj_stat)) {
				DEBUG(1, ("gensec_gssapi_update: GSS UnWrap of SASL protection negotiation failed: %s\n", 
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_ACCESS_DENIED;
			}
			
			if (output_token.length < 4) {
				return NT_STATUS_INVALID_PARAMETER;
			}

			memcpy(maxlength_proposed, output_token.value, 4);
			gss_release_buffer(&min_stat, &output_token);

			/* first byte is the proposed security */
			security_supported = maxlength_proposed[0];
			maxlength_proposed[0] = '\0';
			
			/* Rest is the proposed max wrap length */
			gensec_gssapi_state->max_wrap_buf_size = MIN(RIVAL(maxlength_proposed, 0), 
								     gensec_gssapi_state->max_wrap_buf_size);
			gensec_gssapi_state->sasl_protection = 0;
			if (security_supported & NEG_SEAL) {
				if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
					gensec_gssapi_state->sasl_protection |= NEG_SEAL;
				}
			}
			if (security_supported & NEG_SIGN) {
				if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
					gensec_gssapi_state->sasl_protection |= NEG_SIGN;
				}
			}
			if (security_supported & NEG_NONE) {
				gensec_gssapi_state->sasl_protection |= NEG_NONE;
			}
			if (gensec_gssapi_state->sasl_protection == 0) {
				DEBUG(1, ("Remote server does not support unprotected connections\n"));
				return NT_STATUS_ACCESS_DENIED;
			}

			/* Send back the negotiated max length */

			RSIVAL(maxlength_accepted, 0, gensec_gssapi_state->max_wrap_buf_size);

			maxlength_accepted[0] = gensec_gssapi_state->sasl_protection;
			
			input_token.value = maxlength_accepted;
			input_token.length = sizeof(maxlength_accepted);

			maj_stat = gss_wrap(&min_stat, 
					    gensec_gssapi_state->gssapi_context, 
					    false,
					    GSS_C_QOP_DEFAULT,
					    &input_token,
					    &conf_state,
					    &output_token);
			if (GSS_ERROR(maj_stat)) {
				DEBUG(1, ("GSS Update(SSF_NEG): GSS Wrap failed: %s\n", 
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_ACCESS_DENIED;
			}
			
			*out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
			gss_release_buffer(&min_stat, &output_token);

			/* quirk:  This changes the value that gensec_have_feature returns, to be that after SASL negotiation */
			gensec_gssapi_state->sasl_state = STAGE_DONE;

			if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
				DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographically sealed\n"));
			} else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
				DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographically signed\n"));
			} else {
				DEBUG(3, ("SASL/GSSAPI Connection to server will have no cryptographically protection\n"));
			}

			return NT_STATUS_OK;
		}
		case GENSEC_SERVER:
		{
			uint8_t maxlength_proposed[4]; 
			uint8_t security_supported = 0x0;
			int conf_state;

			/* As a server, we have just been sent a zero-length blob (note this, but it isn't fatal) */
			if (in.length != 0) {
				DEBUG(1, ("SASL/GSSAPI: client sent non-zero length starting SASL negotiation!\n"));
			}
			
			/* Give the client some idea what we will support */
			  
			RSIVAL(maxlength_proposed, 0, gensec_gssapi_state->max_wrap_buf_size);
			/* first byte is the proposed security */
			maxlength_proposed[0] = '\0';
			
			gensec_gssapi_state->sasl_protection = 0;
			if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
				security_supported |= NEG_SEAL;
			} 
			if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
				security_supported |= NEG_SIGN;
			}
			if (security_supported == 0) {
				/* If we don't support anything, this must be 0 */
				RSIVAL(maxlength_proposed, 0, 0x0);
			}

			/* TODO:  We may not wish to support this */
			security_supported |= NEG_NONE;
			maxlength_proposed[0] = security_supported;
			
			input_token.value = maxlength_proposed;
			input_token.length = sizeof(maxlength_proposed);

			maj_stat = gss_wrap(&min_stat, 
					    gensec_gssapi_state->gssapi_context, 
					    false,
					    GSS_C_QOP_DEFAULT,
					    &input_token,
					    &conf_state,
					    &output_token);
			if (GSS_ERROR(maj_stat)) {
				DEBUG(1, ("GSS Update(SSF_NEG): GSS Wrap failed: %s\n", 
					  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
				return NT_STATUS_ACCESS_DENIED;
			}
			
			*out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
			gss_release_buffer(&min_stat, &output_token);

			gensec_gssapi_state->sasl_state = STAGE_SASL_SSF_ACCEPT;
			return NT_STATUS_MORE_PROCESSING_REQUIRED;
		}
		default:
  			return NT_STATUS_INVALID_PARAMETER;
			
		}
	}
	/* This is s server-only stage */
	case STAGE_SASL_SSF_ACCEPT:
	{
		uint8_t maxlength_accepted[4]; 
		uint8_t security_accepted;
		int conf_state;
		gss_qop_t qop_state;
		input_token.length = in.length;
		input_token.value = in.data;
			
		maj_stat = gss_unwrap(&min_stat, 
				      gensec_gssapi_state->gssapi_context, 
				      &input_token,
				      &output_token, 
				      &conf_state,
				      &qop_state);
		if (GSS_ERROR(maj_stat)) {
			DEBUG(1, ("gensec_gssapi_update: GSS UnWrap of SASL protection negotiation failed: %s\n", 
				  gssapi_error_string(out_mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
			return NT_STATUS_ACCESS_DENIED;
		}
			
		if (output_token.length < 4) {
			return NT_STATUS_INVALID_PARAMETER;
		}

		memcpy(maxlength_accepted, output_token.value, 4);
		gss_release_buffer(&min_stat, &output_token);
		
		/* first byte is the proposed security */
		security_accepted = maxlength_accepted[0];
		maxlength_accepted[0] = '\0';

		/* Rest is the proposed max wrap length */
		gensec_gssapi_state->max_wrap_buf_size = MIN(RIVAL(maxlength_accepted, 0), 
							     gensec_gssapi_state->max_wrap_buf_size);

		gensec_gssapi_state->sasl_protection = 0;
		if (security_accepted & NEG_SEAL) {
			if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
				DEBUG(1, ("Remote client wanted seal, but gensec refused\n"));
				return NT_STATUS_ACCESS_DENIED;
			}
			gensec_gssapi_state->sasl_protection |= NEG_SEAL;
		}
		if (security_accepted & NEG_SIGN) {
			if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
				DEBUG(1, ("Remote client wanted sign, but gensec refused\n"));
				return NT_STATUS_ACCESS_DENIED;
			}
			gensec_gssapi_state->sasl_protection |= NEG_SIGN;
		}
		if (security_accepted & NEG_NONE) {
			gensec_gssapi_state->sasl_protection |= NEG_NONE;
		}

		/* quirk:  This changes the value that gensec_have_feature returns, to be that after SASL negotiation */
		gensec_gssapi_state->sasl_state = STAGE_DONE;
		if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
			DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographically sealed\n"));
		} else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
			DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographically signed\n"));
		} else {
			DEBUG(5, ("SASL/GSSAPI Connection from client will have no cryptographic protection\n"));
		}

		*out = data_blob(NULL, 0);
		return NT_STATUS_OK;	
	}
	default:
		return NT_STATUS_INVALID_PARAMETER;
	}
}
Beispiel #16
0
static bool parse_getdc_response(
	struct packet_struct *packet,
	TALLOC_CTX *mem_ctx,
	const char *domain_name,
	uint32_t *nt_version,
	const char **dc_name,
	struct netlogon_samlogon_response **samlogon_response)
{
	DATA_BLOB blob;
	struct netlogon_samlogon_response *r;
	union dgram_message_body p;
	enum ndr_err_code ndr_err;
	NTSTATUS status;

	const char *returned_dc = NULL;
	const char *returned_domain = NULL;

	blob = data_blob_const(packet->packet.dgram.data,
			       packet->packet.dgram.datasize);
	if (blob.length < 4) {
		DEBUG(1, ("invalid length: %d\n", (int)blob.length));
		return false;
	}

	if (RIVAL(blob.data,0) != DGRAM_SMB) {
		DEBUG(1, ("invalid packet\n"));
		return false;
	}

	blob.data += 4;
	blob.length -= 4;

	ndr_err = ndr_pull_union_blob_all(&blob, mem_ctx, &p, DGRAM_SMB,
		       (ndr_pull_flags_fn_t)ndr_pull_dgram_smb_packet);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		DEBUG(1, ("failed to parse packet\n"));
		return false;
	}

	if (p.smb.smb_command != SMB_TRANSACTION) {
		DEBUG(1, ("invalid smb_command: %d\n", p.smb.smb_command));
		return false;
	}

	if (DEBUGLEVEL >= 10) {
		NDR_PRINT_DEBUG(dgram_smb_packet, &p);
	}

	blob = p.smb.body.trans.data;

	r = talloc_zero(mem_ctx, struct netlogon_samlogon_response);
	if (!r) {
		return false;
	}

	status = pull_netlogon_samlogon_response(&blob, r, r);
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(r);
		return false;
	}

	map_netlogon_samlogon_response(r);

	/* do we still need this ? */
	*nt_version = r->ntver;

	returned_domain = r->data.nt5_ex.domain_name;
	returned_dc = r->data.nt5_ex.pdc_name;

	if (!strequal(returned_domain, domain_name)) {
		DEBUG(3, ("GetDC: Expected domain %s, got %s\n",
			  domain_name, returned_domain));
		TALLOC_FREE(r);
		return false;
	}

	if (*returned_dc == '\\') returned_dc += 1;
	if (*returned_dc == '\\') returned_dc += 1;

	*dc_name = talloc_strdup(mem_ctx, returned_dc);
	if (!*dc_name) {
		TALLOC_FREE(r);
		return false;
	}

	if (samlogon_response) {
		*samlogon_response = r;
	} else {
		TALLOC_FREE(r);
	}

	DEBUG(10, ("GetDC gave name %s for domain %s\n",
		   *dc_name, returned_domain));

	return True;
}