NTSTATUS winbindd_replace_memory_creds(const char *username, const char *pass) { struct WINBINDD_MEMORY_CREDS *memcredp = NULL; memcredp = find_memory_creds_by_name(username); if (!memcredp) { DEBUG(10,("winbindd_replace_memory_creds: unknown user %s\n", username)); return NT_STATUS_OBJECT_NAME_NOT_FOUND; } DEBUG(10,("winbindd_replace_memory_creds: replaced creds for user %s\n", username)); return winbindd_replace_memory_creds_internal(memcredp, pass); }
NTSTATUS winbindd_delete_memory_creds(const char *username) { struct WINBINDD_MEMORY_CREDS *memcredp = NULL; struct WINBINDD_CCACHE_ENTRY *entry = NULL; NTSTATUS status = NT_STATUS_OK; memcredp = find_memory_creds_by_name(username); entry = get_ccache_by_username(username); if (!memcredp) { DEBUG(10,("winbindd_delete_memory_creds: unknown user %s\n", username)); return NT_STATUS_OBJECT_NAME_NOT_FOUND; } if (memcredp->ref_count <= 0) { DEBUG(0,("winbindd_delete_memory_creds: logic error. " "ref count for user %s = %d\n", username, memcredp->ref_count)); status = NT_STATUS_INTERNAL_DB_CORRUPTION; } memcredp->ref_count--; if (memcredp->ref_count <= 0) { delete_memory_creds(memcredp); DLIST_REMOVE(memory_creds_list, memcredp); talloc_destroy(memcredp); DEBUG(10,("winbindd_delete_memory_creds: " "deleted entry for user %s\n", username)); } else { DEBUG(10,("winbindd_delete_memory_creds: " "entry for user %s ref_count now %d\n", username, memcredp->ref_count)); } if (entry) { /* Ensure we have no dangling references to this. */ entry->cred_ptr = NULL; } return status; }
NTSTATUS winbindd_add_memory_creds(const char *username, uid_t uid, const char *pass) { struct WINBINDD_CCACHE_ENTRY *entry = get_ccache_by_username(username); NTSTATUS status; status = winbindd_add_memory_creds_internal(username, uid, pass); if (!NT_STATUS_IS_OK(status)) { return status; } if (entry) { struct WINBINDD_MEMORY_CREDS *memcredp = NULL; memcredp = find_memory_creds_by_name(username); if (memcredp) { entry->cred_ptr = memcredp; } } return status; }
void winbindd_ccache_ntlm_auth(struct winbindd_cli_state *state) { struct winbindd_domain *domain; fstring name_domain, name_user; NTSTATUS result = NT_STATUS_NOT_SUPPORTED; struct WINBINDD_MEMORY_CREDS *entry; DATA_BLOB initial, challenge, auth; uint32_t initial_blob_len, challenge_blob_len, extra_len; /* Ensure null termination */ state->request->data.ccache_ntlm_auth.user[ sizeof(state->request->data.ccache_ntlm_auth.user)-1]='\0'; DEBUG(3, ("[%5lu]: perform NTLM auth on behalf of user %s\n", (unsigned long)state->pid, state->request->data.ccache_ntlm_auth.user)); /* Parse domain and username */ if (!canonicalize_username(state->request->data.ccache_ntlm_auth.user, name_domain, name_user)) { DEBUG(5,("winbindd_ccache_ntlm_auth: cannot parse domain and user from name [%s]\n", state->request->data.ccache_ntlm_auth.user)); request_error(state); return; } domain = find_auth_domain(state->request->flags, name_domain); if (domain == NULL) { DEBUG(5,("winbindd_ccache_ntlm_auth: can't get domain [%s]\n", name_domain)); request_error(state); return; } if (!check_client_uid(state, state->request->data.ccache_ntlm_auth.uid)) { request_error(state); return; } /* validate blob lengths */ initial_blob_len = state->request->data.ccache_ntlm_auth.initial_blob_len; challenge_blob_len = state->request->data.ccache_ntlm_auth.challenge_blob_len; extra_len = state->request->extra_len; if (initial_blob_len > extra_len || challenge_blob_len > extra_len || initial_blob_len + challenge_blob_len > extra_len || initial_blob_len + challenge_blob_len < initial_blob_len || initial_blob_len + challenge_blob_len < challenge_blob_len) { DEBUG(10,("winbindd_dual_ccache_ntlm_auth: blob lengths overrun " "or wrap. Buffer [%d+%d > %d]\n", initial_blob_len, challenge_blob_len, extra_len)); goto process_result; } /* Parse domain and username */ if (!parse_domain_user(state->request->data.ccache_ntlm_auth.user, name_domain, name_user)) { DEBUG(10,("winbindd_dual_ccache_ntlm_auth: cannot parse " "domain and user from name [%s]\n", state->request->data.ccache_ntlm_auth.user)); goto process_result; } entry = find_memory_creds_by_name(state->request->data.ccache_ntlm_auth.user); if (entry == NULL || entry->nt_hash == NULL || entry->lm_hash == NULL) { DEBUG(10,("winbindd_dual_ccache_ntlm_auth: could not find " "credentials for user %s\n", state->request->data.ccache_ntlm_auth.user)); goto process_result; } DEBUG(10,("winbindd_dual_ccache_ntlm_auth: found ccache [%s]\n", entry->username)); if (!client_can_access_ccache_entry(state->request->data.ccache_ntlm_auth.uid, entry)) { goto process_result; } if (initial_blob_len == 0 && challenge_blob_len == 0) { /* this is just a probe to see if credentials are available. */ result = NT_STATUS_OK; state->response->data.ccache_ntlm_auth.auth_blob_len = 0; goto process_result; } initial = data_blob_const(state->request->extra_data.data, initial_blob_len); challenge = data_blob_const( state->request->extra_data.data + initial_blob_len, state->request->data.ccache_ntlm_auth.challenge_blob_len); result = do_ntlm_auth_with_stored_pw( name_user, name_domain, entry->pass, initial, challenge, &auth, state->response->data.ccache_ntlm_auth.session_key); if (!NT_STATUS_IS_OK(result)) { goto process_result; } state->response->extra_data.data = talloc_memdup( state->mem_ctx, auth.data, auth.length); if (!state->response->extra_data.data) { result = NT_STATUS_NO_MEMORY; goto process_result; } state->response->length += auth.length; state->response->data.ccache_ntlm_auth.auth_blob_len = auth.length; data_blob_free(&auth); process_result: if (!NT_STATUS_IS_OK(result)) { request_error(state); return; } request_ok(state); }
static NTSTATUS winbindd_add_memory_creds_internal(const char *username, uid_t uid, const char *pass) { /* Shortcut to ensure we don't store if no mlock. */ #if !defined(HAVE_MLOCK) || !defined(HAVE_MUNLOCK) return NT_STATUS_OK; #else NTSTATUS status; struct WINBINDD_MEMORY_CREDS *memcredp = NULL; memcredp = find_memory_creds_by_name(username); if (uid == (uid_t)-1) { DEBUG(0,("winbindd_add_memory_creds_internal: " "invalid uid for user %s.\n", username)); return NT_STATUS_INVALID_PARAMETER; } if (memcredp) { /* Already exists. Increment the reference count and replace stored creds. */ if (uid != memcredp->uid) { DEBUG(0,("winbindd_add_memory_creds_internal: " "uid %u for user %s doesn't " "match stored uid %u. Replacing.\n", (unsigned int)uid, username, (unsigned int)memcredp->uid)); memcredp->uid = uid; } memcredp->ref_count++; DEBUG(10,("winbindd_add_memory_creds_internal: " "ref count for user %s is now %d\n", username, memcredp->ref_count)); return winbindd_replace_memory_creds_internal(memcredp, pass); } memcredp = talloc_zero(NULL, struct WINBINDD_MEMORY_CREDS); if (!memcredp) { return NT_STATUS_NO_MEMORY; } memcredp->username = talloc_strdup(memcredp, username); if (!memcredp->username) { talloc_destroy(memcredp); return NT_STATUS_NO_MEMORY; } status = store_memory_creds(memcredp, pass); if (!NT_STATUS_IS_OK(status)) { talloc_destroy(memcredp); return status; } memcredp->uid = uid; memcredp->ref_count = 1; DLIST_ADD(memory_creds_list, memcredp); DEBUG(10,("winbindd_add_memory_creds_internal: " "added entry for user %s\n", username)); return NT_STATUS_OK; #endif }
enum winbindd_result winbindd_dual_ccache_ntlm_auth(struct winbindd_domain *domain, struct winbindd_cli_state *state) { NTSTATUS result = NT_STATUS_NOT_SUPPORTED; struct WINBINDD_MEMORY_CREDS *entry; DATA_BLOB initial, challenge, auth; fstring name_domain, name_user; uint32 initial_blob_len, challenge_blob_len, extra_len; /* Ensure null termination */ state->request.data.ccache_ntlm_auth.user[ sizeof(state->request.data.ccache_ntlm_auth.user)-1]='\0'; DEBUG(3, ("winbindd_dual_ccache_ntlm_auth: [%5lu]: perform NTLM auth on " "behalf of user %s (dual)\n", (unsigned long)state->pid, state->request.data.ccache_ntlm_auth.user)); /* validate blob lengths */ initial_blob_len = state->request.data.ccache_ntlm_auth.initial_blob_len; challenge_blob_len = state->request.data.ccache_ntlm_auth.challenge_blob_len; extra_len = state->request.extra_len; if (initial_blob_len > extra_len || challenge_blob_len > extra_len || initial_blob_len + challenge_blob_len > extra_len || initial_blob_len + challenge_blob_len < initial_blob_len || initial_blob_len + challenge_blob_len < challenge_blob_len) { DEBUG(10,("winbindd_dual_ccache_ntlm_auth: blob lengths overrun " "or wrap. Buffer [%d+%d > %d]\n", initial_blob_len, challenge_blob_len, extra_len)); goto process_result; } /* Parse domain and username */ if (!parse_domain_user(state->request.data.ccache_ntlm_auth.user, name_domain, name_user)) { DEBUG(10,("winbindd_dual_ccache_ntlm_auth: cannot parse " "domain and user from name [%s]\n", state->request.data.ccache_ntlm_auth.user)); goto process_result; } entry = find_memory_creds_by_name(state->request.data.ccache_ntlm_auth.user); if (entry == NULL || entry->nt_hash == NULL || entry->lm_hash == NULL) { DEBUG(10,("winbindd_dual_ccache_ntlm_auth: could not find " "credentials for user %s\n", state->request.data.ccache_ntlm_auth.user)); goto process_result; } DEBUG(10,("winbindd_dual_ccache_ntlm_auth: found ccache [%s]\n", entry->username)); if (!client_can_access_ccache_entry(state->request.data.ccache_ntlm_auth.uid, entry)) { goto process_result; } if (initial_blob_len == 0 && challenge_blob_len == 0) { /* this is just a probe to see if credentials are available. */ result = NT_STATUS_OK; state->response.data.ccache_ntlm_auth.auth_blob_len = 0; goto process_result; } initial = data_blob(state->request.extra_data.data, initial_blob_len); challenge = data_blob(state->request.extra_data.data + initial_blob_len, state->request.data.ccache_ntlm_auth.challenge_blob_len); if (!initial.data || !challenge.data) { result = NT_STATUS_NO_MEMORY; } else { result = do_ntlm_auth_with_hashes(name_user, name_domain, entry->lm_hash, entry->nt_hash, initial, challenge, &auth); } data_blob_free(&initial); data_blob_free(&challenge); if (!NT_STATUS_IS_OK(result)) { goto process_result; } state->response.extra_data.data = smb_xmemdup(auth.data, auth.length); if (!state->response.extra_data.data) { result = NT_STATUS_NO_MEMORY; goto process_result; } state->response.length += auth.length; state->response.data.ccache_ntlm_auth.auth_blob_len = auth.length; data_blob_free(&auth); process_result: return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR; }