/*************************************************************************** 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); } }
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); }
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; }
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; }
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; }
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; }
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); }
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; } }
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; }
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; }