示例#1
0
static int reply_spnego_negotiate(connection_struct *conn, 
				  char *inbuf,
				  char *outbuf,
				  uint16 vuid,
				  int length, int bufsize,
				  DATA_BLOB blob1,
				  AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
{
	DATA_BLOB secblob;
	DATA_BLOB chal;
	BOOL got_kerberos_mechanism = False;
	NTSTATUS status;

	status = parse_spnego_mechanisms(blob1, &secblob, &got_kerberos_mechanism);
	if (!NT_STATUS_IS_OK(status)) {
		/* Kill the intermediate vuid */
		invalidate_vuid(vuid);
		return ERROR_NT(nt_status_squash(status));
	}

	DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n", (unsigned long)secblob.length));

#ifdef HAVE_KRB5
	if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
		BOOL destroy_vuid = True;
		int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
						length, bufsize, &secblob, &destroy_vuid);
		data_blob_free(&secblob);
		if (destroy_vuid) {
			/* Kill the intermediate vuid */
			invalidate_vuid(vuid);
		}
		return ret;
	}
#endif

	if (*auth_ntlmssp_state) {
		auth_ntlmssp_end(auth_ntlmssp_state);
	}

	status = auth_ntlmssp_start(auth_ntlmssp_state);
	if (!NT_STATUS_IS_OK(status)) {
		/* Kill the intermediate vuid */
		invalidate_vuid(vuid);
		return ERROR_NT(nt_status_squash(status));
	}

	status = auth_ntlmssp_update(*auth_ntlmssp_state, 
					secblob, &chal);

	data_blob_free(&secblob);

	reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state,
			     &chal, status, True);

	data_blob_free(&chal);

	/* already replied */
	return -1;
}
示例#2
0
static NTSTATUS smbd_smb2_raw_ntlmssp_auth(struct smbd_smb2_session *session,
					struct smbd_smb2_request *smb2req,
					uint8_t in_security_mode,
					DATA_BLOB in_security_buffer,
					uint16_t *out_session_flags,
					DATA_BLOB *out_security_buffer,
					uint64_t *out_session_id)
{
	NTSTATUS status;

	if (session->auth_ntlmssp_state == NULL) {
		status = auth_ntlmssp_prepare(session->sconn->remote_address,
					    &session->auth_ntlmssp_state);
		if (!NT_STATUS_IS_OK(status)) {
			TALLOC_FREE(session);
			return status;
		}

		auth_ntlmssp_want_feature(session->auth_ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY);

		if (session->sconn->use_gensec_hook) {
			status = auth_generic_start(session->auth_ntlmssp_state, GENSEC_OID_SPNEGO);
		} else {
			status = auth_ntlmssp_start(session->auth_ntlmssp_state);
		}
		if (!NT_STATUS_IS_OK(status)) {
			TALLOC_FREE(session);
			return status;
		}
	}

	/* RAW NTLMSSP */
	status = auth_ntlmssp_update(session->auth_ntlmssp_state,
				     smb2req,
				     in_security_buffer,
				     out_security_buffer);

	if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
		*out_session_id = session->vuid;
		return status;
	}

	status = auth_ntlmssp_session_info(session,
					   session->auth_ntlmssp_state,
					   &session->session_info);

	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(session->auth_ntlmssp_state);
		TALLOC_FREE(session);
		return status;
	}
	*out_session_id = session->vuid;

	return smbd_smb2_common_ntlmssp_auth_return(session,
						smb2req,
						in_security_mode,
						in_security_buffer,
						out_session_flags,
						out_session_id);
}
示例#3
0
static NTSTATUS smbd_smb2_raw_ntlmssp_auth(struct smbd_smb2_session *session,
					struct smbd_smb2_request *smb2req,
					uint8_t in_security_mode,
					DATA_BLOB in_security_buffer,
					uint16_t *out_session_flags,
					DATA_BLOB *out_security_buffer,
					uint64_t *out_session_id)
{
	NTSTATUS status;
	DATA_BLOB secblob_out = data_blob_null;

	*out_security_buffer = data_blob_null;

	if (session->auth_ntlmssp_state == NULL) {
		status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
		if (!NT_STATUS_IS_OK(status)) {
			TALLOC_FREE(session);
			return status;
		}
	}

	/* RAW NTLMSSP */
	status = auth_ntlmssp_update(session->auth_ntlmssp_state,
				     in_security_buffer,
				     &secblob_out);

	if (NT_STATUS_IS_OK(status) ||
			NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
		*out_security_buffer = data_blob_talloc(smb2req,
						secblob_out.data,
						secblob_out.length);
		if (secblob_out.data && out_security_buffer->data == NULL) {
			TALLOC_FREE(session->auth_ntlmssp_state);
			TALLOC_FREE(session);
			return NT_STATUS_NO_MEMORY;
		}
	}

	if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
		*out_session_id = session->vuid;
		return status;
	}

	status = setup_ntlmssp_session_info(session, status);

	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(session->auth_ntlmssp_state);
		TALLOC_FREE(session);
		return status;
	}
	*out_session_id = session->vuid;

	return smbd_smb2_common_ntlmssp_auth_return(session,
						smb2req,
						in_security_mode,
						in_security_buffer,
						out_session_flags,
						out_session_id);
}
示例#4
0
NTSTATUS ntlmssp_server_auth_start(TALLOC_CTX *mem_ctx,
				   bool do_sign,
				   bool do_seal,
				   bool is_dcerpc,
				   DATA_BLOB *token_in,
				   DATA_BLOB *token_out,
				   const struct tsocket_address *remote_address,
				   struct auth_ntlmssp_state **ctx)
{
	struct auth_ntlmssp_state *a = NULL;
	NTSTATUS status;

	status = auth_ntlmssp_start(remote_address, &a);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, (__location__ ": auth_ntlmssp_start failed: %s\n",
			  nt_errstr(status)));
		return status;
	}

	/* Clear flags, then set them according to requested flags */
	auth_ntlmssp_and_flags(a, ~(NTLMSSP_NEGOTIATE_SIGN |
					NTLMSSP_NEGOTIATE_SEAL));

	if (do_sign) {
		auth_ntlmssp_or_flags(a, NTLMSSP_NEGOTIATE_SIGN);
	}
	if (do_seal) {
		/* Always implies both sign and seal for ntlmssp */
		auth_ntlmssp_or_flags(a, NTLMSSP_NEGOTIATE_SIGN |
					 NTLMSSP_NEGOTIATE_SEAL);
	}

	status = auth_ntlmssp_update(a, *token_in, token_out);
	if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
		DEBUG(0, (__location__ ": auth_ntlmssp_update failed: %s\n",
			  nt_errstr(status)));
		goto done;
	}

	/* Make sure data is bound to the memctx, to be freed the caller */
	talloc_steal(mem_ctx, token_out->data);
	/* steal ntlmssp context too */
	*ctx = talloc_move(mem_ctx, &a);

	status = NT_STATUS_OK;

done:
	if (!NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(a);
	}

	return status;
}
示例#5
0
static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session,
					struct smbd_smb2_request *smb2req,
					uint8_t in_security_mode,
					DATA_BLOB in_security_buffer,
					uint16_t *out_session_flags,
					DATA_BLOB *out_security_buffer,
					uint64_t *out_session_id)
{
	DATA_BLOB auth = data_blob_null;
	DATA_BLOB auth_out = data_blob_null;
	NTSTATUS status;

	if (!spnego_parse_auth(talloc_tos(), in_security_buffer, &auth)) {
		TALLOC_FREE(session);
		return NT_STATUS_LOGON_FAILURE;
	}

	if (auth.data[0] == ASN1_APPLICATION(0)) {
		/* Might be a second negTokenTarg packet */
		DATA_BLOB secblob_in = data_blob_null;
		char *kerb_mech = NULL;

		status = parse_spnego_mechanisms(talloc_tos(),
				in_security_buffer,
				&secblob_in, &kerb_mech);
		if (!NT_STATUS_IS_OK(status)) {
			TALLOC_FREE(session);
			return status;
		}

#ifdef HAVE_KRB5
		if (kerb_mech && ((lp_security()==SEC_ADS) ||
					USE_KERBEROS_KEYTAB) ) {
			status = smbd_smb2_session_setup_krb5(session,
					smb2req,
					in_security_mode,
					&secblob_in,
					kerb_mech,
					out_session_flags,
					out_security_buffer,
					out_session_id);

			data_blob_free(&secblob_in);
			TALLOC_FREE(kerb_mech);
			if (!NT_STATUS_IS_OK(status)) {
				TALLOC_FREE(session);
			}
			return status;
		}
#endif

		/* Can't blunder into NTLMSSP auth if we have
		 * a krb5 ticket. */

		if (kerb_mech) {
			DEBUG(3,("smb2: network "
				"misconfiguration, client sent us a "
				"krb5 ticket and kerberos security "
				"not enabled\n"));
			TALLOC_FREE(session);
			data_blob_free(&secblob_in);
			TALLOC_FREE(kerb_mech);
			return NT_STATUS_LOGON_FAILURE;
		}

		data_blob_free(&secblob_in);
	}

	if (session->auth_ntlmssp_state == NULL) {
		status = auth_ntlmssp_prepare(session->sconn->remote_address,
					    &session->auth_ntlmssp_state);
		if (!NT_STATUS_IS_OK(status)) {
			data_blob_free(&auth);
			TALLOC_FREE(session);
			return status;
		}

		auth_ntlmssp_want_feature(session->auth_ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY);

		status = auth_ntlmssp_start(session->auth_ntlmssp_state);
		if (!NT_STATUS_IS_OK(status)) {
			data_blob_free(&auth);
			TALLOC_FREE(session);
			return status;
		}
	}

	status = auth_ntlmssp_update(session->auth_ntlmssp_state,
				     talloc_tos(), auth,
				     &auth_out);
	/* If status is NT_STATUS_OK then we need to get the token.
	 * Map to guest is now internal to auth_ntlmssp */
	if (NT_STATUS_IS_OK(status)) {
		status = auth_ntlmssp_session_info(session,
						   session->auth_ntlmssp_state,
						   &session->session_info);
	}

	if (!NT_STATUS_IS_OK(status) &&
			!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
		TALLOC_FREE(session->auth_ntlmssp_state);
		data_blob_free(&auth);
		TALLOC_FREE(session);
		return status;
	}

	data_blob_free(&auth);

	*out_security_buffer = spnego_gen_auth_response(smb2req,
				&auth_out, status, NULL);

	if (out_security_buffer->data == NULL) {
		TALLOC_FREE(session->auth_ntlmssp_state);
		TALLOC_FREE(session);
		return NT_STATUS_NO_MEMORY;
	}

	*out_session_id = session->vuid;

	if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
		return NT_STATUS_MORE_PROCESSING_REQUIRED;
	}

	/* We're done - claim the session. */
	return smbd_smb2_common_ntlmssp_auth_return(session,
						smb2req,
						in_security_mode,
						in_security_buffer,
						out_session_flags,
						out_session_id);
}
示例#6
0
static NTSTATUS smbd_smb2_spnego_negotiate(struct smbd_smb2_session *session,
					struct smbd_smb2_request *smb2req,
					uint8_t in_security_mode,
					DATA_BLOB in_security_buffer,
					uint16_t *out_session_flags,
					DATA_BLOB *out_security_buffer,
					uint64_t *out_session_id)
{
	DATA_BLOB secblob_in = data_blob_null;
	DATA_BLOB chal_out = data_blob_null;
	char *kerb_mech = NULL;
	NTSTATUS status;

	/* Ensure we have no old NTLM state around. */
	TALLOC_FREE(session->auth_ntlmssp_state);

	status = parse_spnego_mechanisms(talloc_tos(), in_security_buffer,
			&secblob_in, &kerb_mech);
	if (!NT_STATUS_IS_OK(status)) {
		goto out;
	}

#ifdef HAVE_KRB5
	if (kerb_mech && ((lp_security()==SEC_ADS) ||
				USE_KERBEROS_KEYTAB) ) {
		status = smbd_smb2_session_setup_krb5(session,
				smb2req,
				in_security_mode,
				&secblob_in,
				kerb_mech,
				out_session_flags,
				out_security_buffer,
				out_session_id);

		goto out;
	}
#endif

	if (kerb_mech) {
		/* The mechtoken is a krb5 ticket, but
		 * we need to fall back to NTLM. */

		DEBUG(3,("smb2: Got krb5 ticket in SPNEGO "
			"but set to downgrade to NTLMSSP\n"));

		status = NT_STATUS_MORE_PROCESSING_REQUIRED;
	} else {
		/* Fall back to NTLMSSP. */
		status = auth_ntlmssp_prepare(session->sconn->remote_address,
					    &session->auth_ntlmssp_state);
		if (!NT_STATUS_IS_OK(status)) {
			goto out;
		}

		auth_ntlmssp_want_feature(session->auth_ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY);

		status = auth_ntlmssp_start(session->auth_ntlmssp_state);
		if (!NT_STATUS_IS_OK(status)) {
			goto out;
		}

		status = auth_ntlmssp_update(session->auth_ntlmssp_state,
					     talloc_tos(),
					     secblob_in,
					     &chal_out);
	}

	if (!NT_STATUS_IS_OK(status) &&
			!NT_STATUS_EQUAL(status,
				NT_STATUS_MORE_PROCESSING_REQUIRED)) {
		goto out;
	}

	*out_security_buffer = spnego_gen_auth_response(smb2req,
						&chal_out,
						status,
						OID_NTLMSSP);
	if (out_security_buffer->data == NULL) {
		status = NT_STATUS_NO_MEMORY;
		goto out;
	}
	*out_session_id = session->vuid;

  out:

	data_blob_free(&secblob_in);
	data_blob_free(&chal_out);
	TALLOC_FREE(kerb_mech);
	if (!NT_STATUS_IS_OK(status) &&
			!NT_STATUS_EQUAL(status,
				NT_STATUS_MORE_PROCESSING_REQUIRED)) {
		TALLOC_FREE(session->auth_ntlmssp_state);
		TALLOC_FREE(session);
	}
	return status;
}
示例#7
0
static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
					char *outbuf,
					int length,int bufsize)
{
	uint8 *p;
	DATA_BLOB blob1;
	int ret;
	size_t bufrem;
	fstring native_os, native_lanman, primary_domain;
	char *p2;
	uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
	enum remote_arch_types ra_type = get_remote_arch();
	int vuid = SVAL(inbuf,smb_uid);
	user_struct *vuser = NULL;
	NTSTATUS status = NT_STATUS_OK;
	uint16 smbpid = SVAL(inbuf,smb_pid);

	DEBUG(3,("Doing spnego session setup\n"));

	if (global_client_caps == 0) {
		global_client_caps = IVAL(inbuf,smb_vwv10);

		if (!(global_client_caps & CAP_STATUS32)) {
			remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
		}

	}
		
	p = (uint8 *)smb_buf(inbuf);

	if (data_blob_len == 0) {
		/* an invalid request */
		return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
	}

	bufrem = smb_bufrem(inbuf, p);
	/* pull the spnego blob */
	blob1 = data_blob(p, MIN(bufrem, data_blob_len));

#if 0
	file_save("negotiate.dat", blob1.data, blob1.length);
#endif

	p2 = inbuf + smb_vwv13 + data_blob_len;
	p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
	p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
	p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
	DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", 
		native_os, native_lanman, primary_domain));

	if ( ra_type == RA_WIN2K ) {
		/* Vista sets neither the OS or lanman strings */

		if ( !strlen(native_os) && !strlen(native_lanman) )
			set_remote_arch(RA_VISTA);
		
		/* Windows 2003 doesn't set the native lanman string, 
		   but does set primary domain which is a bug I think */
			   
		if ( !strlen(native_lanman) ) {
			ra_lanman_string( primary_domain );
		} else {
			ra_lanman_string( native_lanman );
		}
	}
		
	vuser = get_partial_auth_user_struct(vuid);
	if (!vuser) {
		struct pending_auth_data *pad = get_pending_auth_data(smbpid);
		if (pad) {
			DEBUG(10,("reply_sesssetup_and_X_spnego: found pending vuid %u\n",
				(unsigned int)pad->vuid ));
			vuid = pad->vuid;
			vuser = get_partial_auth_user_struct(vuid);
		}
	}

	if (!vuser) {
		vuid = register_vuid(NULL, data_blob(NULL, 0), data_blob(NULL, 0), NULL);
		if (vuid == UID_FIELD_INVALID ) {
			data_blob_free(&blob1);
			return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
		}
	
		vuser = get_partial_auth_user_struct(vuid);
	}

	if (!vuser) {
		data_blob_free(&blob1);
		return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
	}
	
	SSVAL(outbuf,smb_uid,vuid);

	/* Large (greater than 4k) SPNEGO blobs are split into multiple
	 * sessionsetup requests as the Windows limit on the security blob
	 * field is 4k. Bug #4400. JRA.
	 */

	status = check_spnego_blob_complete(smbpid, vuid, &blob1);
	if (!NT_STATUS_IS_OK(status)) {
		if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
			/* Real error - kill the intermediate vuid */
			invalidate_vuid(vuid);
		}
		data_blob_free(&blob1);
		return ERROR_NT(nt_status_squash(status));
	}

	if (blob1.data[0] == ASN1_APPLICATION(0)) {
		/* its a negTokenTarg packet */
		ret = reply_spnego_negotiate(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
					     &vuser->auth_ntlmssp_state);
		data_blob_free(&blob1);
		return ret;
	}

	if (blob1.data[0] == ASN1_CONTEXT(1)) {
		/* its a auth packet */
		ret = reply_spnego_auth(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
					&vuser->auth_ntlmssp_state);
		data_blob_free(&blob1);
		return ret;
	}

	if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
		DATA_BLOB chal;
		if (!vuser->auth_ntlmssp_state) {
			status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
			if (!NT_STATUS_IS_OK(status)) {
				/* Kill the intermediate vuid */
				invalidate_vuid(vuid);
				data_blob_free(&blob1);
				return ERROR_NT(nt_status_squash(status));
			}
		}

		status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
						blob1, &chal);
		
		data_blob_free(&blob1);
		
		reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, 
					   &vuser->auth_ntlmssp_state,
					   &chal, status, False);
		data_blob_free(&chal);
		return -1;
	}

	/* what sort of packet is this? */
	DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));

	data_blob_free(&blob1);

	return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
}
示例#8
0
static int reply_spnego_negotiate(connection_struct *conn, 
				  char *inbuf,
				  char *outbuf,
				  int length, int bufsize,
				  DATA_BLOB blob1)
{
	char *OIDs[ASN1_MAX_OIDS];
	DATA_BLOB secblob;
	int i;
	DATA_BLOB chal;
	BOOL got_kerberos = False;
	NTSTATUS nt_status;

	/* parse out the OIDs and the first sec blob */
	if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
		return ERROR_NT(NT_STATUS_LOGON_FAILURE);
	}

	/* only look at the first OID for determining the mechToken --
	   accoirding to RFC2478, we should choose the one we want 
	   and renegotiate, but i smell a client bug here..  
	   
	   Problem observed when connecting to a member (samba box) 
	   of an AD domain as a user in a Samba domain.  Samba member 
	   server sent back krb5/mskrb5/ntlmssp as mechtypes, but the 
	   client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an 
	   NTLMSSP mechtoken.                 --jerry              */
	
	if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
	    strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
		got_kerberos = True;
	}
		
	for (i=0;OIDs[i];i++) {
		DEBUG(3,("Got OID %s\n", OIDs[i]));
		free(OIDs[i]);
	}
	DEBUG(3,("Got secblob of size %lu\n", (unsigned long)secblob.length));

#ifdef HAVE_KRB5
	if (got_kerberos && (SEC_ADS == lp_security())) {
		int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
						length, bufsize, &secblob);
		data_blob_free(&secblob);
		return ret;
	}
#endif

	if (global_ntlmssp_state) {
		auth_ntlmssp_end(&global_ntlmssp_state);
	}

	nt_status = auth_ntlmssp_start(&global_ntlmssp_state);
	if (!NT_STATUS_IS_OK(nt_status)) {
		return ERROR_NT(nt_status);
	}

	nt_status = auth_ntlmssp_update(global_ntlmssp_state, 
					secblob, &chal);

	data_blob_free(&secblob);

	reply_spnego_ntlmssp(conn, inbuf, outbuf, &global_ntlmssp_state,
			     &chal, nt_status);
		
	data_blob_free(&chal);

	/* already replied */
	return -1;
}
示例#9
0
文件: sesssetup.c 项目: hajuuk/R7000
static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
					char *outbuf,
					int length,int bufsize)
{
	uint8 *p;
	DATA_BLOB blob1;
	int ret;
	size_t bufrem;
	fstring native_os, native_lanman, primary_domain;
	char *p2;
	uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
	enum remote_arch_types ra_type = get_remote_arch();

	DEBUG(3,("Doing spnego session setup\n"));

	if (global_client_caps == 0) {
		global_client_caps = IVAL(inbuf,smb_vwv10);

		if (!(global_client_caps & CAP_STATUS32)) {
			remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
		}

	}
		
	p = (uint8 *)smb_buf(inbuf);

	if (data_blob_len == 0) {
		/* an invalid request */
		return ERROR_NT(NT_STATUS_LOGON_FAILURE);
	}

	bufrem = smb_bufrem(inbuf, p);
	/* pull the spnego blob */
	blob1 = data_blob(p, MIN(bufrem, data_blob_len));

#if 0
	file_save("negotiate.dat", blob1.data, blob1.length);
#endif

	p2 = inbuf + smb_vwv13 + data_blob_len;
	p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
	p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
	p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
	DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", 
		native_os, native_lanman, primary_domain));

	if ( ra_type == RA_WIN2K ) {
		/* Windows 2003 doesn't set the native lanman string, 
		   but does set primary domain which is a bug I think */
			   
		if ( !strlen(native_lanman) )
			ra_lanman_string( primary_domain );
		else
			ra_lanman_string( native_lanman );
	}
		
	if (blob1.data[0] == ASN1_APPLICATION(0)) {
		/* its a negTokenTarg packet */
		ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1);
		data_blob_free(&blob1);
		return ret;
	}

	if (blob1.data[0] == ASN1_CONTEXT(1)) {
		/* its a auth packet */
		ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1);
		data_blob_free(&blob1);
		return ret;
	}

	/* Foxconn modified start pling 12/29/2011 */
	/* Fix Android partial auth issue.
	 * Port from Samba 3.0.24 (used by WNDR3800) */
	if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
		DATA_BLOB chal;
		NTSTATUS nt_status;
		if (!global_ntlmssp_state) {
	    	nt_status = auth_ntlmssp_start(&global_ntlmssp_state);
			if (!NT_STATUS_IS_OK(nt_status)) {
				return ERROR_NT(nt_status_squash(nt_status));
			}
		}

		nt_status = auth_ntlmssp_update(global_ntlmssp_state,
						blob1, &chal);
		
		data_blob_free(&blob1);
		
		reply_spnego_ntlmssp(conn, inbuf, outbuf, 
					   &global_ntlmssp_state,
					   &chal, nt_status, False);
		data_blob_free(&chal);
		return -1;
	}
    /* Foxconn added end pling 12/29/2011 */

	/* what sort of packet is this? */
	DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));

	data_blob_free(&blob1);

	return ERROR_NT(NT_STATUS_LOGON_FAILURE);
}