Esempio n. 1
0
File: cgi.c Progetto: gojdic/samba
/***************************************************************************
  load all the variables passed to the CGI program. May have multiple variables
  with the same name and the same or different values. Takes a file parameter
  for simulating CGI invocation eg loading saved preferences.
  ***************************************************************************/
void cgi_load_variables(void)
{
	static char *line;
	char *p, *s, *tok;
	int len, i;
	FILE *f = stdin;

#ifdef DEBUG_COMMENTS
	char dummy[100]="";
	print_title(dummy);
	d_printf("<!== Start dump in cgi_load_variables() %s ==>\n",__FILE__);
#endif

	if (!content_length) {
		p = getenv("CONTENT_LENGTH");
		len = p?atoi(p):0;
	} else {
		len = content_length;
	}


	if (len > 0 && 
	    (request_post ||
	     ((s=getenv("REQUEST_METHOD")) && 
	      strequal(s,"POST")))) {
		while (len && (line=grab_line(f, &len))) {
			p = strchr_m(line,'=');
			if (!p) continue;
			
			*p = 0;
			
			variables[num_variables].name = SMB_STRDUP(line);
			variables[num_variables].value = SMB_STRDUP(p+1);

			SAFE_FREE(line);
			
			if (!variables[num_variables].name || 
			    !variables[num_variables].value)
				continue;

			plus_to_space_unescape(variables[num_variables].value);
			rfc1738_unescape(variables[num_variables].value);
			plus_to_space_unescape(variables[num_variables].name);
			rfc1738_unescape(variables[num_variables].name);

#ifdef DEBUG_COMMENTS
			printf("<!== POST var %s has value \"%s\"  ==>\n",
			       variables[num_variables].name,
			       variables[num_variables].value);
#endif
			
			num_variables++;
			if (num_variables == MAX_VARIABLES) break;
		}
	}

	fclose(stdin);
	open("/dev/null", O_RDWR);

	if ((s=query_string) || (s=getenv("QUERY_STRING"))) {
		char *saveptr;
		for (tok=strtok_r(s, "&;", &saveptr); tok;
		     tok=strtok_r(NULL, "&;", &saveptr)) {
			p = strchr_m(tok,'=');
			if (!p) continue;
			
			*p = 0;
			
			variables[num_variables].name = SMB_STRDUP(tok);
			variables[num_variables].value = SMB_STRDUP(p+1);

			if (!variables[num_variables].name ||
			    !variables[num_variables].value)
				continue;

			plus_to_space_unescape(variables[num_variables].value);
			rfc1738_unescape(variables[num_variables].value);
			plus_to_space_unescape(variables[num_variables].name);
			rfc1738_unescape(variables[num_variables].name);

#ifdef DEBUG_COMMENTS
                        printf("<!== Commandline var %s has value \"%s\"  ==>\n",
                               variables[num_variables].name,
                               variables[num_variables].value);
#endif
			num_variables++;
			if (num_variables == MAX_VARIABLES) break;
		}

	}
#ifdef DEBUG_COMMENTS
        printf("<!== End dump in cgi_load_variables() ==>\n");
#endif

	/* variables from the client are in UTF-8 - convert them
	   to our internal unix charset before use */
	for (i=0;i<num_variables;i++) {
		TALLOC_CTX *frame = talloc_stackframe();
		char *dest = NULL;
		size_t dest_len;

		convert_string_talloc(frame, CH_UTF8, CH_UNIX,
			       variables[i].name, strlen(variables[i].name),
			       &dest, &dest_len, True);
		SAFE_FREE(variables[i].name);
		variables[i].name = SMB_STRDUP(dest ? dest : "");

		dest = NULL;
		convert_string_talloc(frame, CH_UTF8, CH_UNIX,
			       variables[i].value, strlen(variables[i].value),
			       &dest, &dest_len, True);
		SAFE_FREE(variables[i].value);
		variables[i].value = SMB_STRDUP(dest ? dest : "");
		TALLOC_FREE(frame);
	}
}
Esempio n. 2
0
NTSTATUS smbd_smb2_request_process_create(struct smbd_smb2_request *smb2req)
{
	const uint8_t *inbody;
	const struct iovec *indyniov;
	uint8_t in_oplock_level;
	uint32_t in_impersonation_level;
	uint32_t in_desired_access;
	uint32_t in_file_attributes;
	uint32_t in_share_access;
	uint32_t in_create_disposition;
	uint32_t in_create_options;
	uint16_t in_name_offset;
	uint16_t in_name_length;
	DATA_BLOB in_name_buffer;
	char *in_name_string;
	size_t in_name_string_size;
	uint32_t name_offset = 0;
	uint32_t name_available_length = 0;
	uint32_t in_context_offset;
	uint32_t in_context_length;
	DATA_BLOB in_context_buffer;
	struct smb2_create_blobs in_context_blobs;
	uint32_t context_offset = 0;
	uint32_t context_available_length = 0;
	uint32_t dyn_offset;
	NTSTATUS status;
	bool ok;
	struct tevent_req *tsubreq;

	status = smbd_smb2_request_verify_sizes(smb2req, 0x39);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(smb2req, status);
	}
	inbody = SMBD_SMB2_IN_BODY_PTR(smb2req);

	in_oplock_level		= CVAL(inbody, 0x03);
	in_impersonation_level	= IVAL(inbody, 0x04);
	in_desired_access	= IVAL(inbody, 0x18);
	in_file_attributes	= IVAL(inbody, 0x1C);
	in_share_access		= IVAL(inbody, 0x20);
	in_create_disposition	= IVAL(inbody, 0x24);
	in_create_options	= IVAL(inbody, 0x28);
	in_name_offset		= SVAL(inbody, 0x2C);
	in_name_length		= SVAL(inbody, 0x2E);
	in_context_offset	= IVAL(inbody, 0x30);
	in_context_length	= IVAL(inbody, 0x34);

	/*
	 * First check if the dynamic name and context buffers
	 * are correctly specified.
	 *
	 * Note: That we don't check if the name and context buffers
	 *       overlap
	 */

	dyn_offset = SMB2_HDR_BODY + SMBD_SMB2_IN_BODY_LEN(smb2req);

	if (in_name_offset == 0 && in_name_length == 0) {
		/* This is ok */
		name_offset = 0;
	} else if (in_name_offset < dyn_offset) {
		return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
	} else {
		name_offset = in_name_offset - dyn_offset;
	}

	indyniov = SMBD_SMB2_IN_DYN_IOV(smb2req);

	if (name_offset > indyniov->iov_len) {
		return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
	}

	name_available_length = indyniov->iov_len - name_offset;

	if (in_name_length > name_available_length) {
		return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
	}

	in_name_buffer.data = (uint8_t *)indyniov->iov_base + name_offset;
	in_name_buffer.length = in_name_length;

	if (in_context_offset == 0 && in_context_length == 0) {
		/* This is ok */
		context_offset = 0;
	} else if (in_context_offset < dyn_offset) {
		return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
	} else {
		context_offset = in_context_offset - dyn_offset;
	}

	if (context_offset > indyniov->iov_len) {
		return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
	}

	context_available_length = indyniov->iov_len - context_offset;

	if (in_context_length > context_available_length) {
		return smbd_smb2_request_error(smb2req, NT_STATUS_INVALID_PARAMETER);
	}

	in_context_buffer.data = (uint8_t *)indyniov->iov_base +
		context_offset;
	in_context_buffer.length = in_context_length;

	/*
	 * Now interpret the name and context buffers
	 */

	ok = convert_string_talloc(smb2req, CH_UTF16, CH_UNIX,
				   in_name_buffer.data,
				   in_name_buffer.length,
				   &in_name_string,
				   &in_name_string_size);
	if (!ok) {
		return smbd_smb2_request_error(smb2req, NT_STATUS_ILLEGAL_CHARACTER);
	}

	if (in_name_buffer.length == 0) {
		in_name_string_size = 0;
	}

	if (strlen(in_name_string) != in_name_string_size) {
		return smbd_smb2_request_error(smb2req, NT_STATUS_OBJECT_NAME_INVALID);
	}

	ZERO_STRUCT(in_context_blobs);
	status = smb2_create_blob_parse(smb2req, in_context_buffer, &in_context_blobs);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(smb2req, status);
	}

	tsubreq = smbd_smb2_create_send(smb2req,
				       smb2req->sconn->ev_ctx,
				       smb2req,
				       in_oplock_level,
				       in_impersonation_level,
				       in_desired_access,
				       in_file_attributes,
				       in_share_access,
				       in_create_disposition,
				       in_create_options,
				       in_name_string,
				       in_context_blobs);
	if (tsubreq == NULL) {
		smb2req->subreq = NULL;
		return smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
	}
	tevent_req_set_callback(tsubreq, smbd_smb2_request_create_done, smb2req);

	/*
	 * For now we keep the logic that we do not send STATUS_PENDING
	 * for sharing violations, so we just wait 2 seconds.
	 *
	 * TODO: we need more tests for this.
	 */
	return smbd_smb2_request_pending_queue(smb2req, tsubreq, 2000000);
}
Esempio n. 3
0
struct tevent_req *smb1cli_trans_send(
	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
	struct smbXcli_conn *conn, uint8_t cmd,
	uint8_t additional_flags, uint8_t clear_flags,
	uint16_t additional_flags2, uint16_t clear_flags2,
	uint32_t timeout_msec,
	uint32_t pid,
	struct smbXcli_tcon *tcon,
	struct smbXcli_session *session,
	const char *pipe_name, uint16_t fid, uint16_t function, int flags,
	uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
	uint8_t *param, uint32_t num_param, uint32_t max_param,
	uint8_t *data, uint32_t num_data, uint32_t max_data)
{
	struct tevent_req *req, *subreq;
	struct smb1cli_trans_state *state;
	int iov_count;
	uint8_t wct;
	NTSTATUS status;
	charset_t charset;

	req = tevent_req_create(mem_ctx, &state,
				struct smb1cli_trans_state);
	if (req == NULL) {
		return NULL;
	}

	if ((cmd == SMBtrans) || (cmd == SMBtrans2)) {
		if ((num_param > 0xffff) || (max_param > 0xffff)
		    || (num_data > 0xffff) || (max_data > 0xffff)) {
			DEBUG(3, ("Attempt to send invalid trans2 request "
				  "(setup %u, params %u/%u, data %u/%u)\n",
				  (unsigned)num_setup,
				  (unsigned)num_param, (unsigned)max_param,
				  (unsigned)num_data, (unsigned)max_data));
			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
			return tevent_req_post(req, ev);
		}
	}

	/*
	 * The largest wct will be for nttrans (19+num_setup). Make sure we
	 * don't overflow state->vwv in smb1cli_trans_format.
	 */

	if ((num_setup + 19) > ARRAY_SIZE(state->vwv)) {
		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
		return tevent_req_post(req, ev);
	}

	state->conn = conn;
	state->ev = ev;
	state->cmd = cmd;
	state->additional_flags = additional_flags;
	state->clear_flags = clear_flags;
	state->additional_flags2 = additional_flags2;
	state->clear_flags2 = clear_flags2;
	state->timeout_msec = timeout_msec;
	state->flags = flags;
	state->num_rsetup = 0;
	state->rsetup = NULL;
	state->pid = pid;
	state->tcon = tcon;
	state->session = session;
	ZERO_STRUCT(state->rparam);
	ZERO_STRUCT(state->rdata);

	if (smbXcli_conn_use_unicode(conn)) {
		charset = CH_UTF16LE;
	} else {
		charset = CH_DOS;
	}

	if ((pipe_name != NULL)
	    && (!convert_string_talloc(state, CH_UNIX, charset,
				       pipe_name, strlen(pipe_name) + 1,
				       &state->pipe_name_conv,
				       &state->pipe_name_conv_len))) {
		tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
		return tevent_req_post(req, ev);
	}
	state->fid = fid;	/* trans2 */
	state->function = function; /* nttrans */

	state->setup = setup;
	state->num_setup = num_setup;
	state->max_setup = max_setup;

	state->param = param;
	state->num_param = num_param;
	state->param_sent = 0;
	state->rparam.max = max_param;

	state->data = data;
	state->num_data = num_data;
	state->data_sent = 0;
	state->rdata.max = max_data;

	smb1cli_trans_format(state, &wct, &iov_count);

	subreq = smb1cli_req_create(state, ev, conn, cmd,
				    state->additional_flags,
				    state->clear_flags,
				    state->additional_flags2,
				    state->clear_flags2,
				    state->timeout_msec,
				    state->pid,
				    state->tcon,
				    state->session,
				    wct, state->vwv,
				    iov_count, state->iov);
	if (tevent_req_nomem(subreq, req)) {
		return tevent_req_post(req, ev);
	}
	status = smb1cli_req_chain_submit(&subreq, 1);
	if (tevent_req_nterror(req, status)) {
		return tevent_req_post(req, state->ev);
	}
	tevent_req_set_callback(subreq, smb1cli_trans_done, req);

	/*
	 * Now get the MID of the primary request
	 * and mark it as persistent. This means
	 * we will able to send and receive multiple
	 * SMB pdus using this MID in both directions
	 * (including correct SMB signing).
	 */
	state->mid = smb1cli_req_mid(subreq);
	smb1cli_req_set_mid(subreq, state->mid);
	state->primary_subreq = subreq;
	talloc_set_destructor(state, smb1cli_trans_state_destructor);

	tevent_req_set_cancel_fn(req, smb1cli_trans_cancel);

	return req;
}
Esempio n. 4
0
NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx,
                             bool lanman_auth,
                             bool ntlm_auth,
                             uint32_t logon_parameters,
                             const DATA_BLOB *challenge,
                             const DATA_BLOB *lm_response,
                             const DATA_BLOB *nt_response,
                             const char *username,
                             const char *client_username,
                             const char *client_domain,
                             const struct samr_Password *stored_lanman,
                             const struct samr_Password *stored_nt,
                             DATA_BLOB *user_sess_key,
                             DATA_BLOB *lm_sess_key)
{
    const static uint8_t zeros[8];
    DATA_BLOB tmp_sess_key;

    if (stored_nt == NULL) {
        DEBUG(3,("ntlm_password_check: NO NT password stored for user %s.\n",
                 username));
    }

    *lm_sess_key = data_blob(NULL, 0);
    *user_sess_key = data_blob(NULL, 0);

    /* Check for cleartext netlogon. Used by Exchange 5.5. */
    if ((logon_parameters & MSV1_0_CLEARTEXT_PASSWORD_ALLOWED)
            && challenge->length == sizeof(zeros)
            && (memcmp(challenge->data, zeros, challenge->length) == 0 )) {
        struct samr_Password client_nt;
        struct samr_Password client_lm;
        char *unix_pw = NULL;
        bool lm_ok;

        DEBUG(4,("ntlm_password_check: checking plaintext passwords for user %s\n",
                 username));
        mdfour(client_nt.hash, nt_response->data, nt_response->length);

        if (lm_response->length &&
                (convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX,
                                       lm_response->data, lm_response->length,
                                       (void **)&unix_pw, NULL, false))) {
            if (E_deshash(unix_pw, client_lm.hash)) {
                lm_ok = true;
            } else {
                lm_ok = false;
            }
        } else {
            lm_ok = false;
        }
        return hash_password_check(mem_ctx,
                                   lanman_auth,
                                   lm_ok ? &client_lm : NULL,
                                   nt_response->length ? &client_nt : NULL,
                                   username,
                                   stored_lanman, stored_nt);
    }

    if (nt_response->length != 0 && nt_response->length < 24) {
        DEBUG(2,("ntlm_password_check: invalid NT password length (%lu) for user %s\n",
                 (unsigned long)nt_response->length, username));
    }

    if (nt_response->length > 24 && stored_nt) {
        /* We have the NT MD4 hash challenge available - see if we can
           use it
        */
        DEBUG(4,("ntlm_password_check: Checking NTLMv2 password with domain [%s]\n", client_domain));
        if (smb_pwd_check_ntlmv2(mem_ctx,
                                 nt_response,
                                 stored_nt->hash, challenge,
                                 client_username,
                                 client_domain,
                                 false,
                                 user_sess_key)) {
            if (user_sess_key->length) {
                *lm_sess_key = data_blob_talloc(mem_ctx, user_sess_key->data, MIN(8, user_sess_key->length));
            }
            return NT_STATUS_OK;
        }

        DEBUG(4,("ntlm_password_check: Checking NTLMv2 password with uppercased version of domain [%s]\n", client_domain));
        if (smb_pwd_check_ntlmv2(mem_ctx,
                                 nt_response,
                                 stored_nt->hash, challenge,
                                 client_username,
                                 client_domain,
                                 true,
                                 user_sess_key)) {
            if (user_sess_key->length) {
                *lm_sess_key = data_blob_talloc(mem_ctx, user_sess_key->data, MIN(8, user_sess_key->length));
            }
            return NT_STATUS_OK;
        }

        DEBUG(4,("ntlm_password_check: Checking NTLMv2 password without a domain\n"));
        if (smb_pwd_check_ntlmv2(mem_ctx,
                                 nt_response,
                                 stored_nt->hash, challenge,
                                 client_username,
                                 "",
                                 false,
                                 user_sess_key)) {
            if (user_sess_key->length) {
                *lm_sess_key = data_blob_talloc(mem_ctx, user_sess_key->data, MIN(8, user_sess_key->length));
            }
            return NT_STATUS_OK;
        } else {
            DEBUG(3,("ntlm_password_check: NTLMv2 password check failed\n"));
        }
    } else if (nt_response->length == 24 && stored_nt) {
        if (ntlm_auth) {
            /* We have the NT MD4 hash challenge available - see if we can
               use it (ie. does it exist in the smbpasswd file).
            */
            DEBUG(4,("ntlm_password_check: Checking NT MD4 password\n"));
            if (smb_pwd_check_ntlmv1(mem_ctx,
                                     nt_response,
                                     stored_nt->hash, challenge,
                                     user_sess_key)) {
                /* The LM session key for this response is not very secure,
                   so use it only if we otherwise allow LM authentication */

                if (lanman_auth && stored_lanman) {
                    *lm_sess_key = data_blob_talloc(mem_ctx, stored_lanman->hash, MIN(8, user_sess_key->length));
                }
                return NT_STATUS_OK;
            } else {
                DEBUG(3,("ntlm_password_check: NT MD4 password check failed for user %s\n",
                         username));
                return NT_STATUS_WRONG_PASSWORD;
            }
        } else {
            DEBUG(2,("ntlm_password_check: NTLMv1 passwords NOT PERMITTED for user %s\n",
                     username));
            /* no return, becouse we might pick up LMv2 in the LM field */
        }
    }

    if (lm_response->length == 0) {
        DEBUG(3,("ntlm_password_check: NEITHER LanMan nor NT password supplied for user %s\n",
                 username));
        return NT_STATUS_WRONG_PASSWORD;
    }

    if (lm_response->length < 24) {
        DEBUG(2,("ntlm_password_check: invalid LanMan password length (%lu) for user %s\n",
                 (unsigned long)nt_response->length, username));
        return NT_STATUS_WRONG_PASSWORD;
    }

    if (!lanman_auth) {
        DEBUG(3,("ntlm_password_check: Lanman passwords NOT PERMITTED for user %s\n",
                 username));
    } else if (!stored_lanman) {
        DEBUG(3,("ntlm_password_check: NO LanMan password set for user %s (and no NT password supplied)\n",
                 username));
    } else if (strchr_m(username, '@')) {
        DEBUG(3,("ntlm_password_check: NO LanMan password allowed for username@realm logins (user: %s)\n",
                 username));
    } else {
        DEBUG(4,("ntlm_password_check: Checking LM password\n"));
        if (smb_pwd_check_ntlmv1(mem_ctx,
                                 lm_response,
                                 stored_lanman->hash, challenge,
                                 NULL)) {
            /* The session key for this response is still very odd.
               It not very secure, so use it only if we otherwise
               allow LM authentication */

            if (lanman_auth && stored_lanman) {
                uint8_t first_8_lm_hash[16];
                memcpy(first_8_lm_hash, stored_lanman->hash, 8);
                memset(first_8_lm_hash + 8, '\0', 8);
                *user_sess_key = data_blob_talloc(mem_ctx, first_8_lm_hash, 16);
                *lm_sess_key = data_blob_talloc(mem_ctx, stored_lanman->hash, 8);
            }
            return NT_STATUS_OK;
        }
    }

    if (!stored_nt) {
        DEBUG(4,("ntlm_password_check: LM password check failed for user, no NT password %s\n",username));
        return NT_STATUS_WRONG_PASSWORD;
    }

    /* This is for 'LMv2' authentication.  almost NTLMv2 but limited to 24 bytes.
       - related to Win9X, legacy NAS pass-though authentication
    */
    DEBUG(4,("ntlm_password_check: Checking LMv2 password with domain %s\n", client_domain));
    if (smb_pwd_check_ntlmv2(mem_ctx,
                             lm_response,
                             stored_nt->hash, challenge,
                             client_username,
                             client_domain,
                             false,
                             &tmp_sess_key)) {
        if (nt_response->length > 24) {
            /* If NTLMv2 authentication has preceeded us
             * (even if it failed), then use the session
             * key from that.  See the RPC-SAMLOGON
             * torture test */
            smb_sess_key_ntlmv2(mem_ctx,
                                nt_response,
                                stored_nt->hash, challenge,
                                client_username,
                                client_domain,
                                false,
                                user_sess_key);
        } else {
            /* Otherwise, use the LMv2 session key */
            *user_sess_key = tmp_sess_key;
        }
        if (user_sess_key->length) {
            *lm_sess_key = data_blob_talloc(mem_ctx, user_sess_key->data, MIN(8, user_sess_key->length));
        }
        return NT_STATUS_OK;
    }

    DEBUG(4,("ntlm_password_check: Checking LMv2 password with upper-cased version of domain %s\n", client_domain));
    if (smb_pwd_check_ntlmv2(mem_ctx,
                             lm_response,
                             stored_nt->hash, challenge,
                             client_username,
                             client_domain,
                             true,
                             &tmp_sess_key)) {
        if (nt_response->length > 24) {
            /* If NTLMv2 authentication has preceeded us
             * (even if it failed), then use the session
             * key from that.  See the RPC-SAMLOGON
             * torture test */
            smb_sess_key_ntlmv2(mem_ctx,
                                nt_response,
                                stored_nt->hash, challenge,
                                client_username,
                                client_domain,
                                true,
                                user_sess_key);
        } else {
            /* Otherwise, use the LMv2 session key */
            *user_sess_key = tmp_sess_key;
        }
        if (user_sess_key->length) {
            *lm_sess_key = data_blob_talloc(mem_ctx, user_sess_key->data, MIN(8, user_sess_key->length));
        }
        return NT_STATUS_OK;
    }

    DEBUG(4,("ntlm_password_check: Checking LMv2 password without a domain\n"));
    if (smb_pwd_check_ntlmv2(mem_ctx,
                             lm_response,
                             stored_nt->hash, challenge,
                             client_username,
                             "",
                             false,
                             &tmp_sess_key)) {
        if (nt_response->length > 24) {
            /* If NTLMv2 authentication has preceeded us
             * (even if it failed), then use the session
             * key from that.  See the RPC-SAMLOGON
             * torture test */
            smb_sess_key_ntlmv2(mem_ctx,
                                nt_response,
                                stored_nt->hash, challenge,
                                client_username,
                                "",
                                false,
                                user_sess_key);
        } else {
            /* Otherwise, use the LMv2 session key */
            *user_sess_key = tmp_sess_key;
        }
        if (user_sess_key->length) {
            *lm_sess_key = data_blob_talloc(mem_ctx, user_sess_key->data, MIN(8, user_sess_key->length));
        }
        return NT_STATUS_OK;
    }

    /* Apparently NT accepts NT responses in the LM field
       - I think this is related to Win9X pass-though authentication
    */
    DEBUG(4,("ntlm_password_check: Checking NT MD4 password in LM field\n"));
    if (ntlm_auth) {
        if (smb_pwd_check_ntlmv1(mem_ctx,
                                 lm_response,
                                 stored_nt->hash, challenge,
                                 NULL)) {
            /* The session key for this response is still very odd.
               It not very secure, so use it only if we otherwise
               allow LM authentication */

            if (lanman_auth && stored_lanman) {
                uint8_t first_8_lm_hash[16];
                memcpy(first_8_lm_hash, stored_lanman->hash, 8);
                memset(first_8_lm_hash + 8, '\0', 8);
                *user_sess_key = data_blob_talloc(mem_ctx, first_8_lm_hash, 16);
                *lm_sess_key = data_blob_talloc(mem_ctx, stored_lanman->hash, 8);
            }
            return NT_STATUS_OK;
        }
        DEBUG(3,("ntlm_password_check: LM password, NT MD4 password in LM field and LMv2 failed for user %s\n",username));
    } else {
        DEBUG(3,("ntlm_password_check: LM password and LMv2 failed for user %s, and NT MD4 password in LM field not permitted\n",username));
    }

    /* Try and match error codes */
    if (strchr_m(username, '@')) {
        return NT_STATUS_NOT_FOUND;
    }
    return NT_STATUS_WRONG_PASSWORD;
}
Esempio n. 5
0
int mit_samba_kpasswd_change_password(struct mit_samba_context *ctx,
				      char *pwd,
				      krb5_db_entry *db_entry)
{
	NTSTATUS status;
	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
	TALLOC_CTX *tmp_ctx;
	DATA_BLOB password;
	enum samPwdChangeReason reject_reason;
	struct samr_DomInfo1 *dominfo;
	const char *error_string = NULL;
	struct auth_user_info_dc *user_info_dc;
	struct samba_kdc_entry *p;
	krb5_error_code code = 0;

#ifdef DEBUG_PASSWORD
	DEBUG(1,("mit_samba_kpasswd_change_password called with: %s\n", pwd));
#endif

	tmp_ctx = talloc_named(ctx, 0, "mit_samba_kpasswd_change_password");
	if (tmp_ctx == NULL) {
		return ENOMEM;
	}

	p = (struct samba_kdc_entry *)db_entry->e_data;

	status = authsam_make_user_info_dc(tmp_ctx,
					   ctx->db_ctx->samdb,
					   lpcfg_netbios_name(ctx->db_ctx->lp_ctx),
					   lpcfg_sam_name(ctx->db_ctx->lp_ctx),
					   p->realm_dn,
					   p->msg,
					   data_blob(NULL, 0),
					   data_blob(NULL, 0),
					   &user_info_dc);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1,("authsam_make_user_info_dc failed: %s\n",
			nt_errstr(status)));
		talloc_free(tmp_ctx);
		return EINVAL;
	}

	status = auth_generate_session_info(tmp_ctx,
					    ctx->db_ctx->lp_ctx,
					    ctx->db_ctx->samdb,
					    user_info_dc,
					    0, /* session_info_flags */
					    &ctx->session_info);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1,("auth_generate_session_info failed: %s\n",
			nt_errstr(status)));
		talloc_free(tmp_ctx);
		return EINVAL;
	}

	/* password is expected as UTF16 */

	if (!convert_string_talloc(tmp_ctx, CH_UTF8, CH_UTF16,
				   pwd, strlen(pwd),
				   &password.data, &password.length)) {
		DEBUG(1,("convert_string_talloc failed\n"));
		talloc_free(tmp_ctx);
		return EINVAL;
	}

	status = samdb_kpasswd_change_password(tmp_ctx,
					       ctx->db_ctx->lp_ctx,
					       ctx->db_ctx->ev_ctx,
					       ctx->db_ctx->samdb,
					       ctx->session_info,
					       &password,
					       &reject_reason,
					       &dominfo,
					       &error_string,
					       &result);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1,("samdb_kpasswd_change_password failed: %s\n",
			nt_errstr(status)));
		code = KADM5_PASS_Q_GENERIC;
		krb5_set_error_message(ctx->context, code, "%s", error_string);
		goto out;
	}

	if (!NT_STATUS_IS_OK(result)) {
		code = mit_samba_change_pwd_error(ctx->context,
						  result,
						  reject_reason,
						  dominfo);
	}

out:
	talloc_free(tmp_ctx);

	return code;
}
Esempio n. 6
0
static NTSTATUS convert_file_from_ucs2(TALLOC_CTX *mem_ctx,
				       const char *filename_in,
				       char **filename_out)
{
	int tmp_fd = -1;
	uint8 *data_in = NULL;
	uint8 *data_out = NULL;
	char *tmp_name = NULL;
	NTSTATUS status;
	size_t n = 0;

	if (!filename_out) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	data_in = (uint8 *)file_load(filename_in, &n, 0);
	if (!data_in) {
		status = NT_STATUS_NO_SUCH_FILE;
		goto out;
	}

	tmp_name = talloc_asprintf(mem_ctx, "%s/convert_file_from_ucs2.XXXXXX",
		tmpdir());
	if (!tmp_name) {
		status = NT_STATUS_NO_MEMORY;
		goto out;
	}

	tmp_fd = smb_mkstemp(tmp_name);
	if (tmp_fd == -1) {
		status = NT_STATUS_ACCESS_DENIED;
		goto out;
	}

	n = convert_string_talloc(mem_ctx, CH_UTF16LE, CH_UNIX,
				  data_in, n, &data_out, False);

	if (n == -1) {
		status = NT_STATUS_INVALID_BUFFER_SIZE;
		goto out;
	}

	/* skip utf8 BOM */
	DEBUG(11,("convert_file_from_ucs2: "
	       "data_out[0]: 0x%x, data_out[1]: 0x%x, data_out[2]: 0x%x\n",
		data_out[0], data_out[1], data_out[2]));

	if ((data_out[0] == 0xef) && (data_out[1] == 0xbb) &&
	    (data_out[2] == 0xbf)) {
		DEBUG(11,("convert_file_from_ucs2: "
			 "%s skipping utf8 BOM\n", tmp_name));
		data_out += 3;
		n -= 3;
	}

	if (sys_write(tmp_fd, data_out, n) != n) {
		status = map_nt_error_from_unix(errno);
		goto out;
	}

	*filename_out = tmp_name;

	status = NT_STATUS_OK;

 out:
	if (tmp_fd != -1) {
		close(tmp_fd);
	}

	SAFE_FREE(data_in);

	return status;
}
Esempio n. 7
0
NTSTATUS smbd_smb2_request_process_tcon(struct smbd_smb2_request *req)
{
	const uint8_t *inbody;
	int i = req->current_idx;
	uint8_t *outhdr;
	DATA_BLOB outbody;
	uint16_t in_path_offset;
	uint16_t in_path_length;
	DATA_BLOB in_path_buffer;
	char *in_path_string;
	size_t in_path_string_size;
	uint8_t out_share_type = 0;
	uint32_t out_share_flags = 0;
	uint32_t out_capabilities = 0;
	uint32_t out_maximal_access = 0;
	uint32_t out_tree_id = 0;
	NTSTATUS status;
	bool ok;

	status = smbd_smb2_request_verify_sizes(req, 0x09);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(req, status);
	}
	inbody = (const uint8_t *)req->in.vector[i+1].iov_base;

	in_path_offset = SVAL(inbody, 0x04);
	in_path_length = SVAL(inbody, 0x06);

	if (in_path_offset != (SMB2_HDR_BODY + req->in.vector[i+1].iov_len)) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	if (in_path_length > req->in.vector[i+2].iov_len) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	in_path_buffer.data = (uint8_t *)req->in.vector[i+2].iov_base;
	in_path_buffer.length = in_path_length;

	ok = convert_string_talloc(req, CH_UTF16, CH_UNIX,
				   in_path_buffer.data,
				   in_path_buffer.length,
				   &in_path_string,
				   &in_path_string_size);
	if (!ok) {
		return smbd_smb2_request_error(req, NT_STATUS_ILLEGAL_CHARACTER);
	}

	if (in_path_buffer.length == 0) {
		in_path_string_size = 0;
	}

	if (strlen(in_path_string) != in_path_string_size) {
		return smbd_smb2_request_error(req, NT_STATUS_BAD_NETWORK_NAME);
	}

	status = smbd_smb2_tree_connect(req, in_path_string,
					&out_share_type,
					&out_share_flags,
					&out_capabilities,
					&out_maximal_access,
					&out_tree_id);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(req, status);
	}

	outhdr = (uint8_t *)req->out.vector[i].iov_base;

	outbody = data_blob_talloc(req->out.vector, NULL, 0x10);
	if (outbody.data == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
	}

	SIVAL(outhdr, SMB2_HDR_TID, out_tree_id);

	SSVAL(outbody.data, 0x00, 0x10);	/* struct size */
	SCVAL(outbody.data, 0x02,
	      out_share_type);			/* share type */
	SCVAL(outbody.data, 0x03, 0);		/* reserved */
	SIVAL(outbody.data, 0x04,
	      out_share_flags);			/* share flags */
	SIVAL(outbody.data, 0x08,
	      out_capabilities);		/* capabilities */
	SIVAL(outbody.data, 0x0C,
	      out_maximal_access);		/* maximal access */

	return smbd_smb2_request_done(req, outbody, NULL);
}
NTSTATUS smbd_smb2_request_process_query_directory(struct smbd_smb2_request *req)
{
	NTSTATUS status;
	const uint8_t *inbody;
	uint8_t in_file_info_class;
	uint8_t in_flags;
	uint32_t in_file_index;
	uint64_t in_file_id_persistent;
	uint64_t in_file_id_volatile;
	struct files_struct *in_fsp;
	uint16_t in_file_name_offset;
	uint16_t in_file_name_length;
	DATA_BLOB in_file_name_buffer;
	char *in_file_name_string;
	size_t in_file_name_string_size;
	uint32_t in_output_buffer_length;
	struct tevent_req *subreq;
	bool ok;

	status = smbd_smb2_request_verify_sizes(req, 0x21);
	if (!NT_STATUS_IS_OK(status)) {
		return smbd_smb2_request_error(req, status);
	}
	inbody = SMBD_SMB2_IN_BODY_PTR(req);

	in_file_info_class		= CVAL(inbody, 0x02);
	in_flags			= CVAL(inbody, 0x03);
	in_file_index			= IVAL(inbody, 0x04);
	in_file_id_persistent		= BVAL(inbody, 0x08);
	in_file_id_volatile		= BVAL(inbody, 0x10);
	in_file_name_offset		= SVAL(inbody, 0x18);
	in_file_name_length		= SVAL(inbody, 0x1A);
	in_output_buffer_length		= IVAL(inbody, 0x1C);

	if (in_file_name_offset == 0 && in_file_name_length == 0) {
		/* This is ok */
	} else if (in_file_name_offset !=
		   (SMB2_HDR_BODY + SMBD_SMB2_IN_BODY_LEN(req))) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	if (in_file_name_length > SMBD_SMB2_IN_DYN_LEN(req)) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	/* The output header is 8 bytes. */
	if (in_output_buffer_length <= 8) {
		return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
	}

	DEBUG(10,("smbd_smb2_request_find_done: in_output_buffer_length = %u\n",
		(unsigned int)in_output_buffer_length ));

	/* Take into account the output header. */
	in_output_buffer_length -= 8;

	in_file_name_buffer.data = SMBD_SMB2_IN_DYN_PTR(req);
	in_file_name_buffer.length = in_file_name_length;

	ok = convert_string_talloc(req, CH_UTF16, CH_UNIX,
				   in_file_name_buffer.data,
				   in_file_name_buffer.length,
				   &in_file_name_string,
				   &in_file_name_string_size);
	if (!ok) {
		return smbd_smb2_request_error(req, NT_STATUS_ILLEGAL_CHARACTER);
	}

	if (in_file_name_buffer.length == 0) {
		in_file_name_string_size = 0;
	}

	if (strlen(in_file_name_string) != in_file_name_string_size) {
		return smbd_smb2_request_error(req, NT_STATUS_OBJECT_NAME_INVALID);
	}

	in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
	if (in_fsp == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
	}

	subreq = smbd_smb2_query_directory_send(req, req->sconn->ev_ctx,
				     req, in_fsp,
				     in_file_info_class,
				     in_flags,
				     in_file_index,
				     in_output_buffer_length,
				     in_file_name_string);
	if (subreq == NULL) {
		return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
	}
	tevent_req_set_callback(subreq, smbd_smb2_request_find_done, req);

	return smbd_smb2_request_pending_queue(req, subreq, 500);
}
Esempio n. 9
0
File: ldb.c Progetto: srimalik/samba
static void reg_ldb_unpack_value(TALLOC_CTX *mem_ctx,
				 struct ldb_message *msg,
				 const char **name, uint32_t *type,
				 DATA_BLOB *data)
{
	const struct ldb_val *val;
	uint32_t value_type;

	if (name != NULL) {
		*name = talloc_strdup(mem_ctx,
				      ldb_msg_find_attr_as_string(msg, "value",
				      ""));
	}

	value_type = ldb_msg_find_attr_as_uint(msg, "type", 0);
	*type = value_type;

	val = ldb_msg_find_ldb_val(msg, "data");

	switch (value_type)
	{
	case REG_SZ:
	case REG_EXPAND_SZ:
		if (val != NULL) {
			/* The data should be provided as UTF16 string */
			convert_string_talloc(mem_ctx, CH_UTF8, CH_UTF16,
					      val->data, val->length,
					      (void **)&data->data, &data->length);
		} else {
			data->data = NULL;
			data->length = 0;
		}
		break;

	case REG_DWORD:
	case REG_DWORD_BIG_ENDIAN:
		if (val != NULL) {
			/* The data is a plain DWORD */
			uint32_t tmp = strtoul((char *)val->data, NULL, 0);
			data->data = talloc_size(mem_ctx, sizeof(uint32_t));
			if (data->data != NULL) {
				SIVAL(data->data, 0, tmp);
			}
			data->length = sizeof(uint32_t);
		} else {
			data->data = NULL;
			data->length = 0;
		}
		break;

	case REG_QWORD:
		if (val != NULL) {
			/* The data is a plain QWORD */
			uint64_t tmp = strtoull((char *)val->data, NULL, 0);
			data->data = talloc_size(mem_ctx, sizeof(uint64_t));
			if (data->data != NULL) {
				SBVAL(data->data, 0, tmp);
			}
			data->length = sizeof(uint64_t);
		} else {
			data->data = NULL;
			data->length = 0;
		}
		break;

	case REG_BINARY:
	default:
		if (val != NULL) {
			data->data = talloc_memdup(mem_ctx, val->data,
						   val->length);
			data->length = val->length;
		} else {
			data->data = NULL;
			data->length = 0;
		}
		break;
	}
}
Esempio n. 10
0
File: ldb.c Progetto: srimalik/samba
static struct ldb_message *reg_ldb_pack_value(struct ldb_context *ctx,
					      TALLOC_CTX *mem_ctx,
					      const char *name,
					      uint32_t type, DATA_BLOB data)
{
	struct ldb_message *msg;
	char *name_dup, *type_str;
	int ret;

	msg = talloc_zero(mem_ctx, struct ldb_message);
	if (msg == NULL) {
		return NULL;
	}

	name_dup = talloc_strdup(msg, name);
	if (name_dup == NULL) {
		talloc_free(msg);
		return NULL;
	}

	ret = ldb_msg_add_string(msg, "value", name_dup);
	if (ret != LDB_SUCCESS) {
		talloc_free(msg);
		return NULL;
	}

	switch (type) {
	case REG_SZ:
	case REG_EXPAND_SZ:
		if ((data.length > 0) && (data.data != NULL)) {
			struct ldb_val *val;
			bool ret2 = false;

			val = talloc_zero(msg, struct ldb_val);
			if (val == NULL) {
				talloc_free(msg);
				return NULL;
			}

			/* The data is provided as UTF16 string */
			ret2 = convert_string_talloc(mem_ctx, CH_UTF16, CH_UTF8,
						     (void *)data.data, data.length,
						     (void **)&val->data, &val->length);
			if (ret2) {
				ret = ldb_msg_add_value(msg, "data", val, NULL);
			} else {
				/* workaround for non-standard data */
				ret = ldb_msg_add_empty(msg, "data", LDB_FLAG_MOD_DELETE, NULL);
			}
		} else {
			ret = ldb_msg_add_empty(msg, "data", LDB_FLAG_MOD_DELETE, NULL);
		}
		break;

	case REG_DWORD:
	case REG_DWORD_BIG_ENDIAN:
		if ((data.length > 0) && (data.data != NULL)) {
			if (data.length == sizeof(uint32_t)) {
				char *conv_str;

				conv_str = talloc_asprintf(msg, "0x%8.8x",
							   IVAL(data.data, 0));
				if (conv_str == NULL) {
					talloc_free(msg);
					return NULL;
				}
				ret = ldb_msg_add_string(msg, "data", conv_str);
			} else {
				/* workaround for non-standard data */
				talloc_free(msg);
				return NULL;
			}
		} else {
			ret = ldb_msg_add_empty(msg, "data", LDB_FLAG_MOD_DELETE, NULL);
		}
		break;

	case REG_QWORD:
		if ((data.length > 0) && (data.data != NULL)) {
			if (data.length == sizeof(uint64_t)) {
				char *conv_str;

				conv_str = talloc_asprintf(msg, "0x%16.16llx",
							   (unsigned long long)BVAL(data.data, 0));
				if (conv_str == NULL) {
					talloc_free(msg);
					return NULL;
				}
				ret = ldb_msg_add_string(msg, "data", conv_str);
			} else {
				/* workaround for non-standard data */
				talloc_free(msg);
				return NULL;

			}
		} else {
			ret = ldb_msg_add_empty(msg, "data", LDB_FLAG_MOD_DELETE, NULL);
		}
		break;

	case REG_BINARY:
	default:
		if ((data.length > 0) && (data.data != NULL)) {
			ret = ldb_msg_add_value(msg, "data", &data, NULL);
		} else {
			ret = ldb_msg_add_empty(msg, "data", LDB_FLAG_MOD_DELETE, NULL);
		}
		break;
	}
Esempio n. 11
0
NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
			 struct messaging_context *msg_ctx,
			 struct dcerpc_binding_handle *b,
			 const char *domain,
			 bool force)
{
	TALLOC_CTX *frame = talloc_stackframe();
	struct trust_pw_change_state *state;
	struct cli_credentials *creds = NULL;
	const struct samr_Password *current_nt_hash = NULL;
	const struct samr_Password *previous_nt_hash = NULL;
	enum netr_SchannelType sec_channel_type = SEC_CHAN_NULL;
	time_t pass_last_set_time;
	uint32_t old_version = 0;
	struct pdb_trusted_domain *td = NULL;
	struct timeval g_timeout = { 0, };
	int timeout = 0;
	struct timeval tv = { 0, };
	size_t new_len = DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH;
	uint8_t new_password_buffer[256 * 2] = { 0, };
	char *new_trust_passwd = NULL;
	size_t len = 0;
	uint32_t new_version = 0;
	uint32_t *new_trust_version = NULL;
	NTSTATUS status;
	bool ok;

	state = talloc_zero(frame, struct trust_pw_change_state);
	if (state == NULL) {
		TALLOC_FREE(frame);
		return NT_STATUS_NO_MEMORY;
	}

	state->g_ctx = g_lock_ctx_init(state, msg_ctx);
	if (state->g_ctx == NULL) {
		TALLOC_FREE(frame);
		return NT_STATUS_NO_MEMORY;
	}

	state->g_lock_key = talloc_asprintf(state,
				"trust_password_change_%s",
				domain);
	if (state->g_lock_key == NULL) {
		TALLOC_FREE(frame);
		return NT_STATUS_NO_MEMORY;
	}

	g_timeout = timeval_current_ofs(10, 0);
	status = g_lock_lock(state->g_ctx,
			     state->g_lock_key,
			     G_LOCK_WRITE, g_timeout);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("could not get g_lock on [%s]!\n",
			  state->g_lock_key));
		TALLOC_FREE(frame);
		return status;
	}

	talloc_set_destructor(state, trust_pw_change_state_destructor);

	status = pdb_get_trust_credentials(domain, NULL, frame, &creds);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("could not fetch domain creds for domain %s - %s!\n",
			  domain, nt_errstr(status)));
		TALLOC_FREE(frame);
		return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
	}

	current_nt_hash = cli_credentials_get_nt_hash(creds, frame);
	if (current_nt_hash == NULL) {
		DEBUG(0, ("cli_credentials_get_nt_hash failed for domain %s!\n",
			  domain));
		TALLOC_FREE(frame);
		return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
	}

	old_version = cli_credentials_get_kvno(creds);
	pass_last_set_time = cli_credentials_get_password_last_changed_time(creds);
	sec_channel_type = cli_credentials_get_secure_channel_type(creds);

	new_version = old_version + 1;

	switch (sec_channel_type) {
	case SEC_CHAN_WKSTA:
	case SEC_CHAN_BDC:
		break;
	case SEC_CHAN_DNS_DOMAIN:
		/*
		 * new_len * 2 = 498 bytes is the largest possible length
		 * NL_PASSWORD_VERSION consumes the rest of the possible 512 bytes
		 * and a confounder with at least 2 bytes is required.
		 *
		 * Windows uses new_len = 120 => 240 bytes.
		 */
		new_len = 120;

		/* fall through */
	case SEC_CHAN_DOMAIN:
		status = pdb_get_trusted_domain(frame, domain, &td);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(0, ("pdb_get_trusted_domain() failed for domain %s - %s!\n",
				  domain, nt_errstr(status)));
			TALLOC_FREE(frame);
			return status;
		}

		new_trust_version = &new_version;
		break;
	default:
		TALLOC_FREE(frame);
		return NT_STATUS_NOT_SUPPORTED;
	}

	timeout = lp_machine_password_timeout();
	if (timeout == 0) {
		if (!force) {
			DEBUG(10,("machine password never expires\n"));
			TALLOC_FREE(frame);
			return NT_STATUS_OK;
		}
	}

	tv.tv_sec = pass_last_set_time;
	DEBUG(10, ("password last changed %s\n",
		   timeval_string(talloc_tos(), &tv, false)));
	tv.tv_sec += timeout;
	DEBUGADD(10, ("password valid until %s\n",
		      timeval_string(talloc_tos(), &tv, false)));

	if (!force && !timeval_expired(&tv)) {
		TALLOC_FREE(frame);
		return NT_STATUS_OK;
	}

	/*
	 * Create a random machine account password
	 * We create a random buffer and convert that to utf8.
	 * This is similar to what windows is doing.
	 */
	generate_secret_buffer(new_password_buffer, new_len * 2);
	ok = convert_string_talloc(frame,
				   CH_UTF16MUNGED, CH_UTF8,
				   new_password_buffer, new_len * 2,
				   (void *)&new_trust_passwd, &len);
	ZERO_STRUCT(new_password_buffer);
	if (!ok) {
		DEBUG(0, ("convert_string_talloc failed\n"));
		TALLOC_FREE(frame);
		return NT_STATUS_NO_MEMORY;
	}

	/*
	 * We could use cli_credentials_get_old_nt_hash(creds, frame) to
	 * set previous_nt_hash.
	 *
	 * But we want to check if the dc has our current password and only do
	 * a change if that's the case. So we keep previous_nt_hash = NULL.
	 *
	 * TODO:
	 * If the previous password is the only password in common with the dc,
	 * we better skip the password change, or use something like
	 * ServerTrustPasswordsGet() or netr_ServerGetTrustInfo() to fix our
	 * local secrets before doing the change.
	 */
	status = netlogon_creds_cli_auth(context, b,
					 *current_nt_hash,
					 previous_nt_hash);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0, ("netlogon_creds_cli_auth for domain %s - %s!\n",
			  domain, nt_errstr(status)));
		TALLOC_FREE(frame);
		return status;
	}

	/*
	 * Return the result of trying to write the new password
	 * back into the trust account file.
	 */

	switch (sec_channel_type) {

	case SEC_CHAN_WKSTA:
	case SEC_CHAN_BDC:
		ok = secrets_store_machine_password(new_trust_passwd, domain, sec_channel_type);
		if (!ok) {
			DEBUG(0, ("secrets_store_machine_password failed for domain %s!\n",
				  domain));
			TALLOC_FREE(frame);
			return NT_STATUS_INTERNAL_DB_CORRUPTION;
		}
		break;

	case SEC_CHAN_DNS_DOMAIN:
	case SEC_CHAN_DOMAIN:
		/*
		 * we need to get the sid first for the
		 * pdb_set_trusteddom_pw call
		 */
		ok = pdb_set_trusteddom_pw(domain, new_trust_passwd,
					   &td->security_identifier);
		if (!ok) {
			DEBUG(0, ("pdb_set_trusteddom_pw() failed for domain %s!\n",
				  domain));
			TALLOC_FREE(frame);
			return NT_STATUS_INTERNAL_DB_CORRUPTION;
		}
		break;

	default:
		smb_panic("Unsupported secure channel type");
		break;
	}

	DEBUG(1,("%s : %s(%s): Changed password locally\n",
		 current_timestring(talloc_tos(), false), __func__, domain));

	status = netlogon_creds_cli_ServerPasswordSet(context, b,
						      new_trust_passwd,
						      new_trust_version);
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(0,("%s : %s(%s) remote password change set failed - %s\n",
			 current_timestring(talloc_tos(), false), __func__,
			 domain, nt_errstr(status)));
		TALLOC_FREE(frame);
		return status;
	}

	DEBUG(1,("%s : %s(%s): Changed password remotely.\n",
		 current_timestring(talloc_tos(), false), __func__, domain));

	TALLOC_FREE(frame);
	return NT_STATUS_OK;
}