Example #1
0
 BOOL get_krb5_smb_session_key(krb5_context context, krb5_auth_context auth_context, DATA_BLOB *session_key, BOOL remote)
 {
	krb5_keyblock *skey;
	krb5_error_code err;
	BOOL ret = False;

	if (remote)
		err = krb5_auth_con_getremotesubkey(context, auth_context, &skey);
	else
		err = krb5_auth_con_getlocalsubkey(context, auth_context, &skey);
	if (err == 0 && skey != NULL) {
		DEBUG(10, ("Got KRB5 session key of length %d\n",  (int)KRB5_KEY_LENGTH(skey)));
		*session_key = data_blob(KRB5_KEY_DATA(skey), KRB5_KEY_LENGTH(skey));
		dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);

		ret = True;

		krb5_free_keyblock(context, skey);
	} else {
		DEBUG(10, ("KRB5 error getting session key %d\n", err));
	}

	return ret;
 }
Example #2
0
/*
  generate a krb5 GSS-API wrapper packet given a ticket
*/
DATA_BLOB spnego_gen_krb5_wrap(DATA_BLOB ticket, const uint8 tok_id[2])
{
	ASN1_DATA data;
	DATA_BLOB ret;

	memset(&data, 0, sizeof(data));

	asn1_push_tag(&data, ASN1_APPLICATION(0));
	asn1_write_OID(&data, OID_KERBEROS5);

	asn1_write(&data, tok_id, 2);
	asn1_write(&data, ticket.data, ticket.length);
	asn1_pop_tag(&data);

	if (data.has_error) {
		DEBUG(1,("Failed to build krb5 wrapper at offset %d\n", (int)data.ofs));
		asn1_free(&data);
	}

	ret = data_blob(data.data, data.length);
	asn1_free(&data);

	return ret;
}
Example #3
0
/*
  test pid ops with 2 tcons
*/
static BOOL test_pid_2tcon(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
	NTSTATUS status;
	BOOL ret = True;
	const char *share, *host;
	struct smbcli_tree *tree;
	union smb_tcon tcon;
	union smb_open io;
	union smb_write wr;
	union smb_close cl;
	int fnum1, fnum2;
	const char *fname1 = BASEDIR "\\test1.txt";
	const char *fname2 = BASEDIR "\\test2.txt";
	uint8_t c = 1;
	uint16_t tid1, tid2;

	printf("TESTING PID HANDLING WITH 2 TCONS\n");

	if (!torture_setup_dir(cli, BASEDIR)) {
		return False;
	}

	share = lp_parm_string(-1, "torture", "share");
	host  = lp_parm_string(-1, "torture", "host");
	
	printf("create a second tree context on the same session\n");
	tree = smbcli_tree_init(cli->session, mem_ctx, False);

	tcon.generic.level = RAW_TCON_TCONX;
	tcon.tconx.in.flags = 0;
	tcon.tconx.in.password = data_blob(NULL, 0);
	tcon.tconx.in.path = talloc_asprintf(mem_ctx, "\\\\%s\\%s", host, share);
	tcon.tconx.in.device = "A:";	
	status = smb_raw_tcon(tree, mem_ctx, &tcon);
	CHECK_STATUS(status, NT_STATUS_OK);	

	tree->tid = tcon.tconx.out.tid;

	tid1 = cli->tree->tid;
	tid2 = tree->tid;
	printf("tid1=%d tid2=%d\n", tid1, tid2);

	printf("create a file using the tid1\n");
	cli->tree->tid = tid1;
	io.generic.level = RAW_OPEN_NTCREATEX;
	io.ntcreatex.in.root_fid = 0;
	io.ntcreatex.in.flags = 0;
	io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
	io.ntcreatex.in.create_options = 0;
	io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
	io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
	io.ntcreatex.in.alloc_size = 0;
	io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
	io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
	io.ntcreatex.in.security_flags = 0;
	io.ntcreatex.in.fname = fname1;
	status = smb_raw_open(cli->tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	fnum1 = io.ntcreatex.out.file.fnum;

	printf("write using the tid1\n");
	wr.generic.level = RAW_WRITE_WRITEX;
	wr.writex.in.file.fnum = fnum1;
	wr.writex.in.offset = 0;
	wr.writex.in.wmode = 0;
	wr.writex.in.remaining = 0;
	wr.writex.in.count = 1;
	wr.writex.in.data = &c;

	status = smb_raw_write(cli->tree, &wr);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_VALUE(wr.writex.out.nwritten, 1);

	printf("create a file using the tid2\n");
	cli->tree->tid = tid2;
	io.generic.level = RAW_OPEN_NTCREATEX;
	io.ntcreatex.in.root_fid = 0;
	io.ntcreatex.in.flags = 0;
	io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
	io.ntcreatex.in.create_options = 0;
	io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
	io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
	io.ntcreatex.in.alloc_size = 0;
	io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
	io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
	io.ntcreatex.in.security_flags = 0;
	io.ntcreatex.in.fname = fname2;
	status = smb_raw_open(cli->tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	fnum2 = io.ntcreatex.out.file.fnum;

	printf("write using the tid2\n");
	wr.generic.level = RAW_WRITE_WRITEX;
	wr.writex.in.file.fnum = fnum2;
	wr.writex.in.offset = 0;
	wr.writex.in.wmode = 0;
	wr.writex.in.remaining = 0;
	wr.writex.in.count = 1;
	wr.writex.in.data = &c;

	status = smb_raw_write(cli->tree, &wr);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_VALUE(wr.writex.out.nwritten, 1);

	printf("exit the pid\n");
	status = smb_raw_exit(cli->session);
	CHECK_STATUS(status, NT_STATUS_OK);

	printf("the fnum1 on tid1 should not be accessible\n");
	cli->tree->tid = tid1;
	wr.writex.in.file.fnum = fnum1;
	status = smb_raw_write(cli->tree, &wr);
	CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);

	printf("the fnum1 on tid1 should have been auto-closed\n");
	cl.close.level = RAW_CLOSE_CLOSE;
	cl.close.in.file.fnum = fnum1;
	cl.close.in.write_time = 0;
	status = smb_raw_close(cli->tree, &cl);
	CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);

	printf("the fnum2 on tid2 should not be accessible\n");
	cli->tree->tid = tid2;
	wr.writex.in.file.fnum = fnum2;
	status = smb_raw_write(cli->tree, &wr);
	CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);

	printf("the fnum2 on tid2 should have been auto-closed\n");
	cl.close.level = RAW_CLOSE_CLOSE;
	cl.close.in.file.fnum = fnum2;
	cl.close.in.write_time = 0;
	status = smb_raw_close(cli->tree, &cl);
	CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);

done:
	return ret;
}
Example #4
0
/*
  test tree with ulogoff
  this demonstrates that a tcon isn't autoclosed by a ulogoff
  the tcon can be reused using any other valid session later
*/
static BOOL test_tree_ulogoff(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
{
	NTSTATUS status;
	BOOL ret = True;
	const char *share, *host;
	struct smbcli_session *session1;
	struct smbcli_session *session2;
	struct smb_composite_sesssetup setup;
	struct smbcli_tree *tree;
	union smb_tcon tcon;
	union smb_open io;
	union smb_write wr;
	int fnum1, fnum2;
	const char *fname1 = BASEDIR "\\test1.txt";
	const char *fname2 = BASEDIR "\\test2.txt";
	uint8_t c = 1;

	printf("TESTING TREE with ulogoff\n");

	if (!torture_setup_dir(cli, BASEDIR)) {
		return False;
	}

	share = lp_parm_string(-1, "torture", "share");
	host  = lp_parm_string(-1, "torture", "host");

	printf("create the first new sessions\n");
	session1 = smbcli_session_init(cli->transport, mem_ctx, False);
	setup.in.sesskey = cli->transport->negotiate.sesskey;
	setup.in.capabilities = cli->transport->negotiate.capabilities;
	setup.in.workgroup = lp_workgroup();
	setup.in.credentials = cmdline_credentials;
	status = smb_composite_sesssetup(session1, &setup);
	CHECK_STATUS(status, NT_STATUS_OK);
	session1->vuid = setup.out.vuid;
	printf("vuid1=%d\n", session1->vuid);

	printf("create a tree context on the with vuid1\n");
	tree = smbcli_tree_init(session1, mem_ctx, False);
	tcon.generic.level = RAW_TCON_TCONX;
	tcon.tconx.in.flags = 0;
	tcon.tconx.in.password = data_blob(NULL, 0);
	tcon.tconx.in.path = talloc_asprintf(mem_ctx, "\\\\%s\\%s", host, share);
	tcon.tconx.in.device = "A:";
	status = smb_raw_tcon(tree, mem_ctx, &tcon);
	CHECK_STATUS(status, NT_STATUS_OK);
	tree->tid = tcon.tconx.out.tid;
	printf("tid=%d\n", tree->tid);

	printf("create a file using vuid1\n");
	io.generic.level = RAW_OPEN_NTCREATEX;
	io.ntcreatex.in.root_fid = 0;
	io.ntcreatex.in.flags = 0;
	io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
	io.ntcreatex.in.create_options = 0;
	io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
	io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
	io.ntcreatex.in.alloc_size = 0;
	io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
	io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
	io.ntcreatex.in.security_flags = 0;
	io.ntcreatex.in.fname = fname1;
	status = smb_raw_open(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	fnum1 = io.ntcreatex.out.file.fnum;

	printf("write using vuid1\n");
	wr.generic.level = RAW_WRITE_WRITEX;
	wr.writex.in.file.fnum = fnum1;
	wr.writex.in.offset = 0;
	wr.writex.in.wmode = 0;
	wr.writex.in.remaining = 0;
	wr.writex.in.count = 1;
	wr.writex.in.data = &c;
	status = smb_raw_write(tree, &wr);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_VALUE(wr.writex.out.nwritten, 1);

	printf("ulogoff the vuid1\n");
	status = smb_raw_ulogoff(session1);
	CHECK_STATUS(status, NT_STATUS_OK);

	printf("create the second new sessions\n");
	session2 = smbcli_session_init(cli->transport, mem_ctx, False);
	setup.in.sesskey = cli->transport->negotiate.sesskey;
	setup.in.capabilities = cli->transport->negotiate.capabilities;
	setup.in.workgroup = lp_workgroup();
	setup.in.credentials = cmdline_credentials;
	status = smb_composite_sesssetup(session2, &setup);
	CHECK_STATUS(status, NT_STATUS_OK);
	session2->vuid = setup.out.vuid;
	printf("vuid2=%d\n", session2->vuid);

	printf("use the existing tree with vuid2\n");
	tree->session = session2;

	printf("create a file using vuid2\n");
	io.generic.level = RAW_OPEN_NTCREATEX;
	io.ntcreatex.in.root_fid = 0;
	io.ntcreatex.in.flags = 0;
	io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
	io.ntcreatex.in.create_options = 0;
	io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
	io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
	io.ntcreatex.in.alloc_size = 0;
	io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
	io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
	io.ntcreatex.in.security_flags = 0;
	io.ntcreatex.in.fname = fname2;
	status = smb_raw_open(tree, mem_ctx, &io);
	CHECK_STATUS(status, NT_STATUS_OK);
	fnum2 = io.ntcreatex.out.file.fnum;

	printf("write using vuid2\n");
	wr.generic.level = RAW_WRITE_WRITEX;
	wr.writex.in.file.fnum = fnum2;
	wr.writex.in.offset = 0;
	wr.writex.in.wmode = 0;
	wr.writex.in.remaining = 0;
	wr.writex.in.count = 1;
	wr.writex.in.data = &c;
	status = smb_raw_write(tree, &wr);
	CHECK_STATUS(status, NT_STATUS_OK);
	CHECK_VALUE(wr.writex.out.nwritten, 1);

	printf("ulogoff the vuid2\n");
	status = smb_raw_ulogoff(session2);
	CHECK_STATUS(status, NT_STATUS_OK);

	/* this also demonstrates that SMBtdis doesn't need a valid vuid */
	printf("disconnect the existing tree connection\n");
	status = smb_tree_disconnect(tree);
	CHECK_STATUS(status, NT_STATUS_OK);

	printf("disconnect the existing tree connection\n");
	status = smb_tree_disconnect(tree);
	CHECK_STATUS(status, NT_STATUS_DOS(ERRSRV,ERRinvnid));

	/* close down the new tree */
	talloc_free(tree);
	
done:
	return ret;
}
Example #5
0
static bool test_lm_ntlm_broken(enum ntlm_break break_which) 
{
	bool pass = True;
	NTSTATUS nt_status;
	uint32 flags = 0;
	DATA_BLOB lm_response = data_blob(NULL, 24);
	DATA_BLOB nt_response = data_blob(NULL, 24);
	DATA_BLOB session_key = data_blob(NULL, 16);

	uchar lm_key[8];
	uchar user_session_key[16];
	uchar lm_hash[16];
	uchar nt_hash[16];
	DATA_BLOB chall = get_challenge();
	char *error_string;
	
	ZERO_STRUCT(lm_key);
	ZERO_STRUCT(user_session_key);

	flags |= WBFLAG_PAM_LMKEY;
	flags |= WBFLAG_PAM_USER_SESSION_KEY;

	SMBencrypt(opt_password,chall.data,lm_response.data);
	E_deshash(opt_password, lm_hash); 

	SMBNTencrypt(opt_password,chall.data,nt_response.data);

	E_md4hash(opt_password, nt_hash);
	SMBsesskeygen_ntv1(nt_hash, session_key.data);

	switch (break_which) {
	case BREAK_NONE:
		break;
	case BREAK_LM:
		lm_response.data[0]++;
		break;
	case BREAK_NT:
		nt_response.data[0]++;
		break;
	case NO_LM:
		data_blob_free(&lm_response);
		break;
	case NO_NT:
		data_blob_free(&nt_response);
		break;
	}

	nt_status = contact_winbind_auth_crap(opt_username, opt_domain, 
					      opt_workstation,
					      &chall,
					      &lm_response,
					      &nt_response,
					      flags,
					      lm_key, 
					      user_session_key,
					      &error_string, NULL);
	
	data_blob_free(&lm_response);

	if (!NT_STATUS_IS_OK(nt_status)) {
		d_printf("%s (0x%x)\n", 
			 error_string,
			 NT_STATUS_V(nt_status));
		SAFE_FREE(error_string);
		return break_which == BREAK_NT;
	}

	if (memcmp(lm_hash, lm_key, 
		   sizeof(lm_key)) != 0) {
		DEBUG(1, ("LM Key does not match expectations!\n"));
 		DEBUG(1, ("lm_key:\n"));
		dump_data(1, lm_key, 8);
		DEBUG(1, ("expected:\n"));
		dump_data(1, lm_hash, 8);
		pass = False;
	}

	if (break_which == NO_NT) {
		if (memcmp(lm_hash, user_session_key, 
			   8) != 0) {
			DEBUG(1, ("NT Session Key does not match expectations (should be LM hash)!\n"));
			DEBUG(1, ("user_session_key:\n"));
			dump_data(1, user_session_key, sizeof(user_session_key));
			DEBUG(1, ("expected:\n"));
			dump_data(1, lm_hash, sizeof(lm_hash));
			pass = False;
		}
	} else {		
		if (memcmp(session_key.data, user_session_key, 
			   sizeof(user_session_key)) != 0) {
			DEBUG(1, ("NT Session Key does not match expectations!\n"));
			DEBUG(1, ("user_session_key:\n"));
			dump_data(1, user_session_key, 16);
			DEBUG(1, ("expected:\n"));
			dump_data(1, session_key.data, session_key.length);
			pass = False;
		}
	}
        return pass;
}
Example #6
0
/*
  handler for old style session setup
*/
static void sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess)
{
	struct auth_usersupplied_info *user_info = NULL;
	struct tsocket_address *remote_address;
	const char *remote_machine = NULL;
	struct tevent_req *subreq;
	struct sesssetup_context *state;

	sess->old.out.vuid = 0;
	sess->old.out.action = 0;

	sesssetup_common_strings(req, 
				 &sess->old.out.os,
				 &sess->old.out.lanman,
				 &sess->old.out.domain);

	if (!req->smb_conn->negotiate.done_sesssetup) {
		req->smb_conn->negotiate.max_send = sess->old.in.bufsize;
	}

	if (req->smb_conn->negotiate.calling_name) {
		remote_machine = req->smb_conn->negotiate.calling_name->name;
	}
	
	remote_address = socket_get_remote_addr(req->smb_conn->connection->socket, req);
	if (!remote_address) goto nomem;

	if (!remote_machine) {
		remote_machine = tsocket_address_inet_addr_string(remote_address, req);
		if (!remote_machine) goto nomem;
	}

	user_info = talloc_zero(req, struct auth_usersupplied_info);
	if (!user_info) goto nomem;
	
	user_info->mapped_state = false;
	user_info->logon_parameters = 0;
	user_info->flags = 0;
	user_info->client.account_name = sess->old.in.user;
	user_info->client.domain_name = sess->old.in.domain;
	user_info->workstation_name = remote_machine;
	user_info->remote_host = talloc_steal(user_info, remote_address);
	
	user_info->password_state = AUTH_PASSWORD_RESPONSE;
	user_info->password.response.lanman = sess->old.in.password;
	user_info->password.response.lanman.data = talloc_steal(user_info, sess->old.in.password.data);
	user_info->password.response.nt = data_blob(NULL, 0);

	state = talloc(req, struct sesssetup_context);
	if (!state) goto nomem;

	if (req->smb_conn->negotiate.auth_context) {
		state->auth_context = req->smb_conn->negotiate.auth_context;
	} else {
		/* TODO: should we use just "anonymous" here? */
		NTSTATUS status = auth_context_create(state,
						      req->smb_conn->connection->event.ctx,
						      req->smb_conn->connection->msg_ctx,
						      req->smb_conn->lp_ctx,
						      &state->auth_context);
		if (!NT_STATUS_IS_OK(status)) {
			smbsrv_sesssetup_backend_send(req, sess, status);
			return;
		}
	}

	state->req = req;

	subreq = auth_check_password_send(state,
					  req->smb_conn->connection->event.ctx,
					  req->smb_conn->negotiate.auth_context,
					  user_info);
	if (!subreq) goto nomem;
	tevent_req_set_callback(subreq, sesssetup_old_send, state);
	return;

nomem:
	smbsrv_sesssetup_backend_send(req, sess, NT_STATUS_NO_MEMORY);
}
Example #7
0
static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, 
					 const DATA_BLOB reply, DATA_BLOB *next_request) 
{
	uint32 chal_flags, ntlmssp_command, unkn1, unkn2;
	DATA_BLOB server_domain_blob;
	DATA_BLOB challenge_blob;
	DATA_BLOB struct_blob = data_blob_null;
	char *server_domain;
	const char *chal_parse_string;
	const char *auth_gen_string;
	DATA_BLOB lm_response = data_blob_null;
	DATA_BLOB nt_response = data_blob_null;
	DATA_BLOB session_key = data_blob_null;
	DATA_BLOB encrypted_session_key = data_blob_null;
	NTSTATUS nt_status = NT_STATUS_OK;

	if (!msrpc_parse(&reply, "CdBd",
			 "NTLMSSP",
			 &ntlmssp_command, 
			 &server_domain_blob,
			 &chal_flags)) {
		DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n"));
		dump_data(2, reply.data, reply.length);

		return NT_STATUS_INVALID_PARAMETER;
	}
	
	data_blob_free(&server_domain_blob);

	DEBUG(3, ("Got challenge flags:\n"));
	debug_ntlmssp_flags(chal_flags);

	ntlmssp_handle_neg_flags(ntlmssp_state, chal_flags, lp_client_lanman_auth());

	if (ntlmssp_state->unicode) {
		if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
			chal_parse_string = "CdUdbddB";
		} else {
			chal_parse_string = "CdUdbdd";
		}
		auth_gen_string = "CdBBUUUBd";
	} else {
		if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
			chal_parse_string = "CdAdbddB";
		} else {
			chal_parse_string = "CdAdbdd";
		}

		auth_gen_string = "CdBBAAABd";
	}

	DEBUG(3, ("NTLMSSP: Set final flags:\n"));
	debug_ntlmssp_flags(ntlmssp_state->neg_flags);

	if (!msrpc_parse(&reply, chal_parse_string,
			 "NTLMSSP",
			 &ntlmssp_command, 
			 &server_domain,
			 &chal_flags,
			 &challenge_blob, 8,
			 &unkn1, &unkn2,
			 &struct_blob)) {
		DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#2)\n"));
		dump_data(2, reply.data, reply.length);
		return NT_STATUS_INVALID_PARAMETER;
	}

	ntlmssp_state->server_domain = talloc_strdup(ntlmssp_state->mem_ctx,
						     server_domain);

	SAFE_FREE(server_domain);
	if (challenge_blob.length != 8) {
		data_blob_free(&struct_blob);
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (!ntlmssp_state->nt_hash || !ntlmssp_state->lm_hash) {
		uchar zeros[16];
		/* do nothing - blobs are zero length */

		ZERO_STRUCT(zeros);

		/* session key is all zeros */
		session_key = data_blob_talloc(ntlmssp_state->mem_ctx, zeros, 16);
		
		/* not doing NLTM2 without a password */
		ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
	} else if (ntlmssp_state->use_ntlmv2) {

		if (!struct_blob.length) {
			/* be lazy, match win2k - we can't do NTLMv2 without it */
			DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
			return NT_STATUS_INVALID_PARAMETER;
		}

		/* TODO: if the remote server is standalone, then we should replace 'domain'
		   with the server name as supplied above */
		
		if (!SMBNTLMv2encrypt_hash(ntlmssp_state->user, 
				      ntlmssp_state->domain, 
				      ntlmssp_state->nt_hash, &challenge_blob, 
				      &struct_blob, 
				      &lm_response, &nt_response, &session_key)) {
			data_blob_free(&challenge_blob);
			data_blob_free(&struct_blob);
			return NT_STATUS_NO_MEMORY;
		}
	} else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
		struct MD5Context md5_session_nonce_ctx;
		uchar session_nonce[16];
		uchar session_nonce_hash[16];
		uchar user_session_key[16];
		
		lm_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
		generate_random_buffer(lm_response.data, 8);
		memset(lm_response.data+8, 0, 16);

		memcpy(session_nonce, challenge_blob.data, 8);
		memcpy(&session_nonce[8], lm_response.data, 8);
	
		MD5Init(&md5_session_nonce_ctx);
		MD5Update(&md5_session_nonce_ctx, challenge_blob.data, 8);
		MD5Update(&md5_session_nonce_ctx, lm_response.data, 8);
		MD5Final(session_nonce_hash, &md5_session_nonce_ctx);

		DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
		DEBUG(5, ("challenge is: \n"));
		dump_data(5, session_nonce_hash, 8);
		
		nt_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
		SMBNTencrypt_hash(ntlmssp_state->nt_hash,
			     session_nonce_hash,
			     nt_response.data);

		session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);

		SMBsesskeygen_ntv1(ntlmssp_state->nt_hash, NULL, user_session_key);
		hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data);
		dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
	} else {
		/* lanman auth is insecure, it may be disabled */
		if (lp_client_lanman_auth()) {
			lm_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
			SMBencrypt_hash(ntlmssp_state->lm_hash,challenge_blob.data,
				   lm_response.data);
		}
		
		nt_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
		SMBNTencrypt_hash(ntlmssp_state->nt_hash,challenge_blob.data,
			     nt_response.data);
		
		session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);
		if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) 
		    && lp_client_lanman_auth()) {
			SMBsesskeygen_lm_sess_key(ntlmssp_state->lm_hash, lm_response.data,
					session_key.data);
			dump_data_pw("LM session key\n", session_key.data, session_key.length);
		} else {
			SMBsesskeygen_ntv1(ntlmssp_state->nt_hash, NULL, session_key.data);
			dump_data_pw("NT session key:\n", session_key.data, session_key.length);
		}
	}
	data_blob_free(&struct_blob);

	/* Key exchange encryptes a new client-generated session key with
	   the password-derived key */
	if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
		/* Make up a new session key */
		uint8 client_session_key[16];
		generate_random_buffer(client_session_key, sizeof(client_session_key));

		/* Encrypt the new session key with the old one */
		encrypted_session_key = data_blob(client_session_key, sizeof(client_session_key));
		dump_data_pw("KEY_EXCH session key:\n", encrypted_session_key.data, encrypted_session_key.length);
		SamOEMhash(encrypted_session_key.data, session_key.data, encrypted_session_key.length);
		dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length);

		/* Mark the new session key as the 'real' session key */
		data_blob_free(&session_key);
		session_key = data_blob_talloc(ntlmssp_state->mem_ctx, client_session_key, sizeof(client_session_key));
	}

	/* this generates the actual auth packet */
	if (!msrpc_gen(next_request, auth_gen_string, 
		       "NTLMSSP", 
		       NTLMSSP_AUTH, 
		       lm_response.data, lm_response.length,
		       nt_response.data, nt_response.length,
		       ntlmssp_state->domain, 
		       ntlmssp_state->user, 
		       ntlmssp_state->get_global_myname(), 
		       encrypted_session_key.data, encrypted_session_key.length,
		       ntlmssp_state->neg_flags)) {
		
		return NT_STATUS_NO_MEMORY;
	}

	data_blob_free(&encrypted_session_key);

	data_blob_free(&ntlmssp_state->chal);

	ntlmssp_state->session_key = session_key;

	ntlmssp_state->chal = challenge_blob;
	ntlmssp_state->lm_resp = lm_response;
	ntlmssp_state->nt_resp = nt_response;

	ntlmssp_state->expected_state = NTLMSSP_DONE;

	if (!NT_STATUS_IS_OK(nt_status = ntlmssp_sign_init(ntlmssp_state))) {
		DEBUG(1, ("Could not setup NTLMSSP signing/sealing system (error was: %s)\n", nt_errstr(nt_status)));
	}

	return nt_status;
}
Example #8
0
/* 
   this performs a SASL/SPNEGO bind
*/
static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
{
	TALLOC_CTX *frame = talloc_stackframe();
	struct ads_service_principal p = {0};
	struct berval *scred=NULL;
	int rc, i;
	ADS_STATUS status;
	DATA_BLOB blob = data_blob_null;
	char *given_principal = NULL;
	char *OIDs[ASN1_MAX_OIDS];
#ifdef HAVE_KRB5
	bool got_kerberos_mechanism = False;
#endif
	const char *mech = NULL;

	rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);

	if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
		status = ADS_ERROR(rc);
		goto done;
	}

	blob = data_blob(scred->bv_val, scred->bv_len);

	ber_bvfree(scred);

#if 0
	file_save("sasl_spnego.dat", blob.data, blob.length);
#endif

	/* the server sent us the first part of the SPNEGO exchange in the negprot 
	   reply */
	if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) ||
			OIDs[0] == NULL) {
		status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
		goto done;
	}
	TALLOC_FREE(given_principal);

	/* make sure the server understands kerberos */
	for (i=0;OIDs[i];i++) {
		DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
#ifdef HAVE_KRB5
		if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
		    strcmp(OIDs[i], OID_KERBEROS5) == 0) {
			got_kerberos_mechanism = True;
		}
#endif
		talloc_free(OIDs[i]);
	}

	status = ads_generate_service_principal(ads, &p);
	if (!ADS_ERR_OK(status)) {
		goto done;
	}

#ifdef HAVE_KRB5
	if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
	    got_kerberos_mechanism) 
	{
		mech = "KRB5";

		if (ads->auth.password == NULL ||
		    ads->auth.password[0] == '\0')
		{

			status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
							     CRED_MUST_USE_KERBEROS,
							     p.service, p.hostname,
							     blob);
			if (ADS_ERR_OK(status)) {
				ads_free_service_principal(&p);
				goto done;
			}

			DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, "
				  "calling kinit\n", ads_errstr(status)));
		}

		status = ADS_ERROR_KRB5(ads_kinit_password(ads)); 

		if (ADS_ERR_OK(status)) {
			status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
							CRED_MUST_USE_KERBEROS,
							p.service, p.hostname,
							blob);
			if (!ADS_ERR_OK(status)) {
				DEBUG(0,("kinit succeeded but "
					"ads_sasl_spnego_gensec_bind(KRB5) failed "
					"for %s/%s with user[%s] realm[%s]: %s\n",
					p.service, p.hostname,
					ads->auth.user_name,
					ads->auth.realm,
					ads_errstr(status)));
			}
		}

		/* only fallback to NTLMSSP if allowed */
		if (ADS_ERR_OK(status) || 
		    !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
			goto done;
		}

		DEBUG(1,("ads_sasl_spnego_gensec_bind(KRB5) failed "
			 "for %s/%s with user[%s] realm[%s]: %s, "
			 "fallback to NTLMSSP\n",
			 p.service, p.hostname,
			 ads->auth.user_name,
			 ads->auth.realm,
			 ads_errstr(status)));
	}
#endif

	/* lets do NTLMSSP ... this has the big advantage that we don't need
	   to sync clocks, and we don't rely on special versions of the krb5 
	   library for HMAC_MD4 encryption */
	mech = "NTLMSSP";
	status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO",
					     CRED_DONT_USE_KERBEROS,
					     p.service, p.hostname,
					     data_blob_null);
done:
	if (!ADS_ERR_OK(status)) {
		DEBUG(1,("ads_sasl_spnego_gensec_bind(%s) failed "
			 "for %s/%s with user[%s] realm=[%s]: %s\n", mech,
			  p.service, p.hostname,
			  ads->auth.user_name,
			  ads->auth.realm,
			  ads_errstr(status)));
	}
	ads_free_service_principal(&p);
	TALLOC_FREE(frame);
	if (blob.data != NULL) {
		data_blob_free(&blob);
	}
	return status;
}
Example #9
0
NTSTATUS gensec_socket_init(struct gensec_security *gensec_security,
			    TALLOC_CTX *mem_ctx,
			    struct socket_context *current_socket,
			    struct tevent_context *ev,
			    void (*recv_handler)(void *, uint16_t),
			    void *recv_private,
			    struct socket_context **new_socket)
{
	struct gensec_socket *gensec_socket;
	struct socket_context *new_sock;
	NTSTATUS nt_status;

	nt_status = socket_create_with_ops(mem_ctx, &gensec_socket_ops, &new_sock, 
					   SOCKET_TYPE_STREAM, current_socket->flags | SOCKET_FLAG_ENCRYPT);
	if (!NT_STATUS_IS_OK(nt_status)) {
		*new_socket = NULL;
		return nt_status;
	}

	new_sock->state = current_socket->state;

	gensec_socket = talloc(new_sock, struct gensec_socket);
	if (gensec_socket == NULL) {
		*new_socket = NULL;
		talloc_free(new_sock);
		return NT_STATUS_NO_MEMORY;
	}

	new_sock->private_data       = gensec_socket;
	gensec_socket->socket        = current_socket;

	/* Nothing to do here, if we are not actually wrapping on this socket */
	if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL) &&
	    !gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
		
		gensec_socket->wrap = false;
		talloc_steal(gensec_socket, current_socket);
		*new_socket = new_sock;
		return NT_STATUS_OK;
	}

	gensec_socket->gensec_security = gensec_security;

	gensec_socket->wrap          = true;
	gensec_socket->eof           = false;
	gensec_socket->error         = NT_STATUS_OK;
	gensec_socket->interrupted   = false;
	gensec_socket->in_extra_read = 0;

	gensec_socket->read_buffer   = data_blob(NULL, 0);

	gensec_socket->recv_handler  = recv_handler;
	gensec_socket->recv_private  = recv_private;
	gensec_socket->ev            = ev;

	gensec_socket->packet = packet_init(gensec_socket);
	if (gensec_socket->packet == NULL) {
		*new_socket = NULL;
		talloc_free(new_sock);
		return NT_STATUS_NO_MEMORY;
	}

	packet_set_private(gensec_socket->packet, gensec_socket);
	packet_set_socket(gensec_socket->packet, gensec_socket->socket);
	packet_set_callback(gensec_socket->packet, gensec_socket_unwrap);
	packet_set_full_request(gensec_socket->packet, gensec_socket_full_request);
	packet_set_error_handler(gensec_socket->packet, gensec_socket_error_handler);
	packet_set_serialise(gensec_socket->packet);

	/* TODO: full-request that knows about maximum packet size */

	talloc_steal(gensec_socket, current_socket);
	*new_socket = new_sock;
	return NT_STATUS_OK;
}
Example #10
0
/* 
   perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can
   we fit on one socket??)
*/
static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
{
	DATA_BLOB msg1 = data_blob_null;
	DATA_BLOB blob = data_blob_null;
	DATA_BLOB blob_in = data_blob_null;
	DATA_BLOB blob_out = data_blob_null;
	struct berval cred, *scred = NULL;
	int rc;
	NTSTATUS nt_status;
	ADS_STATUS status;
	int turn = 1;
	uint32 features = 0;

	struct ntlmssp_state *ntlmssp_state;

	if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
		return ADS_ERROR_NT(nt_status);
	}
	ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN;

	if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, ads->auth.user_name))) {
		return ADS_ERROR_NT(nt_status);
	}
	if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, ads->auth.realm))) {
		return ADS_ERROR_NT(nt_status);
	}
	if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, ads->auth.password))) {
		return ADS_ERROR_NT(nt_status);
	}

	switch (ads->ldap.wrap_type) {
	case ADS_SASLWRAP_TYPE_SEAL:
		features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
		break;
	case ADS_SASLWRAP_TYPE_SIGN:
		if (ads->auth.flags & ADS_AUTH_SASL_FORCE) {
			features = NTLMSSP_FEATURE_SIGN;
		} else {
			/*
			 * windows servers are broken with sign only,
			 * so we need to use seal here too
			 */
			features = NTLMSSP_FEATURE_SIGN | NTLMSSP_FEATURE_SEAL;
			ads->ldap.wrap_type = ADS_SASLWRAP_TYPE_SEAL;
		}
		break;
	case ADS_SASLWRAP_TYPE_PLAIN:
		break;
	}

	ntlmssp_want_feature(ntlmssp_state, features);

	blob_in = data_blob_null;

	do {
		nt_status = ntlmssp_update(ntlmssp_state, 
					   blob_in, &blob_out);
		data_blob_free(&blob_in);
		if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) 
		     || NT_STATUS_IS_OK(nt_status))
		    && blob_out.length) {
			if (turn == 1) {
				/* and wrap it in a SPNEGO wrapper */
				msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
			} else {
				/* wrap it in SPNEGO */
				msg1 = spnego_gen_auth(blob_out);
			}

			data_blob_free(&blob_out);

			cred.bv_val = (char *)msg1.data;
			cred.bv_len = msg1.length;
			scred = NULL;
			rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
			data_blob_free(&msg1);
			if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
				if (scred) {
					ber_bvfree(scred);
				}

				ntlmssp_end(&ntlmssp_state);
				return ADS_ERROR(rc);
			}
			if (scred) {
				blob = data_blob(scred->bv_val, scred->bv_len);
				ber_bvfree(scred);
			} else {
				blob = data_blob_null;
			}

		} else {

			ntlmssp_end(&ntlmssp_state);
			data_blob_free(&blob_out);
			return ADS_ERROR_NT(nt_status);
		}
		
		if ((turn == 1) && 
		    (rc == LDAP_SASL_BIND_IN_PROGRESS)) {
			DATA_BLOB tmp_blob = data_blob_null;
			/* the server might give us back two challenges */
			if (!spnego_parse_challenge(blob, &blob_in, 
						    &tmp_blob)) {

				ntlmssp_end(&ntlmssp_state);
				data_blob_free(&blob);
				DEBUG(3,("Failed to parse challenges\n"));
				return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
			}
			data_blob_free(&tmp_blob);
		} else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
			if (!spnego_parse_auth_response(blob, nt_status, OID_NTLMSSP, 
							&blob_in)) {

				ntlmssp_end(&ntlmssp_state);
				data_blob_free(&blob);
				DEBUG(3,("Failed to parse auth response\n"));
				return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
			}
		}
		data_blob_free(&blob);
		data_blob_free(&blob_out);
		turn++;
	} while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status));
	
	/* we have a reference conter on ntlmssp_state, if we are signing
	   then the state will be kept by the signing engine */

	if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
		ads->ldap.out.max_unwrapped = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED - NTLMSSP_SIG_SIZE;
		ads->ldap.out.sig_size = NTLMSSP_SIG_SIZE;
		ads->ldap.in.min_wrapped = ads->ldap.out.sig_size;
		ads->ldap.in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED;
		status = ads_setup_sasl_wrapping(ads, &ads_sasl_ntlmssp_ops, ntlmssp_state);
		if (!ADS_ERR_OK(status)) {
			DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n",
				ads_errstr(status)));
			ntlmssp_end(&ntlmssp_state);
			return status;
		}
	} else {
		ntlmssp_end(&ntlmssp_state);
	}

	return ADS_ERROR(rc);
}
Example #11
0
/* TODO: look at how to best fill in parms retrieveing a struct passwd info
 * except in case USER_INFO_DONT_CHECK_UNIX_ACCOUNT is set
 */
static NTSTATUS authunix_make_server_info(TALLOC_CTX *mem_ctx,
					  const char *netbios_name,
					  const struct auth_usersupplied_info *user_info,
					  struct passwd *pwd,
					  struct auth_serversupplied_info **_server_info)
{
	struct auth_serversupplied_info *server_info;
	NTSTATUS status;

	/* This is a real, real hack */
	if (pwd->pw_uid == 0) {
		status = auth_system_server_info(mem_ctx, netbios_name, &server_info);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}

		server_info->account_name = talloc_steal(server_info, pwd->pw_name);
		NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
		
		server_info->domain_name = talloc_strdup(server_info, "unix");
		NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);
	} else {
		server_info = talloc(mem_ctx, struct auth_serversupplied_info);
		NT_STATUS_HAVE_NO_MEMORY(server_info);
		
		server_info->authenticated = true;
		
		server_info->account_name = talloc_steal(server_info, pwd->pw_name);
		NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
		
		server_info->domain_name = talloc_strdup(server_info, "unix");
		NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);

		/* This isn't in any way correct.. */
		server_info->account_sid = NULL;
		server_info->primary_group_sid = NULL;
		server_info->n_domain_groups = 0;
		server_info->domain_groups = NULL;
	}
	server_info->user_session_key = data_blob(NULL,0);
	server_info->lm_session_key = data_blob(NULL,0);

	server_info->full_name = talloc_steal(server_info, pwd->pw_gecos);
	NT_STATUS_HAVE_NO_MEMORY(server_info->full_name);
	server_info->logon_script = talloc_strdup(server_info, "");
	NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script);
	server_info->profile_path = talloc_strdup(server_info, "");
	NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path);
	server_info->home_directory = talloc_strdup(server_info, "");
	NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory);
	server_info->home_drive = talloc_strdup(server_info, "");
	NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive);

	server_info->last_logon = 0;
	server_info->last_logoff = 0;
	server_info->acct_expiry = 0;
	server_info->last_password_change = 0;
	server_info->allow_password_change = 0;
	server_info->force_password_change = 0;
	server_info->logon_count = 0;
	server_info->bad_password_count = 0;
	server_info->acct_flags = 0;

	*_server_info = server_info;

	return NT_STATUS_OK;
}
Example #12
0
/*
  try the various request blobs
 */
static bool test_create_blob(struct torture_context *tctx, struct smb2_tree *tree)
{
    struct smb2_create io;
    NTSTATUS status;

    smb2_deltree(tree, FNAME);

    ZERO_STRUCT(io);
    io.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
    io.in.file_attributes    = FILE_ATTRIBUTE_NORMAL;
    io.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
    io.in.share_access =
        NTCREATEX_SHARE_ACCESS_DELETE|
        NTCREATEX_SHARE_ACCESS_READ|
        NTCREATEX_SHARE_ACCESS_WRITE;
    io.in.create_options		= NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
                                  NTCREATEX_OPTIONS_ASYNC_ALERT	|
                                  NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
                                  0x00200000;
    io.in.fname = FNAME;

    status = smb2_create(tree, tctx, &io);
    CHECK_STATUS(status, NT_STATUS_OK);

    status = smb2_util_close(tree, io.out.file.handle);
    CHECK_STATUS(status, NT_STATUS_OK);

    torture_comment(tctx, "Testing alloc size\n");
    io.in.alloc_size = 4096;
    status = smb2_create(tree, tctx, &io);
    CHECK_STATUS(status, NT_STATUS_OK);
    CHECK_EQUAL(io.out.alloc_size, io.in.alloc_size);

    status = smb2_util_close(tree, io.out.file.handle);
    CHECK_STATUS(status, NT_STATUS_OK);

    torture_comment(tctx, "Testing durable open\n");
    io.in.durable_open = true;
    status = smb2_create(tree, tctx, &io);
    CHECK_STATUS(status, NT_STATUS_OK);

    status = smb2_util_close(tree, io.out.file.handle);
    CHECK_STATUS(status, NT_STATUS_OK);

    torture_comment(tctx, "Testing query maximal access\n");
    io.in.query_maximal_access = true;
    status = smb2_create(tree, tctx, &io);
    CHECK_STATUS(status, NT_STATUS_OK);
    CHECK_EQUAL(io.out.maximal_access, 0x001f01ff);

    status = smb2_util_close(tree, io.out.file.handle);
    CHECK_STATUS(status, NT_STATUS_OK);

    torture_comment(tctx, "Testing timewarp\n");
    io.in.timewarp = 10000;
    status = smb2_create(tree, tctx, &io);
    CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
    io.in.timewarp = 0;

    torture_comment(tctx, "Testing query_on_disk\n");
    io.in.query_on_disk_id = true;
    status = smb2_create(tree, tctx, &io);
    CHECK_STATUS(status, NT_STATUS_OK);

    status = smb2_util_close(tree, io.out.file.handle);
    CHECK_STATUS(status, NT_STATUS_OK);

    torture_comment(tctx, "Testing unknown tag\n");
    status = smb2_create_blob_add(tctx, &io.in.blobs,
                                  "FooO", data_blob(NULL, 0));
    CHECK_STATUS(status, NT_STATUS_OK);

    status = smb2_create(tree, tctx, &io);
    CHECK_STATUS(status, NT_STATUS_OK);

    status = smb2_util_close(tree, io.out.file.handle);
    CHECK_STATUS(status, NT_STATUS_OK);

    torture_comment(tctx, "Testing bad tag length\n");
    status = smb2_create_blob_add(tctx, &io.in.blobs,
                                  "xxx", data_blob(NULL, 0));
    CHECK_STATUS(status, NT_STATUS_OK);

    status = smb2_create(tree, tctx, &io);
    CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);

    smb2_deltree(tree, FNAME);

    return true;
}
Example #13
0
bool make_user_info_for_reply(struct auth_usersupplied_info **user_info,
			      const char *smb_name, 
			      const char *client_domain,
			      const uint8 chal[8],
			      DATA_BLOB plaintext_password)
{

	DATA_BLOB local_lm_blob;
	DATA_BLOB local_nt_blob;
	NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
	char *plaintext_password_string;
	/*
	 * Not encrypted - do so.
	 */

	DEBUG(5,("make_user_info_for_reply: User passwords not in encrypted "
		 "format.\n"));
	if (plaintext_password.data && plaintext_password.length) {
		unsigned char local_lm_response[24];

#ifdef DEBUG_PASSWORD
		DEBUG(10,("Unencrypted password (len %d):\n",
			  (int)plaintext_password.length));
		dump_data(100, plaintext_password.data,
			  plaintext_password.length);
#endif

		SMBencrypt( (const char *)plaintext_password.data,
			    (const uchar*)chal, local_lm_response);
		local_lm_blob = data_blob(local_lm_response, 24);

		/* We can't do an NT hash here, as the password needs to be
		   case insensitive */
		local_nt_blob = data_blob_null; 
	} else {
		local_lm_blob = data_blob_null; 
		local_nt_blob = data_blob_null; 
	}

	plaintext_password_string = talloc_strndup(talloc_tos(),
						   (const char *)plaintext_password.data,
						   plaintext_password.length);
	if (!plaintext_password_string) {
		return False;
	}

	ret = make_user_info_map(
		user_info, smb_name, client_domain, 
		get_remote_machine_name(),
		local_lm_blob.data ? &local_lm_blob : NULL,
		local_nt_blob.data ? &local_nt_blob : NULL,
		NULL, NULL,
		plaintext_password_string,
		AUTH_PASSWORD_PLAIN);

	if (plaintext_password_string) {
		memset(plaintext_password_string, '\0', strlen(plaintext_password_string));
		talloc_free(plaintext_password_string);
	}

	data_blob_free(&local_lm_blob);
	return NT_STATUS_IS_OK(ret) ? True : False;
}
Example #14
0
bool make_user_info_netlogon_interactive(struct auth_usersupplied_info **user_info,
					 const char *smb_name, 
					 const char *client_domain, 
					 const char *workstation_name,
					 uint32 logon_parameters,
					 const uchar chal[8], 
					 const uchar lm_interactive_pwd[16], 
					 const uchar nt_interactive_pwd[16], 
					 const uchar *dc_sess_key)
{
	struct samr_Password lm_pwd;
	struct samr_Password nt_pwd;
	unsigned char local_lm_response[24];
	unsigned char local_nt_response[24];
	unsigned char key[16];

	memcpy(key, dc_sess_key, 16);

	if (lm_interactive_pwd)
		memcpy(lm_pwd.hash, lm_interactive_pwd, sizeof(lm_pwd.hash));

	if (nt_interactive_pwd)
		memcpy(nt_pwd.hash, nt_interactive_pwd, sizeof(nt_pwd.hash));

#ifdef DEBUG_PASSWORD
	DEBUG(100,("key:"));
	dump_data(100, key, sizeof(key));

	DEBUG(100,("lm owf password:"));
	dump_data(100, lm_pwd.hash, sizeof(lm_pwd.hash));

	DEBUG(100,("nt owf password:"));
	dump_data(100, nt_pwd.hash, sizeof(nt_pwd.hash));
#endif

	if (lm_interactive_pwd)
		arcfour_crypt(lm_pwd.hash, key, sizeof(lm_pwd.hash));

	if (nt_interactive_pwd)
		arcfour_crypt(nt_pwd.hash, key, sizeof(nt_pwd.hash));

#ifdef DEBUG_PASSWORD
	DEBUG(100,("decrypt of lm owf password:"));
	dump_data(100, lm_pwd.hash, sizeof(lm_pwd));

	DEBUG(100,("decrypt of nt owf password:"));
	dump_data(100, nt_pwd.hash, sizeof(nt_pwd));
#endif

	if (lm_interactive_pwd)
		SMBOWFencrypt(lm_pwd.hash, chal,
			      local_lm_response);

	if (nt_interactive_pwd)
		SMBOWFencrypt(nt_pwd.hash, chal,
			      local_nt_response);

	/* Password info paranoia */
	ZERO_STRUCT(key);

	{
		bool ret;
		NTSTATUS nt_status;
		DATA_BLOB local_lm_blob;
		DATA_BLOB local_nt_blob;

		if (lm_interactive_pwd) {
			local_lm_blob = data_blob(local_lm_response,
						  sizeof(local_lm_response));
		}

		if (nt_interactive_pwd) {
			local_nt_blob = data_blob(local_nt_response,
						  sizeof(local_nt_response));
		}

		nt_status = make_user_info_map(
			user_info, 
			smb_name, client_domain, workstation_name,
			lm_interactive_pwd ? &local_lm_blob : NULL,
			nt_interactive_pwd ? &local_nt_blob : NULL,
			lm_interactive_pwd ? &lm_pwd : NULL,
			nt_interactive_pwd ? &nt_pwd : NULL,
			NULL, AUTH_PASSWORD_HASH);

		if (NT_STATUS_IS_OK(nt_status)) {
			(*user_info)->logon_parameters = logon_parameters;
		}

		ret = NT_STATUS_IS_OK(nt_status) ? True : False;
		data_blob_free(&local_lm_blob);
		data_blob_free(&local_nt_blob);
		return ret;
	}
}
Example #15
0
/*
  receive a cldap netlogon reply
*/
static int recv_cldap_netlogon(TALLOC_CTX *mem_ctx,
			       int sock,
			       uint32_t *nt_version,
			       union nbt_cldap_netlogon **reply)
{
	int ret;
	ASN1_DATA data;
	DATA_BLOB blob = data_blob_null;
	DATA_BLOB os1 = data_blob_null;
	DATA_BLOB os2 = data_blob_null;
	DATA_BLOB os3 = data_blob_null;
	int i1;
	/* half the time of a regular ldap timeout, not less than 3 seconds. */
	unsigned int al_secs = MAX(3,lp_ldap_timeout()/2);
	union nbt_cldap_netlogon *r = NULL;

	blob = data_blob(NULL, 8192);
	if (blob.data == NULL) {
		DEBUG(1, ("data_blob failed\n"));
		errno = ENOMEM;
		return -1;
	}

	/* Setup timeout */
	gotalarm = 0;
	CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
	alarm(al_secs);
	/* End setup timeout. */
 
	ret = read(sock, blob.data, blob.length);

	/* Teardown timeout. */
	CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
	alarm(0);

	if (ret <= 0) {
		DEBUG(1,("no reply received to cldap netlogon\n"));
		data_blob_free(&blob);
		return -1;
	}
	blob.length = ret;

	asn1_load(&data, blob);
	asn1_start_tag(&data, ASN1_SEQUENCE(0));
	asn1_read_Integer(&data, &i1);
	asn1_start_tag(&data, ASN1_APPLICATION(4));
	asn1_read_OctetString(&data, &os1);
	asn1_start_tag(&data, ASN1_SEQUENCE(0));
	asn1_start_tag(&data, ASN1_SEQUENCE(0));
	asn1_read_OctetString(&data, &os2);
	asn1_start_tag(&data, ASN1_SET);
	asn1_read_OctetString(&data, &os3);
	asn1_end_tag(&data);
	asn1_end_tag(&data);
	asn1_end_tag(&data);
	asn1_end_tag(&data);
	asn1_end_tag(&data);

	if (data.has_error) {
		data_blob_free(&blob);
		data_blob_free(&os1);
		data_blob_free(&os2);
		data_blob_free(&os3);
		asn1_free(&data);
		DEBUG(1,("Failed to parse cldap reply\n"));
		return -1;
	}

	r = TALLOC_ZERO_P(mem_ctx, union nbt_cldap_netlogon);
	if (!r) {
		errno = ENOMEM;
		data_blob_free(&os1);
		data_blob_free(&os2);
		data_blob_free(&os3);
		data_blob_free(&blob);
		return -1;
	}

	if (!pull_mailslot_cldap_reply(mem_ctx, &os3, r, nt_version)) {
		data_blob_free(&os1);
		data_blob_free(&os2);
		data_blob_free(&os3);
		data_blob_free(&blob);
		TALLOC_FREE(r);
		return -1;
	}

	data_blob_free(&os1);
	data_blob_free(&os2);
	data_blob_free(&os3);
	data_blob_free(&blob);
	
	asn1_free(&data);

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

	return 0;
}
Example #16
0
/*
 * Test some updates
 */
static bool test_dlz_bind9_update01(struct torture_context *tctx)
{
	NTSTATUS status;
	struct gensec_security *gensec_client_context;
	DATA_BLOB client_to_server, server_to_client;
	void *dbdata;
	void *version = NULL;
	const char *argv[] = {
		"samba_dlz",
		"-H",
		lpcfg_private_path(tctx, tctx->lp_ctx, "dns/sam.ldb"),
		NULL
	};
	struct test_expected_rr *expected1 = NULL;
	char *name = NULL;
	char *data0 = NULL;
	char *data1 = NULL;
	char *data2 = NULL;
	bool ret = false;

	tctx_static = tctx;
	torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, argv, &dbdata,
						  "log", dlz_bind9_log_wrapper,
						  "writeable_zone", dlz_bind9_writeable_zone_hook,
						  "putrr", dlz_bind9_putrr_hook,
						  "putnamedrr", dlz_bind9_putnamedrr_hook,
						  NULL),
				 ISC_R_SUCCESS,
				 "Failed to create samba_dlz");

	torture_assert_int_equal(tctx, dlz_configure((void*)tctx, dbdata),
						     ISC_R_SUCCESS,
				 "Failed to configure samba_dlz");

	expected1 = talloc_zero(tctx, struct test_expected_rr);
	torture_assert(tctx, expected1 != NULL, "talloc failed");
	expected1->tctx = tctx;

	expected1->query_name = __func__;

	name = talloc_asprintf(expected1, "%s.%s",
				expected1->query_name,
				lpcfg_dnsdomain(tctx->lp_ctx));
	torture_assert(tctx, name != NULL, "talloc failed");

	expected1->num_records = 2;
	expected1->records = talloc_zero_array(expected1,
					       struct test_expected_record,
					       expected1->num_records);
	torture_assert(tctx, expected1->records != NULL, "talloc failed");

	expected1->records[0].name = expected1->query_name;
	expected1->records[0].type = "a";
	expected1->records[0].ttl = 3600;
	expected1->records[0].data = "127.1.2.3";
	expected1->records[0].printed = false;

	data0 = talloc_asprintf(expected1,
				"%s.\t" "%u\t" "%s\t" "%s\t" "%s",
				name,
				(unsigned)expected1->records[0].ttl,
				"in",
				expected1->records[0].type,
				expected1->records[0].data);
	torture_assert(tctx, data0 != NULL, "talloc failed");

	expected1->records[1].name = expected1->query_name;
	expected1->records[1].type = "a";
	expected1->records[1].ttl = 3600;
	expected1->records[1].data = "127.3.2.1";
	expected1->records[1].printed = false;

	data1 = talloc_asprintf(expected1,
				"%s.\t" "%u\t" "%s\t" "%s\t" "%s",
				name,
				(unsigned)expected1->records[1].ttl,
				"in",
				expected1->records[1].type,
				expected1->records[1].data);
	torture_assert(tctx, data1 != NULL, "talloc failed");

	data2 = talloc_asprintf(expected1,
				"%s.\t" "0\t" "in\t" "a\t" "127.3.3.3",
				name);
	torture_assert(tctx, data2 != NULL, "talloc failed");

	/*
	 * Prepare session info
	 */
	status = gensec_client_start(tctx, &gensec_client_context,
				     lpcfg_gensec_settings(tctx, tctx->lp_ctx));
	torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed");

	/*
	 * dlz_bind9 use the special dns/host.domain account
	 */
	status = gensec_set_target_hostname(gensec_client_context,
					    talloc_asprintf(tctx,
				"%s.%s",
				torture_setting_string(tctx, "host", NULL),
				lpcfg_dnsdomain(tctx->lp_ctx)));
	torture_assert_ntstatus_ok(tctx, status, "gensec_set_target_hostname (client) failed");

	status = gensec_set_target_service(gensec_client_context, "dns");
	torture_assert_ntstatus_ok(tctx, status, "gensec_set_target_service failed");

	status = gensec_set_credentials(gensec_client_context, cmdline_credentials);
	torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");

	status = gensec_start_mech_by_sasl_name(gensec_client_context, "GSS-SPNEGO");
	torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (client) failed");

	server_to_client = data_blob(NULL, 0);

	/* Do one step of the client-server update dance */
	status = gensec_update(gensec_client_context, tctx, tctx->ev, server_to_client, &client_to_server);
	if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
		torture_assert_ntstatus_ok(tctx, status, "gensec_update (client) failed");
	}

	torture_assert_int_equal(tctx, dlz_ssumatch(cli_credentials_get_username(cmdline_credentials),
						    name,
						    "127.0.0.1",
						    expected1->records[0].type,
						    "key",
						    client_to_server.length,
						    client_to_server.data,
						    dbdata),
				 ISC_TRUE,
				 "Failed to check key for update rights samba_dlz");

	/*
	 * We test the following:
	 *
	 *  1. lookup the records => NOT_FOUND
	 *  2. delete all records => NOT_FOUND
	 *  3. delete 1st record => NOT_FOUND
	 *  4. create 1st record => SUCCESS
	 *  5. lookup the records => found 1st
	 *  6. create 2nd record => SUCCESS
	 *  7. lookup the records => found 1st and 2nd
	 *  8. delete unknown record => NOT_FOUND
	 *  9. lookup the records => found 1st and 2nd
	 * 10. delete 1st record => SUCCESS
	 * 11. lookup the records => found 2nd
	 * 12. delete 2nd record => SUCCESS
	 * 13. lookup the records => NOT_FOUND
	 * 14. create 1st record => SUCCESS
	 * 15. lookup the records => found 1st
	 * 16. create 2nd record => SUCCESS
	 * 17. lookup the records => found 1st and 2nd
	 * 18. update 1st record => SUCCESS
	 * 19. lookup the records => found 1st and 2nd
	 * 20. delete all unknown type records => NOT_FOUND
	 * 21. lookup the records => found 1st and 2nd
	 * 22. delete all records => SUCCESS
	 * 23. lookup the records => NOT_FOUND
	 */

	/* Step 1. */
	expected1->num_rr = 0;
	expected1->records[0].printed = false;
	expected1->records[1].printed = false;
	torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
						  expected1->query_name, dbdata,
						  (dns_sdlzlookup_t *)expected1),
				 ISC_R_NOTFOUND,
				 "Found hostname");
	torture_assert_int_equal(tctx, expected1->num_rr, 0,
				 "Got wrong record count");

	/* Step 2. */
	torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
						      dbdata, &version),
				 ISC_R_SUCCESS,
				 "Failed to start transaction");
	torture_assert_int_equal_goto(tctx,
			dlz_delrdataset(name,
					expected1->records[0].type,
					dbdata, version),
			ISC_R_NOTFOUND, ret, cancel_version,
			talloc_asprintf(tctx, "Deleted name[%s] type[%s]\n",
			name, expected1->records[0].type));
	dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), false, dbdata, &version);

	/* Step 3. */
	torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
						      dbdata, &version),
				 ISC_R_SUCCESS,
				 "Failed to start transaction");
	torture_assert_int_equal_goto(tctx,
			dlz_subrdataset(name, data0, dbdata, version),
			ISC_R_NOTFOUND, ret, cancel_version,
			talloc_asprintf(tctx, "Deleted name[%s] data[%s]\n",
			name, data0));
	dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), false, dbdata, &version);

	/* Step 4. */
	torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
						      dbdata, &version),
				 ISC_R_SUCCESS,
				 "Failed to start transaction");
	torture_assert_int_equal_goto(tctx,
			dlz_addrdataset(name, data0, dbdata, version),
			ISC_R_SUCCESS, ret, cancel_version,
			talloc_asprintf(tctx, "Failed to add name[%s] data[%s]\n",
			name, data0));
	dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);

	/* Step 5. */
	expected1->num_rr = 0;
	expected1->records[0].printed = false;
	expected1->records[1].printed = false;
	torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
						  expected1->query_name, dbdata,
						  (dns_sdlzlookup_t *)expected1),
				 ISC_R_SUCCESS,
				 "Not found hostname");
	torture_assert(tctx, expected1->records[0].printed,
		       talloc_asprintf(tctx,
		       "Failed to have putrr callback run name[%s] for type %s",
		       expected1->records[0].name,
		       expected1->records[0].type));
	torture_assert_int_equal(tctx, expected1->num_rr, 1,
				 "Got wrong record count");

	/* Step 6. */
	torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
						      dbdata, &version),
				 ISC_R_SUCCESS,
				 "Failed to start transaction");
	torture_assert_int_equal_goto(tctx,
			dlz_addrdataset(name, data1, dbdata, version),
			ISC_R_SUCCESS, ret, cancel_version,
			talloc_asprintf(tctx, "Failed to add name[%s] data[%s]\n",
			name, data1));
	dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);

	/* Step 7. */
	expected1->num_rr = 0;
	expected1->records[0].printed = false;
	expected1->records[1].printed = false;
	torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
						  expected1->query_name, dbdata,
						  (dns_sdlzlookup_t *)expected1),
				 ISC_R_SUCCESS,
				 "Not found hostname");
	torture_assert(tctx, expected1->records[0].printed,
		       talloc_asprintf(tctx,
		       "Failed to have putrr callback run name[%s] for type %s",
		       expected1->records[0].name,
		       expected1->records[0].type));
	torture_assert(tctx, expected1->records[1].printed,
		       talloc_asprintf(tctx,
		       "Failed to have putrr callback run name[%s] for type %s",
		       expected1->records[1].name,
		       expected1->records[1].type));
	torture_assert_int_equal(tctx, expected1->num_rr, 2,
				 "Got wrong record count");

	/* Step 8. */
	torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
						      dbdata, &version),
				 ISC_R_SUCCESS,
				 "Failed to start transaction");
	torture_assert_int_equal_goto(tctx,
			dlz_subrdataset(name, data2, dbdata, version),
			ISC_R_NOTFOUND, ret, cancel_version,
			talloc_asprintf(tctx, "Deleted name[%s] data[%s]\n",
			name, data2));
	dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);

	/* Step 9. */
	expected1->num_rr = 0;
	expected1->records[0].printed = false;
	expected1->records[1].printed = false;
	torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
						  expected1->query_name, dbdata,
						  (dns_sdlzlookup_t *)expected1),
				 ISC_R_SUCCESS,
				 "Not found hostname");
	torture_assert(tctx, expected1->records[0].printed,
		       talloc_asprintf(tctx,
		       "Failed to have putrr callback run name[%s] for type %s",
		       expected1->records[0].name,
		       expected1->records[0].type));
	torture_assert(tctx, expected1->records[1].printed,
		       talloc_asprintf(tctx,
		       "Failed to have putrr callback run name[%s] for type %s",
		       expected1->records[1].name,
		       expected1->records[1].type));
	torture_assert_int_equal(tctx, expected1->num_rr, 2,
				 "Got wrong record count");

	/* Step 10. */
	torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
						      dbdata, &version),
				 ISC_R_SUCCESS,
				 "Failed to start transaction");
	torture_assert_int_equal_goto(tctx,
			dlz_subrdataset(name, data0, dbdata, version),
			ISC_R_SUCCESS, ret, cancel_version,
			talloc_asprintf(tctx, "Failed to delete name[%s] data[%s]\n",
			name, data0));
	dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);

	/* Step 11. */
	expected1->num_rr = 0;
	expected1->records[0].printed = false;
	expected1->records[1].printed = false;
	torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
						  expected1->query_name, dbdata,
						  (dns_sdlzlookup_t *)expected1),
				 ISC_R_SUCCESS,
				 "Not found hostname");
	torture_assert(tctx, expected1->records[1].printed,
		       talloc_asprintf(tctx,
		       "Failed to have putrr callback run name[%s] for type %s",
		       expected1->records[1].name,
		       expected1->records[1].type));
	torture_assert_int_equal(tctx, expected1->num_rr, 1,
				 "Got wrong record count");

	/* Step 12. */
	torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
						      dbdata, &version),
				 ISC_R_SUCCESS,
				 "Failed to start transaction");
	torture_assert_int_equal_goto(tctx,
			dlz_subrdataset(name, data1, dbdata, version),
			ISC_R_SUCCESS, ret, cancel_version,
			talloc_asprintf(tctx, "Failed to delete name[%s] data[%s]\n",
			name, data1));
	dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);

	/* Step 13. */
	expected1->num_rr = 0;
	expected1->records[0].printed = false;
	expected1->records[1].printed = false;
	torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
						  expected1->query_name, dbdata,
						  (dns_sdlzlookup_t *)expected1),
				 ISC_R_NOTFOUND,
				 "Found hostname");
	torture_assert_int_equal(tctx, expected1->num_rr, 0,
				 "Got wrong record count");

	/* Step 14. */
	torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
						      dbdata, &version),
				 ISC_R_SUCCESS,
				 "Failed to start transaction");
	torture_assert_int_equal_goto(tctx,
			dlz_addrdataset(name, data0, dbdata, version),
			ISC_R_SUCCESS, ret, cancel_version,
			talloc_asprintf(tctx, "Failed to add name[%s] data[%s]\n",
			name, data0));
	dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);

	/* Step 15. */
	expected1->num_rr = 0;
	expected1->records[0].printed = false;
	expected1->records[1].printed = false;
	torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
						  expected1->query_name, dbdata,
						  (dns_sdlzlookup_t *)expected1),
				 ISC_R_SUCCESS,
				 "Not found hostname");
	torture_assert(tctx, expected1->records[0].printed,
		       talloc_asprintf(tctx,
		       "Failed to have putrr callback run name[%s] for type %s",
		       expected1->records[0].name,
		       expected1->records[0].type));
	torture_assert_int_equal(tctx, expected1->num_rr, 1,
				 "Got wrong record count");

	/* Step 16. */
	torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
						      dbdata, &version),
				 ISC_R_SUCCESS,
				 "Failed to start transaction");
	torture_assert_int_equal_goto(tctx,
			dlz_addrdataset(name, data1, dbdata, version),
			ISC_R_SUCCESS, ret, cancel_version,
			talloc_asprintf(tctx, "Failed to add name[%s] data[%s]\n",
			name, data1));
	dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);

	/* Step 17. */
	expected1->num_rr = 0;
	expected1->records[0].printed = false;
	expected1->records[1].printed = false;
	torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
						  expected1->query_name, dbdata,
						  (dns_sdlzlookup_t *)expected1),
				 ISC_R_SUCCESS,
				 "Not found hostname");
	torture_assert(tctx, expected1->records[0].printed,
		       talloc_asprintf(tctx,
		       "Failed to have putrr callback run name[%s] for type %s",
		       expected1->records[0].name,
		       expected1->records[0].type));
	torture_assert(tctx, expected1->records[1].printed,
		       talloc_asprintf(tctx,
		       "Failed to have putrr callback run name[%s] for type %s",
		       expected1->records[1].name,
		       expected1->records[1].type));
	torture_assert_int_equal(tctx, expected1->num_rr, 2,
				 "Got wrong record count");

	/* Step 18. */
	torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
						      dbdata, &version),
				 ISC_R_SUCCESS,
				 "Failed to start transaction");
	torture_assert_int_equal_goto(tctx,
			dlz_addrdataset(name, data0, dbdata, version),
			ISC_R_SUCCESS, ret, cancel_version,
			talloc_asprintf(tctx, "Failed to update name[%s] data[%s]\n",
			name, data0));
	dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);

	/* Step 19. */
	expected1->num_rr = 0;
	expected1->records[0].printed = false;
	expected1->records[1].printed = false;
	torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
						  expected1->query_name, dbdata,
						  (dns_sdlzlookup_t *)expected1),
				 ISC_R_SUCCESS,
				 "Not found hostname");
	torture_assert(tctx, expected1->records[0].printed,
		       talloc_asprintf(tctx,
		       "Failed to have putrr callback run name[%s] for type %s",
		       expected1->records[0].name,
		       expected1->records[0].type));
	torture_assert(tctx, expected1->records[1].printed,
		       talloc_asprintf(tctx,
		       "Failed to have putrr callback run name[%s] for type %s",
		       expected1->records[1].name,
		       expected1->records[1].type));
	torture_assert_int_equal(tctx, expected1->num_rr, 2,
				 "Got wrong record count");

	/* Step 20. */
	torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
						      dbdata, &version),
				 ISC_R_SUCCESS,
				 "Failed to start transaction");
	torture_assert_int_equal_goto(tctx,
			dlz_delrdataset(name, "txt", dbdata, version),
			ISC_R_FAILURE, ret, cancel_version,
			talloc_asprintf(tctx, "Deleted name[%s] type[%s]\n",
			name, "txt"));
	dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), false, dbdata, &version);

	/* Step 21. */
	expected1->num_rr = 0;
	expected1->records[0].printed = false;
	expected1->records[1].printed = false;
	torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
						  expected1->query_name, dbdata,
						  (dns_sdlzlookup_t *)expected1),
				 ISC_R_SUCCESS,
				 "Not found hostname");
	torture_assert(tctx, expected1->records[0].printed,
		       talloc_asprintf(tctx,
		       "Failed to have putrr callback run name[%s] for type %s",
		       expected1->records[0].name,
		       expected1->records[0].type));
	torture_assert(tctx, expected1->records[1].printed,
		       talloc_asprintf(tctx,
		       "Failed to have putrr callback run name[%s] for type %s",
		       expected1->records[1].name,
		       expected1->records[1].type));
	torture_assert_int_equal(tctx, expected1->num_rr, 2,
				 "Got wrong record count");

	/* Step 22. */
	torture_assert_int_equal(tctx, dlz_newversion(lpcfg_dnsdomain(tctx->lp_ctx),
						      dbdata, &version),
				 ISC_R_SUCCESS,
				 "Failed to start transaction");
	torture_assert_int_equal_goto(tctx,
			dlz_delrdataset(name,
					expected1->records[0].type,
					dbdata, version),
			ISC_R_SUCCESS, ret, cancel_version,
			talloc_asprintf(tctx, "Failed to delete name[%s] type[%s]\n",
			name, expected1->records[0].type));
	dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), true, dbdata, &version);

	/* Step 23. */
	expected1->num_rr = 0;
	expected1->records[0].printed = false;
	expected1->records[1].printed = false;
	torture_assert_int_equal(tctx, dlz_lookup(lpcfg_dnsdomain(tctx->lp_ctx),
						  expected1->query_name, dbdata,
						  (dns_sdlzlookup_t *)expected1),
				 ISC_R_NOTFOUND,
				 "Found hostname");
	torture_assert_int_equal(tctx, expected1->num_rr, 0,
				 "Got wrong record count");

	dlz_destroy(dbdata);

	return true;

cancel_version:
	dlz_closeversion(lpcfg_dnsdomain(tctx->lp_ctx), false, dbdata, &version);
	return ret;
}
Example #17
0
/* 
   this performs a SASL/SPNEGO bind
*/
static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
{
	struct berval *scred=NULL;
	int rc, i;
	ADS_STATUS status;
	DATA_BLOB blob;
	char *given_principal = NULL;
	char *OIDs[ASN1_MAX_OIDS];
#ifdef HAVE_KRB5
	bool got_kerberos_mechanism = False;
#endif

	rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);

	if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
		status = ADS_ERROR(rc);
		goto failed;
	}

	blob = data_blob(scred->bv_val, scred->bv_len);

	ber_bvfree(scred);

#if 0
	file_save("sasl_spnego.dat", blob.data, blob.length);
#endif

	/* the server sent us the first part of the SPNEGO exchange in the negprot 
	   reply */
	if (!spnego_parse_negTokenInit(blob, OIDs, &given_principal)) {
		data_blob_free(&blob);
		status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
		goto failed;
	}
	data_blob_free(&blob);

	/* make sure the server understands kerberos */
	for (i=0;OIDs[i];i++) {
		DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
#ifdef HAVE_KRB5
		if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
		    strcmp(OIDs[i], OID_KERBEROS5) == 0) {
			got_kerberos_mechanism = True;
		}
#endif
		talloc_free(OIDs[i]);
	}
	DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));

#ifdef HAVE_KRB5
	if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
	    got_kerberos_mechanism) 
	{
		struct ads_service_principal p;

		status = ads_generate_service_principal(ads, given_principal, &p);
		TALLOC_FREE(given_principal);
		if (!ADS_ERR_OK(status)) {
			return status;
		}

		status = ads_sasl_spnego_krb5_bind(ads, &p);
		if (ADS_ERR_OK(status)) {
			ads_free_service_principal(&p);
			return status;
		}

		DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
			  "calling kinit\n", ads_errstr(status)));

		status = ADS_ERROR_KRB5(ads_kinit_password(ads)); 

		if (ADS_ERR_OK(status)) {
			status = ads_sasl_spnego_krb5_bind(ads, &p);
			if (!ADS_ERR_OK(status)) {
				DEBUG(0,("kinit succeeded but "
					"ads_sasl_spnego_krb5_bind failed: %s\n",
					ads_errstr(status)));
			}
		}

		ads_free_service_principal(&p);

		/* only fallback to NTLMSSP if allowed */
		if (ADS_ERR_OK(status) || 
		    !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
			return status;
		}
	} else
#endif
	{
		TALLOC_FREE(given_principal);
	}

	/* lets do NTLMSSP ... this has the big advantage that we don't need
	   to sync clocks, and we don't rely on special versions of the krb5 
	   library for HMAC_MD4 encryption */
	return ads_sasl_spnego_ntlmssp_bind(ads);

failed:
	return status;
}
Example #18
0
static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg,
				 struct kdc_check_generic_kerberos *r)
{
	struct PAC_Validate pac_validate;
	DATA_BLOB srv_sig;
	struct PAC_SIGNATURE_DATA kdc_sig;
	struct kdc_server *kdc = talloc_get_type(msg->private_data, struct kdc_server);
	krb5_kdc_configuration *kdc_config =
		(krb5_kdc_configuration *)kdc->private_data;
	enum ndr_err_code ndr_err;
	int ret;
	hdb_entry_ex ent;
	krb5_principal principal;


	/* There is no reply to this request */
	r->out.generic_reply = data_blob(NULL, 0);

	ndr_err = ndr_pull_struct_blob(&r->in.generic_request, msg, &pac_validate,
				       (ndr_pull_flags_fn_t)ndr_pull_PAC_Validate);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (pac_validate.MessageType != NETLOGON_GENERIC_KRB5_PAC_VALIDATE) {
		/* We don't implement any other message types - such as certificate validation - yet */
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (pac_validate.ChecksumAndSignature.length != (pac_validate.ChecksumLength + pac_validate.SignatureLength)
	    || pac_validate.ChecksumAndSignature.length < pac_validate.ChecksumLength
	    || pac_validate.ChecksumAndSignature.length < pac_validate.SignatureLength ) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	srv_sig = data_blob_const(pac_validate.ChecksumAndSignature.data,
				  pac_validate.ChecksumLength);

	ret = krb5_make_principal(kdc->smb_krb5_context->krb5_context, &principal,
				  lpcfg_realm(kdc->task->lp_ctx),
				  "krbtgt", lpcfg_realm(kdc->task->lp_ctx),
				  NULL);

	if (ret != 0) {
		return NT_STATUS_NO_MEMORY;
	}

	ret = kdc_config->db[0]->hdb_fetch_kvno(kdc->smb_krb5_context->krb5_context,
						 kdc_config->db[0],
						 principal,
						 HDB_F_GET_KRBTGT | HDB_F_DECRYPT,
						 0,
						 &ent);

	if (ret != 0) {
		hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent);
		krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal);

		return NT_STATUS_LOGON_FAILURE;
	}

	kdc_sig.type = pac_validate.SignatureType;
	kdc_sig.signature = data_blob_const(&pac_validate.ChecksumAndSignature.data[pac_validate.ChecksumLength],
					    pac_validate.SignatureLength);

	ret = kdc_check_pac(kdc->smb_krb5_context->krb5_context, srv_sig, &kdc_sig, &ent);

	hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent);
	krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal);

	if (ret != 0) {
		return NT_STATUS_LOGON_FAILURE;
	}

	return NT_STATUS_OK;
}
Example #19
0
int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute, 
		 void (*fn)(const char *, file_info *, const char *, void *), void *state)
{
#if 1
	int max_matches = 1366; /* Match W2k - was 512. */
#else
	int max_matches = 512;
#endif
	int info_level;
	char *p, *p2;
	pstring mask;
	file_info finfo;
	int i;
	char *dirlist = NULL;
	int dirlist_len = 0;
	int total_received = -1;
	BOOL First = True;
	int ff_searchcount=0;
	int ff_eos=0;
	int ff_dir_handle=0;
	int loop_count = 0;
	char *rparam=NULL, *rdata=NULL;
	unsigned int param_len, data_len;	
	uint16 setup;
	pstring param;
	const char *mnt;
	uint32 resume_key = 0;
	uint32 last_name_raw_len = 0;
	DATA_BLOB last_name_raw = data_blob(NULL, 2*sizeof(pstring));

	/* NT uses 260, OS/2 uses 2. Both accept 1. */
	info_level = (cli->capabilities&CAP_NT_SMBS)?260:1;
	
	pstrcpy(mask,Mask);
	
	while (ff_eos == 0) {
		loop_count++;
		if (loop_count > 200) {
			DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
			break;
		}

		if (First) {
			setup = TRANSACT2_FINDFIRST;
			SSVAL(param,0,attribute); /* attribute */
			SSVAL(param,2,max_matches); /* max count */
			SSVAL(param,4,(FLAG_TRANS2_FIND_REQUIRE_RESUME|FLAG_TRANS2_FIND_CLOSE_IF_END));	/* resume required + close on end */
			SSVAL(param,6,info_level); 
			SIVAL(param,8,0);
			p = param+12;
			p += clistr_push(cli, param+12, mask, sizeof(param)-12, 
					 STR_TERMINATE);
		} else {
			setup = TRANSACT2_FINDNEXT;
			SSVAL(param,0,ff_dir_handle);
			SSVAL(param,2,max_matches); /* max count */
			SSVAL(param,4,info_level); 
			/* For W2K servers serving out FAT filesystems we *must* set the
			   resume key. If it's not FAT then it's returned as zero. */
			SIVAL(param,6,resume_key); /* ff_resume_key */
			/* NB. *DON'T* use continue here. If you do it seems that W2K and bretheren
			   can miss filenames. Use last filename continue instead. JRA */
			SSVAL(param,10,(FLAG_TRANS2_FIND_REQUIRE_RESUME|FLAG_TRANS2_FIND_CLOSE_IF_END));	/* resume required + close on end */
			p = param+12;
			if (last_name_raw_len && (last_name_raw_len < (sizeof(param)-12))) {
				memcpy(p, last_name_raw.data, last_name_raw_len);
				p += last_name_raw_len;
			} else {
				p += clistr_push(cli, param+12, mask, sizeof(param)-12, STR_TERMINATE);
			}
		}

		param_len = PTR_DIFF(p, param);

		if (!cli_send_trans(cli, SMBtrans2, 
				    NULL,                   /* Name */
				    -1, 0,                  /* fid, flags */
				    &setup, 1, 0,           /* setup, length, max */
				    param, param_len, 10,   /* param, length, max */
				    NULL, 0, 
#if 0
				    /* w2k value. */
				    MIN(16384,cli->max_xmit) /* data, length, max. */
#else
				    cli->max_xmit	    /* data, length, max. */
#endif
				    )) {
			break;
		}

		if (!cli_receive_trans(cli, SMBtrans2, 
				       &rparam, &param_len,
				       &rdata, &data_len) &&
                    cli_is_dos_error(cli)) {
			/* We need to work around a Win95 bug - sometimes
			   it gives ERRSRV/ERRerror temprarily */
			uint8 eclass;
			uint32 ecode;

			SAFE_FREE(rdata);
			SAFE_FREE(rparam);

			cli_dos_error(cli, &eclass, &ecode);

			/*
			 * OS/2 might return "no more files",
			 * which just tells us, that searchcount is zero
			 * in this search.
			 * Guenter Kukkukk <[email protected]>
			 */

			if (eclass == ERRDOS && ecode == ERRnofiles) {
				ff_searchcount = 0;
				cli_reset_error(cli);
				break;
			}

			if (eclass != ERRSRV || ecode != ERRerror)
				break;
			smb_msleep(100);
			continue;
		}

                if (cli_is_error(cli) || !rdata || !rparam) {
			SAFE_FREE(rdata);
			SAFE_FREE(rparam);
			break;
		}

		if (total_received == -1)
			total_received = 0;

		/* parse out some important return info */
		p = rparam;
		if (First) {
			ff_dir_handle = SVAL(p,0);
			ff_searchcount = SVAL(p,2);
			ff_eos = SVAL(p,4);
		} else {
			ff_searchcount = SVAL(p,0);
			ff_eos = SVAL(p,2);
		}

		if (ff_searchcount == 0) {
			SAFE_FREE(rdata);
			SAFE_FREE(rparam);
			break;
		}

		/* point to the data bytes */
		p = rdata;

		/* we might need the lastname for continuations */
		for (p2=p,i=0;i<ff_searchcount;i++) {
			if ((info_level == 260) && (i == ff_searchcount-1)) {
				/* Last entry - fixup the last offset length. */
				SIVAL(p2,0,PTR_DIFF((rdata + data_len),p2));
			}
			p2 += interpret_long_filename(cli,info_level,p2,&finfo,
							&resume_key,&last_name_raw,&last_name_raw_len);

			if (!First && *mask && strcsequal(finfo.name, mask)) {
				DEBUG(0,("Error: Looping in FIND_NEXT as name %s has already been seen?\n",
					finfo.name));
				ff_eos = 1;
				break;
			}
		}

		if (ff_searchcount > 0) {
			pstrcpy(mask, finfo.name);
		} else {
			pstrcpy(mask,"");
		}

		/* grab the data for later use */
		/* and add them to the dirlist pool */
		dirlist = (char *)SMB_REALLOC(dirlist,dirlist_len + data_len);

		if (!dirlist) {
			DEBUG(0,("cli_list_new: Failed to expand dirlist\n"));
			SAFE_FREE(rdata);
			SAFE_FREE(rparam);
			break;
		}

		memcpy(dirlist+dirlist_len,p,data_len);
		dirlist_len += data_len;

		total_received += ff_searchcount;

		SAFE_FREE(rdata);
		SAFE_FREE(rparam);

		DEBUG(3,("received %d entries (eos=%d)\n",
			 ff_searchcount,ff_eos));

		if (ff_searchcount > 0)
			loop_count = 0;

		First = False;
	}

	mnt = cli_cm_get_mntpoint( cli );

        /* see if the server disconnected or the connection otherwise failed */
        if (cli_is_error(cli)) {
                total_received = -1;
        } else {
                /* no connection problem.  let user function add each entry */
                for (p=dirlist,i=0;i<total_received;i++) {
                        p += interpret_long_filename(cli, info_level, p,
                                                     &finfo,NULL,NULL,NULL);
                        fn( mnt,&finfo, Mask, state );
                }
        }

	/* free up the dirlist buffer and last name raw blob */
	SAFE_FREE(dirlist);
	data_blob_free(&last_name_raw);
	return(total_received);
}
Example #20
0
_PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, 
					   int *flags,
					   DATA_BLOB challenge,
					   const NTTIME *server_timestamp,
					   DATA_BLOB target_info,
					   DATA_BLOB *_lm_response, DATA_BLOB *_nt_response, 
					   DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key) 
{
	const char *user, *domain;
	DATA_BLOB lm_response, nt_response;
	DATA_BLOB lm_session_key, session_key;
	const struct samr_Password *nt_hash;
	lm_session_key = data_blob(NULL, 0);

	/* We may already have an NTLM response we prepared earlier.
	 * This is used for NTLM pass-though authentication */
	if (cred->nt_response.data || cred->lm_response.data) {
		*_nt_response = cred->nt_response;
		*_lm_response = cred->lm_response;

		if (!cred->lm_response.data) {
			*flags = *flags & ~CLI_CRED_LANMAN_AUTH;
		}
		*_lm_session_key = data_blob(NULL, 0);
		*_session_key = data_blob(NULL, 0);
		return NT_STATUS_OK;
	}

	nt_hash = cli_credentials_get_nt_hash(cred, mem_ctx);

	cli_credentials_get_ntlm_username_domain(cred, mem_ctx, &user, &domain);

	/* If we are sending a [email protected] login (see function
	 * above), then we will not send LM, it will not be
	 * accepted */
	if (cred->principal_obtained > cred->username_obtained) {
		*flags = *flags & ~CLI_CRED_LANMAN_AUTH;
	}

	/* Likewise if we are a machine account (avoid protocol downgrade attacks) */
	if (cred->machine_account) {
		*flags = *flags & ~CLI_CRED_LANMAN_AUTH;
	}
	
	if (cred->use_kerberos == CRED_MUST_USE_KERBEROS) {
		return NT_STATUS_ACCESS_DENIED;
	}

	if (!nt_hash) {
		static const uint8_t zeros[16];
		/* do nothing - blobs are zero length */

		/* session key is all zeros */
		session_key = data_blob_talloc(mem_ctx, zeros, 16);
		lm_session_key = data_blob_talloc(mem_ctx, zeros, 16);

		lm_response = data_blob(NULL, 0);
		nt_response = data_blob(NULL, 0);
		
		/* not doing NTLM2 without a password */
		*flags &= ~CLI_CRED_NTLM2;
	} else if (*flags & CLI_CRED_NTLMv2_AUTH) {

		if (!target_info.length) {
			/* be lazy, match win2k - we can't do NTLMv2 without it */
			DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
			return NT_STATUS_INVALID_PARAMETER;
		}

		/* TODO: if the remote server is standalone, then we should replace 'domain'
		   with the server name as supplied above */
		
		if (!SMBNTLMv2encrypt_hash(mem_ctx,
					   user, 
					   domain, 
					   nt_hash->hash, &challenge, 
					   server_timestamp, &target_info,
					   &lm_response, &nt_response, 
					   NULL, &session_key)) {
			return NT_STATUS_NO_MEMORY;
		}

		/* LM Key is incompatible... */
		*flags &= ~CLI_CRED_LANMAN_AUTH;
		if (lm_response.length != 0) {
			/*
			 * We should not expose the lm key.
			 */
			memset(lm_response.data, 0, lm_response.length);
		}
	} else if (*flags & CLI_CRED_NTLM2) {
		MD5_CTX md5_session_nonce_ctx;
		uint8_t session_nonce[16];
		uint8_t session_nonce_hash[16];
		uint8_t user_session_key[16];
		
		lm_response = data_blob_talloc(mem_ctx, NULL, 24);
		generate_random_buffer(lm_response.data, 8);
		memset(lm_response.data+8, 0, 16);

		memcpy(session_nonce, challenge.data, 8);
		memcpy(&session_nonce[8], lm_response.data, 8);
	
		MD5Init(&md5_session_nonce_ctx);
		MD5Update(&md5_session_nonce_ctx, challenge.data, 8);
		MD5Update(&md5_session_nonce_ctx, lm_response.data, 8);
		MD5Final(session_nonce_hash, &md5_session_nonce_ctx);

		DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
		DEBUG(5, ("challenge is: \n"));
		dump_data(5, session_nonce_hash, 8);
		
		nt_response = data_blob_talloc(mem_ctx, NULL, 24);
		SMBOWFencrypt(nt_hash->hash,
			      session_nonce_hash,
			      nt_response.data);
		
		session_key = data_blob_talloc(mem_ctx, NULL, 16);

		SMBsesskeygen_ntv1(nt_hash->hash, user_session_key);
		hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data);
		dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);

		/* LM Key is incompatible... */
		*flags &= ~CLI_CRED_LANMAN_AUTH;
	} else {
		uint8_t lm_hash[16];
		nt_response = data_blob_talloc(mem_ctx, NULL, 24);
		SMBOWFencrypt(nt_hash->hash, challenge.data,
			      nt_response.data);
		
		session_key = data_blob_talloc(mem_ctx, NULL, 16);
		SMBsesskeygen_ntv1(nt_hash->hash, session_key.data);
		dump_data_pw("NT session key:\n", session_key.data, session_key.length);

		/* lanman auth is insecure, it may be disabled.  
		   We may also not have a password */
		if (*flags & CLI_CRED_LANMAN_AUTH) {
			const char *password;
			password = cli_credentials_get_password(cred);
			if (!password) {
				lm_response = nt_response;
			} else {
				lm_response = data_blob_talloc(mem_ctx, NULL, 24);
				if (!SMBencrypt(password,challenge.data,
						lm_response.data)) {
					/* If the LM password was too long (and therefore the LM hash being
					   of the first 14 chars only), don't send it.

					   We don't have any better options but to send the NT response 
					*/
					data_blob_free(&lm_response);
					lm_response = nt_response;
					/* LM Key is incompatible with 'long' passwords */
					*flags &= ~CLI_CRED_LANMAN_AUTH;
				} else if (E_deshash(password, lm_hash)) {
					lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
					memcpy(lm_session_key.data, lm_hash, 8);
					memset(&lm_session_key.data[8], '\0', 8);
					
					if (!(*flags & CLI_CRED_NTLM_AUTH)) {
						session_key = lm_session_key;
					}
				}
			}
		} else {
			const char *password;

			/* LM Key is incompatible... */
			lm_response = nt_response;
			*flags &= ~CLI_CRED_LANMAN_AUTH;

			password = cli_credentials_get_password(cred);
			if (password && E_deshash(password, lm_hash)) {
				lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
				memcpy(lm_session_key.data, lm_hash, 8);
				memset(&lm_session_key.data[8], '\0', 8);
			}
		}
	}
	if (_lm_response) {
		*_lm_response = lm_response;
	}
	if (_nt_response) {
		*_nt_response = nt_response;
	}
	if (_lm_session_key) {
		*_lm_session_key = lm_session_key;
	}
	if (_session_key) {
		*_session_key = session_key;
	}
	return NT_STATUS_OK;
}
Example #21
0
static bool test_ntlm_in_both(void) 
{
	bool pass = True;
	NTSTATUS nt_status;
	uint32 flags = 0;
	DATA_BLOB nt_response = data_blob(NULL, 24);
	DATA_BLOB session_key = data_blob(NULL, 16);

	uint8 lm_key[8];
	uint8 lm_hash[16];
	uint8 user_session_key[16];
	uint8 nt_hash[16];
	DATA_BLOB chall = get_challenge();
	char *error_string;
	
	ZERO_STRUCT(lm_key);
	ZERO_STRUCT(user_session_key);

	flags |= WBFLAG_PAM_LMKEY;
	flags |= WBFLAG_PAM_USER_SESSION_KEY;

	SMBNTencrypt(opt_password,chall.data,nt_response.data);
	E_md4hash(opt_password, nt_hash);
	SMBsesskeygen_ntv1(nt_hash, session_key.data);

	E_deshash(opt_password, lm_hash); 

	nt_status = contact_winbind_auth_crap(opt_username, opt_domain, 
					      opt_workstation,
					      &chall,
					      &nt_response,
					      &nt_response,
					      flags,
					      lm_key,
					      user_session_key,
					      &error_string, NULL);
	
	data_blob_free(&nt_response);

	if (!NT_STATUS_IS_OK(nt_status)) {
		d_printf("%s (0x%x)\n", 
			 error_string,
			 NT_STATUS_V(nt_status));
		SAFE_FREE(error_string);
		return False;
	}

	if (memcmp(lm_hash, lm_key, 
		   sizeof(lm_key)) != 0) {
		DEBUG(1, ("LM Key does not match expectations!\n"));
 		DEBUG(1, ("lm_key:\n"));
		dump_data(1, lm_key, 8);
		DEBUG(1, ("expected:\n"));
		dump_data(1, lm_hash, 8);
		pass = False;
	}
	if (memcmp(session_key.data, user_session_key, 
		   sizeof(user_session_key)) != 0) {
		DEBUG(1, ("NT Session Key does not match expectations!\n"));
 		DEBUG(1, ("user_session_key:\n"));
		dump_data(1, user_session_key, 16);
 		DEBUG(1, ("expected:\n"));
		dump_data(1, session_key.data, session_key.length);
		pass = False;
	}


        return pass;
}
Example #22
0
File: negprot.c Project: aosm/samba
static DATA_BLOB negprot_spnego(void)
{
	DATA_BLOB blob;
	nstring dos_name;
	fstring unix_name;
#ifdef DEVELOPER
	size_t slen;
#endif
	char guid[17];
	const char *OIDs_krb5[] = {OID_KERBEROS5,
				   OID_KERBEROS5_OLD,
				   OID_NTLMSSP,
				   NULL};
	const char *OIDs_plain[] = {OID_NTLMSSP, NULL};

	global_spnego_negotiated = True;

	memset(guid, '\0', sizeof(guid));

	safe_strcpy(unix_name, global_myname(), sizeof(unix_name)-1);
	strlower_m(unix_name);
	push_ascii_nstring(dos_name, unix_name);
	safe_strcpy(guid, dos_name, sizeof(guid)-1);

#ifdef DEVELOPER
	/* Fix valgrind 'uninitialized bytes' issue. */
	slen = strlen(dos_name);
	if (slen < sizeof(guid)) {
		memset(guid+slen, '\0', sizeof(guid) - slen);
	}
#endif

	/* strangely enough, NT does not sent the single OID NTLMSSP when
	   not a ADS member, it sends no OIDs at all

	   OLD COMMENT : "we can't do this until we teach our sesssion setup parser to know
		   about raw NTLMSSP (clients send no ASN.1 wrapping if we do this)"

	   Our sessionsetup code now handles raw NTLMSSP connects, so we can go
	   back to doing what W2K3 does here. This is needed to make PocketPC 2003
	   CIFS connections work with SPNEGO. See bugzilla bugs #1828 and #3133
	   for details. JRA.

	*/

	if (lp_security() != SEC_ADS && !lp_use_kerberos_keytab()) {
#if 0
		/* Code for PocketPC client */
		blob = data_blob(guid, 16);
#else
		/* Code for standalone WXP client */
		blob = spnego_gen_negTokenInit(guid, OIDs_plain, "NONE");
#endif
	} else {
		fstring myname;
		char *host_princ_s = NULL;

		const char * lkdc_realm =
			lp_parm_talloc_string(GLOBAL_SECTION_SNUM,
				"com.apple", "lkdc realm", NULL);

		myname[0] = '\0';
		get_mydnsfullname(myname);
		strlower_m(myname);

		/* If we have a LKDC, use it unless there is a managed realm
		 * also configured. The managed realm should have precedence.
		 */
		if (lkdc_realm && (*lp_realm() == '\0' ||
				strcmp(lkdc_realm, lp_realm()) == 0)) {
			asprintf(&host_princ_s,
				"cifs/%[email protected]%s", lkdc_realm, lkdc_realm);
		} else {
			asprintf(&host_princ_s, "cifs/%[email protected]%s",
					myname, lp_realm());
		}

		blob = spnego_gen_negTokenInit(guid, OIDs_krb5, host_princ_s);

		SAFE_FREE(host_princ_s);
		TALLOC_FREE(lkdc_realm);
	}

	return blob;
}
Example #23
0
static bool test_plaintext(enum ntlm_break break_which)
{
	NTSTATUS nt_status;
	uint32 flags = 0;
	DATA_BLOB nt_response = data_blob_null;
	DATA_BLOB lm_response = data_blob_null;
	char *password;
	smb_ucs2_t *nt_response_ucs2;
	size_t converted_size;

	uchar user_session_key[16];
	uchar lm_key[16];
	static const uchar zeros[8] = { 0, };
	DATA_BLOB chall = data_blob(zeros, sizeof(zeros));
	char *error_string;

	ZERO_STRUCT(user_session_key);
	
	flags |= WBFLAG_PAM_LMKEY;
	flags |= WBFLAG_PAM_USER_SESSION_KEY;

	if (!push_ucs2_talloc(talloc_tos(), &nt_response_ucs2, opt_password,
				&converted_size))
	{
		DEBUG(0, ("push_ucs2_talloc failed!\n"));
		exit(1);
	}

	nt_response.data = (unsigned char *)nt_response_ucs2;
	nt_response.length = strlen_w(nt_response_ucs2)*sizeof(smb_ucs2_t);

	if ((password = strupper_talloc(talloc_tos(), opt_password)) == NULL) {
		DEBUG(0, ("strupper_talloc() failed!\n"));
		exit(1);
	}

	if (!convert_string_talloc(talloc_tos(), CH_UNIX,
				   CH_DOS, password,
				   strlen(password)+1, 
				   &lm_response.data,
				   &lm_response.length, True)) {
		DEBUG(0, ("convert_string_talloc failed!\n"));
		exit(1);
	}

	TALLOC_FREE(password);

	switch (break_which) {
	case BREAK_NONE:
		break;
	case BREAK_LM:
		lm_response.data[0]++;
		break;
	case BREAK_NT:
		nt_response.data[0]++;
		break;
	case NO_LM:
		TALLOC_FREE(lm_response.data);
		lm_response.length = 0;
		break;
	case NO_NT:
		TALLOC_FREE(nt_response.data);
		nt_response.length = 0;
		break;
	}

	nt_status = contact_winbind_auth_crap(opt_username, opt_domain, 
					      opt_workstation,
					      &chall,
					      &lm_response,
					      &nt_response,
					      flags,
					      lm_key,
					      user_session_key,
					      &error_string, NULL);
	
	TALLOC_FREE(nt_response.data);
	TALLOC_FREE(lm_response.data);
	data_blob_free(&chall);

	if (!NT_STATUS_IS_OK(nt_status)) {
		d_printf("%s (0x%x)\n", 
			 error_string,
			 NT_STATUS_V(nt_status));
		SAFE_FREE(error_string);
		return break_which == BREAK_NT;
	}

        return break_which != BREAK_NT;
}
Example #24
0
/*
  send a async dcerpc bind request
*/
struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
					   TALLOC_CTX *mem_ctx,
					   const struct ndr_syntax_id *syntax,
					   const struct ndr_syntax_id *transfer_syntax)
{
	struct composite_context *c;
	struct ncacn_packet pkt;
	DATA_BLOB blob;
	struct rpc_request *req;

	c = composite_create(mem_ctx,p->conn->event_ctx);
	if (c == NULL) return NULL;

	c->private_data = p;

	p->syntax = *syntax;
	p->transfer_syntax = *transfer_syntax;

	init_ncacn_hdr(p->conn, &pkt);

	pkt.ptype = DCERPC_PKT_BIND;
	pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
	pkt.call_id = p->conn->call_id;
	pkt.auth_length = 0;

	if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
		pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
	}

	if (p->binding->flags & DCERPC_HEADER_SIGNING) {
		pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
	}

	pkt.u.bind.max_xmit_frag = 5840;
	pkt.u.bind.max_recv_frag = 5840;
	pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
	pkt.u.bind.num_contexts = 1;
	pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
	if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
	pkt.u.bind.ctx_list[0].context_id = p->context_id;
	pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
	pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
	pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
	pkt.u.bind.auth_info = data_blob(NULL, 0);

	/* construct the NDR form of the packet */
	c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
				    p->conn->security_state.auth_info);
	if (!composite_is_ok(c)) return c;

	p->conn->transport.recv_data = dcerpc_recv_data;

	/*
	 * we allocate a dcerpc_request so we can be in the same
	 * request queue as normal requests
	 */
	req = talloc_zero(c, struct rpc_request);
	if (composite_nomem(req, c)) return c;

	req->state = RPC_REQUEST_PENDING;
	req->call_id = pkt.call_id;
	req->async.private_data = c;
	req->async.callback = dcerpc_composite_fail;
	req->p = p;
	req->recv_handler = dcerpc_bind_recv_handler;
	DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
	talloc_set_destructor(req, dcerpc_req_dequeue);

	c->status = p->conn->transport.send_request(p->conn, &blob,
						    true);
	if (!composite_is_ok(c)) return c;

	event_add_timed(c->event_ctx, req,
			timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
			dcerpc_timeout_handler, req);

	return c;
}
Example #25
0
/*
 * Test that a ticket obtained for the DNS service will be accepted on the Samba DLZ side
 *
 */
static bool test_dlz_bind9_gensec(struct torture_context *tctx, const char *mech)
{
	NTSTATUS status;

	struct gensec_security *gensec_client_context;

	DATA_BLOB client_to_server, server_to_client;

	void *dbdata;
	const char *argv[] = {
		"samba_dlz",
		"-H",
		lpcfg_private_path(tctx, tctx->lp_ctx, "dns/sam.ldb"),
		NULL
	};
	tctx_static = tctx;
	torture_assert_int_equal(tctx, dlz_create("samba_dlz", 3, argv, &dbdata,
						  "log", dlz_bind9_log_wrapper,
						  "writeable_zone", dlz_bind9_writeable_zone_hook, NULL),
				 ISC_R_SUCCESS,
				 "Failed to create samba_dlz");

	torture_assert_int_equal(tctx, dlz_configure((void*)tctx, dbdata),
						     ISC_R_SUCCESS,
				 "Failed to configure samba_dlz");

	status = gensec_client_start(tctx, &gensec_client_context,
				     lpcfg_gensec_settings(tctx, tctx->lp_ctx));
	torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed");

	/*
	 * dlz_bind9 use the special dns/host.domain account
	 */
	status = gensec_set_target_hostname(gensec_client_context,
					    talloc_asprintf(tctx,
				"%s.%s",
				torture_setting_string(tctx, "host", NULL),
				lpcfg_dnsdomain(tctx->lp_ctx)));
	torture_assert_ntstatus_ok(tctx, status, "gensec_set_target_hostname (client) failed");

	status = gensec_set_target_service(gensec_client_context, "dns");
	torture_assert_ntstatus_ok(tctx, status, "gensec_set_target_service failed");

	status = gensec_set_credentials(gensec_client_context, cmdline_credentials);
	torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed");

	status = gensec_start_mech_by_sasl_name(gensec_client_context, mech);
	torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (client) failed");

	server_to_client = data_blob(NULL, 0);

	/* Do one step of the client-server update dance */
	status = gensec_update(gensec_client_context, tctx, tctx->ev, server_to_client, &client_to_server);
	if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
		torture_assert_ntstatus_ok(tctx, status, "gensec_update (client) failed");
	}

	torture_assert_int_equal(tctx, dlz_ssumatch(cli_credentials_get_username(cmdline_credentials),
						    lpcfg_dnsdomain(tctx->lp_ctx),
						    "127.0.0.1", "type", "key",
						    client_to_server.length,
						    client_to_server.data,
						    dbdata),
				 ISC_TRUE,
				 "Failed to check key for update rights samba_dlz");

	dlz_destroy(dbdata);

	return true;
}
Example #26
0
/* 
   push a dcerpc request packet into a blob, possibly signing it.
*/
static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c, 
					 DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
					 size_t sig_size,
					 struct ncacn_packet *pkt)
{
	NTSTATUS status;
	struct ndr_push *ndr;
	DATA_BLOB creds2;
	size_t payload_length;
	enum ndr_err_code ndr_err;
	size_t hdr_size = DCERPC_REQUEST_LENGTH;

	/* non-signed packets are simpler */
	if (sig_size == 0) {
		return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
	}

	switch (c->security_state.auth_info->auth_level) {
	case DCERPC_AUTH_LEVEL_PRIVACY:
	case DCERPC_AUTH_LEVEL_INTEGRITY:
		break;

	case DCERPC_AUTH_LEVEL_CONNECT:
		/* TODO: let the gensec mech decide if it wants to generate a signature */
		return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);

	case DCERPC_AUTH_LEVEL_NONE:
		return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);

	default:
		return NT_STATUS_INVALID_LEVEL;
	}

	ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
	if (!ndr) {
		return NT_STATUS_NO_MEMORY;
	}

	if (c->flags & DCERPC_PUSH_BIGENDIAN) {
		ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
	}

	if (c->flags & DCERPC_NDR64) {
		ndr->flags |= LIBNDR_FLAG_NDR64;
	}

	if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
		ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
		hdr_size += 16;
	}

	ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		return ndr_map_error2ntstatus(ndr_err);
	}
	status = NT_STATUS_OK;

	/* pad to 16 byte multiple in the payload portion of the
	   packet. This matches what w2k3 does */
	c->security_state.auth_info->auth_pad_length = 
		(16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
	ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		return ndr_map_error2ntstatus(ndr_err);
	}
	status = NT_STATUS_OK;

	payload_length = pkt->u.request.stub_and_verifier.length + 
		c->security_state.auth_info->auth_pad_length;

	/* we start without signature, it will appended later */
	c->security_state.auth_info->credentials = data_blob(NULL,0);

	/* add the auth verifier */
	ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		return ndr_map_error2ntstatus(ndr_err);
	}
	status = NT_STATUS_OK;

	/* extract the whole packet as a blob */
	*blob = ndr_push_blob(ndr);

	/*
	 * Setup the frag and auth length in the packet buffer.
	 * This is needed if the GENSEC mech does AEAD signing
	 * of the packet headers. The signature itself will be
	 * appended later.
	 */
	dcerpc_set_frag_length(blob, blob->length + sig_size);
	dcerpc_set_auth_length(blob, sig_size);

	/* sign or seal the packet */
	switch (c->security_state.auth_info->auth_level) {
	case DCERPC_AUTH_LEVEL_PRIVACY:
		status = gensec_seal_packet(c->security_state.generic_state, 
					    mem_ctx, 
					    blob->data + hdr_size,
					    payload_length,
					    blob->data,
					    blob->length,
					    &creds2);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}
		break;

	case DCERPC_AUTH_LEVEL_INTEGRITY:
		status = gensec_sign_packet(c->security_state.generic_state, 
					    mem_ctx, 
					    blob->data + hdr_size,
					    payload_length, 
					    blob->data,
					    blob->length,
					    &creds2);
		if (!NT_STATUS_IS_OK(status)) {
			return status;
		}
		break;

	default:
		status = NT_STATUS_INVALID_LEVEL;
		break;
	}

	if (creds2.length != sig_size) {
		DEBUG(0,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
			(unsigned) creds2.length,
			(unsigned) sig_size,
			(unsigned) c->security_state.auth_info->auth_pad_length,
			(unsigned) pkt->u.request.stub_and_verifier.length));
		return NT_STATUS_INTERNAL_ERROR;
	}

	if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
		return NT_STATUS_NO_MEMORY;
	}

	return NT_STATUS_OK;
}
Example #27
0
static bool wbinfo_auth_crap(char *username, const char *pass)
{
	wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
	struct wbcAuthUserParams params;
	struct wbcAuthUserInfo *info = NULL;
	struct wbcAuthErrorInfo *err = NULL;
	DATA_BLOB lm = data_blob_null;
	DATA_BLOB nt = data_blob_null;
	fstring name_user;
	fstring name_domain;

	parse_wbinfo_domain_user(username, name_domain, name_user);

	params.account_name	= name_user;
	params.domain_name	= name_domain;
	params.workstation_name	= NULL;

	params.flags		= 0;
	params.parameter_control= WBC_MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT |
				  WBC_MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT;

	params.level		= WBC_AUTH_USER_LEVEL_RESPONSE;

	generate_random_buffer(params.password.response.challenge, 8);

	if (lp_client_ntlmv2_auth()) {
		DATA_BLOB server_chal;
		DATA_BLOB names_blob;

		server_chal = data_blob(params.password.response.challenge, 8);

		/* Pretend this is a login to 'us', for blob purposes */
		names_blob = NTLMv2_generate_names_blob(global_myname(), lp_workgroup());

		if (!SMBNTLMv2encrypt(name_user, name_domain, pass, &server_chal,
				      &names_blob,
				      &lm, &nt, NULL)) {
			data_blob_free(&names_blob);
			data_blob_free(&server_chal);
			return false;
		}
		data_blob_free(&names_blob);
		data_blob_free(&server_chal);

	} else {
		if (lp_client_lanman_auth()) {
			bool ok;
			lm = data_blob(NULL, 24);
			ok = SMBencrypt(pass, params.password.response.challenge,
					lm.data);
			if (!ok) {
				data_blob_free(&lm);
			}
		}
		nt = data_blob(NULL, 24);
		SMBNTencrypt(pass, params.password.response.challenge,
			     nt.data);
	}

	params.password.response.nt_length	= nt.length;
	params.password.response.nt_data	= nt.data;
	params.password.response.lm_length	= lm.length;
	params.password.response.lm_data	= lm.data;

	wbc_status = wbcAuthenticateUserEx(&params, &info, &err);

	/* Display response */

	d_printf("challenge/response password authentication %s\n",
		 WBC_ERROR_IS_OK(wbc_status) ? "succeeded" : "failed");

	if (wbc_status == WBC_ERR_AUTH_ERROR) {
		d_fprintf(stderr, "error code was %s (0x%x)\nerror messsage was: %s\n", 
			 err->nt_string,
			 err->nt_status,
			 err->display_string);
		wbcFreeMemory(err);
	} else if (WBC_ERROR_IS_OK(wbc_status)) {
		wbcFreeMemory(info);
	}

	data_blob_free(&nt);
	data_blob_free(&lm);

	return WBC_ERROR_IS_OK(wbc_status);
}
Example #28
0
/*
  handler for completion of a smbcli_request sub-request
*/
static void request_handler(struct smbcli_request *req)
{
	struct composite_context *c = (struct composite_context *)req->async.private_data;
	struct sesssetup_state *state = talloc_get_type(c->private_data, struct sesssetup_state);
	struct smbcli_session *session = req->session;
	DATA_BLOB null_data_blob = data_blob(NULL, 0);
	NTSTATUS session_key_err, nt_status;
	struct smbcli_request *check_req = NULL;
	const char *os = NULL;
	const char *lanman = NULL;

	if (req->sign_caller_checks) {
		req->do_not_free = true;
		check_req = req;
	}

	state->remote_status = smb_raw_sesssetup_recv(req, state, &state->setup);
	c->status = state->remote_status;
	state->req = NULL;

	/*
	 * we only need to check the signature if the
	 * NT_STATUS_OK is returned
	 */
	if (!NT_STATUS_IS_OK(state->remote_status)) {
		talloc_free(check_req);
		check_req = NULL;
	}

	switch (state->setup.old.level) {
	case RAW_SESSSETUP_OLD:
		state->io->out.vuid = state->setup.old.out.vuid;
		/* This doesn't work, as this only happens on old
		 * protocols, where this comparison won't match. */
		if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
			/* we neet to reset the vuid for a new try */
			session->vuid = 0;
			if (cli_credentials_wrong_password(state->io->in.credentials)) {
				nt_status = session_setup_old(c, session, 
							      state->io, 
							      &state->req);
				if (NT_STATUS_IS_OK(nt_status)) {
					talloc_free(check_req);
					c->status = nt_status;
					composite_continue_smb(c, state->req, request_handler, c);
					return;
				}
			}
		}
		os = state->setup.old.out.os;
		lanman = state->setup.old.out.lanman;
		break;

	case RAW_SESSSETUP_NT1:
		state->io->out.vuid = state->setup.nt1.out.vuid;
		if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
			/* we need to reset the vuid for a new try */
			session->vuid = 0;
			if (cli_credentials_wrong_password(state->io->in.credentials)) {
				nt_status = session_setup_nt1(c, session, 
							      state->io, 
							      &state->req);
				if (NT_STATUS_IS_OK(nt_status)) {
					talloc_free(check_req);
					c->status = nt_status;
					composite_continue_smb(c, state->req, request_handler, c);
					return;
				}
			}
		}
		os = state->setup.nt1.out.os;
		lanman = state->setup.nt1.out.lanman;
		break;

	case RAW_SESSSETUP_SPNEGO:
		state->io->out.vuid = state->setup.spnego.out.vuid;
		if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
			const char *principal;

			/* we need to reset the vuid for a new try */
			session->vuid = 0;

			principal = gensec_get_target_principal(session->gensec);
			if (principal == NULL) {
				const char *hostname = gensec_get_target_hostname(session->gensec);
				const char *service  = gensec_get_target_service(session->gensec);
				if (hostname != NULL && service != NULL) {
					principal = talloc_asprintf(state, "%s/%s", service, hostname);
				}
			}
			if (cli_credentials_failed_kerberos_login(state->io->in.credentials, principal, &state->logon_retries) ||
			    cli_credentials_wrong_password(state->io->in.credentials)) {
				nt_status = session_setup_spnego(c, session, 
								      state->io, 
								      &state->req);
				if (NT_STATUS_IS_OK(nt_status)) {
					talloc_free(check_req);
					c->status = nt_status;
					composite_continue_smb(c, state->req, request_handler, c);
					return;
				}
			}
		}
		if (!NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED) && 
		    !NT_STATUS_IS_OK(c->status)) {
			break;
		}
		if (NT_STATUS_EQUAL(state->gensec_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {

			/* The status value here, from the earlier pass at GENSEC is
			 * vital to the security of the system.  Even if the other end
			 * accepts, if GENSEC claims 'MORE_PROCESSING_REQUIRED' then
			 * you must keep feeding it blobs, or else the remote
			 * host/attacker might avoid mutal authentication
			 * requirements */
			
			state->gensec_status = gensec_update(session->gensec, state, c->event_ctx,
							 state->setup.spnego.out.secblob,
							 &state->setup.spnego.in.secblob);
			c->status = state->gensec_status;
			if (!NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED) && 
			    !NT_STATUS_IS_OK(c->status)) {
				break;
			}
		} else {
			state->setup.spnego.in.secblob = data_blob(NULL, 0);
		}

		if (NT_STATUS_IS_OK(state->remote_status)) {
			DATA_BLOB session_key;

			if (state->setup.spnego.in.secblob.length) {
				c->status = NT_STATUS_INTERNAL_ERROR;
				break;
			}
			session_key_err = gensec_session_key(session->gensec, session, &session_key);
			if (NT_STATUS_IS_OK(session_key_err)) {
				smb1cli_conn_activate_signing(session->transport->conn,
							      session_key,
							      null_data_blob);
			}

			c->status = smb1cli_session_set_session_key(session->smbXcli,
								    session_key);
			data_blob_free(&session_key);
			if (!NT_STATUS_IS_OK(c->status)) {
				break;
			}
		}

		if (state->setup.spnego.in.secblob.length) {
			/* 
			 * set the session->vuid value only for calling
			 * smb_raw_sesssetup_send()
			 */
			uint16_t vuid = session->vuid;
			session->vuid = state->io->out.vuid;
			state->req = smb_raw_sesssetup_send(session, &state->setup);
			session->vuid = vuid;
			if (state->req &&
			    !smb1cli_conn_signing_is_active(state->req->transport->conn)) {
				state->req->sign_caller_checks = true;
			}
			composite_continue_smb(c, state->req, request_handler, c);
			return;
		}
		os = state->setup.spnego.out.os;
		lanman = state->setup.spnego.out.lanman;
		break;

	case RAW_SESSSETUP_SMB2:
		c->status = NT_STATUS_INTERNAL_ERROR;
		break;
	}

	if (check_req) {
		bool ok;

		check_req->sign_caller_checks = false;

		ok = smb1cli_conn_check_signing(check_req->transport->conn,
						check_req->in.buffer, 1);
		if (!ok) {
			c->status = NT_STATUS_ACCESS_DENIED;
		}
		talloc_free(check_req);
		check_req = NULL;
	}

	if (!NT_STATUS_IS_OK(c->status)) {
		composite_error(c, c->status);
		return;
	}

	if (os) {
		session->os = talloc_strdup(session, os);
		if (composite_nomem(session->os, c)) return;
	} else {
		session->os = NULL;
	}
	if (lanman) {
		session->lanman = talloc_strdup(session, lanman);
		if (composite_nomem(session->lanman, c)) return;
	} else {
		session->lanman = NULL;
	}

	composite_done(c);
}
Example #29
0
/*
  Modern, all singing, all dancing extended security (and possibly SPNEGO) request
*/
static NTSTATUS session_setup_spnego(struct composite_context *c,
				     struct smbcli_session *session, 
				     struct smb_composite_sesssetup *io,
				     struct smbcli_request **req) 
{
	struct sesssetup_state *state = talloc_get_type(c->private_data, struct sesssetup_state);
	NTSTATUS status;
	const char *chosen_oid = NULL;

	state->setup.spnego.level           = RAW_SESSSETUP_SPNEGO;
	state->setup.spnego.in.bufsize      = session->transport->options.max_xmit;
	state->setup.spnego.in.mpx_max      = session->transport->options.max_mux;
	state->setup.spnego.in.vc_num       = 1;
	state->setup.spnego.in.sesskey      = io->in.sesskey;
	state->setup.spnego.in.capabilities = io->in.capabilities;
	state->setup.spnego.in.os           = "Unix";
	state->setup.spnego.in.lanman       = talloc_asprintf(state, "Samba %s", SAMBA_VERSION_STRING);
	state->setup.spnego.in.workgroup    = io->in.workgroup;

	status = gensec_client_start(session, &session->gensec,
				     io->in.gensec_settings);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Failed to start GENSEC client mode: %s\n", nt_errstr(status)));
		return status;
	}

	gensec_want_feature(session->gensec, GENSEC_FEATURE_SESSION_KEY);

	status = gensec_set_credentials(session->gensec, io->in.credentials);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Failed to start set GENSEC client credentials: %s\n", 
			  nt_errstr(status)));
		return status;
	}

	status = gensec_set_target_hostname(session->gensec,
			smbXcli_conn_remote_name(session->transport->conn));
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n", 
			  nt_errstr(status)));
		return status;
	}

	status = gensec_set_target_service(session->gensec, "cifs");
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Failed to start set GENSEC target service: %s\n", 
			  nt_errstr(status)));
		return status;
	}

	if (session->transport->negotiate.secblob.length) {
		chosen_oid = GENSEC_OID_SPNEGO;
		status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(1, ("Failed to start set GENSEC client mechanism %s: %s\n",
				  gensec_get_name_by_oid(session->gensec, chosen_oid), nt_errstr(status)));
			chosen_oid = GENSEC_OID_NTLMSSP;
			status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
			if (!NT_STATUS_IS_OK(status)) {
				DEBUG(1, ("Failed to start set (fallback) GENSEC client mechanism %s: %s\n",
					  gensec_get_name_by_oid(session->gensec, chosen_oid), 
					  nt_errstr(status)));
			return status;
			}
		}
	} else {
		/* without a sec blob, means raw NTLMSSP */
		chosen_oid = GENSEC_OID_NTLMSSP;
		status = gensec_start_mech_by_oid(session->gensec, chosen_oid);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(1, ("Failed to start set GENSEC client mechanism %s: %s\n",
				  gensec_get_name_by_oid(session->gensec, chosen_oid), nt_errstr(status)));
		}
	}

	if (strequal(chosen_oid, GENSEC_OID_SPNEGO)) {
		status = gensec_update(session->gensec, state,
				       c->event_ctx,
				       session->transport->negotiate.secblob,
				       &state->setup.spnego.in.secblob);
	} else {
		status = gensec_update(session->gensec, state,
				       c->event_ctx,
				       data_blob(NULL, 0),
				       &state->setup.spnego.in.secblob);

	}

	if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && 
	    !NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Failed initial gensec_update with mechanism %s: %s\n",
			  gensec_get_name_by_oid(session->gensec, chosen_oid), 
			  nt_errstr(status)));
		return status;
	}
	state->gensec_status = status;

	*req = smb_raw_sesssetup_send(session, &state->setup);
	if (!*req) {
		return NT_STATUS_NO_MEMORY;
	}

	/*
	 * we need to check the signature ourself
	 * as the session key might be the acceptor subkey
	 * which comes within the response itself
	 */
	if (!smb1cli_conn_signing_is_active((*req)->transport->conn)) {
		(*req)->sign_caller_checks = true;
	}

	return (*req)->status;
}
Example #30
-1
/*
  send a nt1 style session setup
*/
static NTSTATUS session_setup_nt1(struct composite_context *c,
				  struct smbcli_session *session, 
				  struct smb_composite_sesssetup *io,
				  struct smbcli_request **req) 
{
	NTSTATUS nt_status = NT_STATUS_INTERNAL_ERROR;
	struct sesssetup_state *state = talloc_get_type(c->private_data,
							struct sesssetup_state);
	const char *domain = cli_credentials_get_domain(io->in.credentials);

	/*
	 * domain controllers tend to reject the NTLM v2 blob
	 * if the netbiosname is not valid (e.g. IP address or FQDN)
	 * so just leave it away (as Windows client do)
	 */
	DATA_BLOB names_blob = NTLMv2_generate_names_blob(state, NULL, domain);

	DATA_BLOB session_key = data_blob(NULL, 0);
	int flags = CLI_CRED_NTLM_AUTH;

	if (session->options.lanman_auth) {
		flags |= CLI_CRED_LANMAN_AUTH;
	}

	if (session->options.ntlmv2_auth) {
		flags |= CLI_CRED_NTLMv2_AUTH;
	}

	state->setup.nt1.level           = RAW_SESSSETUP_NT1;
	state->setup.nt1.in.bufsize      = session->transport->options.max_xmit;
	state->setup.nt1.in.mpx_max      = session->transport->options.max_mux;
	state->setup.nt1.in.vc_num       = 1;
	state->setup.nt1.in.sesskey      = io->in.sesskey;
	state->setup.nt1.in.capabilities = io->in.capabilities;
	state->setup.nt1.in.os           = "Unix";
	state->setup.nt1.in.lanman       = talloc_asprintf(state, "Samba %s", SAMBA_VERSION_STRING);

	cli_credentials_get_ntlm_username_domain(io->in.credentials, state, 
						 &state->setup.nt1.in.user,
						 &state->setup.nt1.in.domain);
	

	if (session->transport->negotiate.sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) {
		nt_status = cli_credentials_get_ntlm_response(io->in.credentials, state, 
							      &flags, 
							      session->transport->negotiate.secblob, 
							      names_blob,
							      &state->setup.nt1.in.password1,
							      &state->setup.nt1.in.password2,
							      NULL, &session_key);
		NT_STATUS_NOT_OK_RETURN(nt_status);
	} else if (session->options.plaintext_auth) {
		const char *password = cli_credentials_get_password(io->in.credentials);
		state->setup.nt1.in.password1 = data_blob_talloc(state, password, strlen(password));
		state->setup.nt1.in.password2 = data_blob(NULL, 0);
	} else {
		/* could match windows client and return 'cannot logon from this workstation', but it just confuses everybody */
		return NT_STATUS_INVALID_PARAMETER;
	}

	*req = smb_raw_sesssetup_send(session, &state->setup);
	if (!*req) {
		return NT_STATUS_NO_MEMORY;
	}

	if (NT_STATUS_IS_OK(nt_status)) {
		smb1cli_conn_activate_signing(session->transport->conn,
					      session_key,
					      state->setup.nt1.in.password2);

		nt_status = smb1cli_session_set_session_key(session->smbXcli,
							    session_key);
		data_blob_free(&session_key);
		if (!NT_STATUS_IS_OK(nt_status)) {
			return nt_status;
		}
	}

	return (*req)->status;
}