enum winbindd_result winbindd_dual_ccache_save( struct winbindd_domain *domain, struct winbindd_cli_state *state) { NTSTATUS status = NT_STATUS_NOT_SUPPORTED; /* Ensure null termination */ state->request->data.ccache_save.user[ sizeof(state->request->data.ccache_save.user)-1]='\0'; state->request->data.ccache_save.pass[ sizeof(state->request->data.ccache_save.pass)-1]='\0'; DEBUG(3, ("winbindd_dual_ccache_save: [%5lu]: save password of user " "%s\n", (unsigned long)state->pid, state->request->data.ccache_save.user)); status = winbindd_add_memory_creds( state->request->data.ccache_save.user, state->request->data.ccache_save.uid, state->request->data.ccache_save.pass); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("winbindd_add_memory_creds failed %s\n", nt_errstr(status))); return WINBINDD_ERROR; } return WINBINDD_OK; }
void winbindd_ccache_save(struct winbindd_cli_state *state) { struct winbindd_domain *domain; fstring name_domain, name_user; NTSTATUS status; /* Ensure null termination */ state->request->data.ccache_save.user[ sizeof(state->request->data.ccache_save.user)-1]='\0'; state->request->data.ccache_save.pass[ sizeof(state->request->data.ccache_save.pass)-1]='\0'; DEBUG(3, ("[%5lu]: save password of user %s\n", (unsigned long)state->pid, state->request->data.ccache_save.user)); /* Parse domain and username */ if (!canonicalize_username(state->request->data.ccache_save.user, name_domain, name_user)) { DEBUG(5,("winbindd_ccache_save: cannot parse domain and user " "from name [%s]\n", state->request->data.ccache_save.user)); request_error(state); return; } /* * The domain is checked here only for compatibility * reasons. We used to do the winbindd memory ccache for * ntlm_auth in the domain child. With that code, we had to * make sure that we do have a domain around to send this * to. Now we do the memory cache in the parent winbindd, * where it would not matter if we have a domain or not. */ domain = find_auth_domain(state->request->flags, name_domain); if (domain == NULL) { DEBUG(5, ("winbindd_ccache_save: can't get domain [%s]\n", name_domain)); request_error(state); return; } if (!check_client_uid(state, state->request->data.ccache_save.uid)) { request_error(state); return; } status = winbindd_add_memory_creds( state->request->data.ccache_save.user, state->request->data.ccache_save.uid, state->request->data.ccache_save.pass); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("winbindd_add_memory_creds failed %s\n", nt_errstr(status))); request_error(state); return; } request_ok(state); }
NTSTATUS add_ccache_to_list(const char *princ_name, const char *ccname, const char *service, const char *username, const char *pass, const char *realm, uid_t uid, time_t create_time, time_t ticket_end, time_t renew_until, bool postponed_request) { struct WINBINDD_CCACHE_ENTRY *entry = NULL; struct timeval t; NTSTATUS ntret; #ifdef HAVE_KRB5 int ret; #endif if ((username == NULL && princ_name == NULL) || ccname == NULL || uid < 0) { return NT_STATUS_INVALID_PARAMETER; } if (ccache_entry_count() + 1 > MAX_CCACHES) { DEBUG(10,("add_ccache_to_list: " "max number of ccaches reached\n")); return NT_STATUS_NO_MORE_ENTRIES; } /* If it is cached login, destroy krb5 ticket * to avoid surprise. */ #ifdef HAVE_KRB5 if (postponed_request) { /* ignore KRB5_FCC_NOFILE error here */ ret = ads_kdestroy(ccname); if (ret == KRB5_FCC_NOFILE) { ret = 0; } if (ret) { DEBUG(0, ("add_ccache_to_list: failed to destroy " "user krb5 ccache %s with %s\n", ccname, error_message(ret))); return krb5_to_nt_status(ret); } DEBUG(10, ("add_ccache_to_list: successfully destroyed " "krb5 ccache %s for user %s\n", ccname, username)); } #endif /* Reference count old entries */ entry = get_ccache_by_username(username); if (entry) { /* Check cached entries are identical. */ if (!ccache_entry_identical(username, uid, ccname)) { return NT_STATUS_INVALID_PARAMETER; } entry->ref_count++; DEBUG(10,("add_ccache_to_list: " "ref count on entry %s is now %d\n", username, entry->ref_count)); /* FIXME: in this case we still might want to have a krb5 cred * event handler created - gd * Add ticket refresh handler here */ if (!lp_winbind_refresh_tickets() || renew_until <= 0) { return NT_STATUS_OK; } if (!entry->event) { if (postponed_request) { t = timeval_current_ofs(MAX(30, lp_winbind_cache_time()), 0); add_krb5_ticket_gain_handler_event(entry, t); } else { /* Renew at 1/2 the ticket expiration time */ #if defined(DEBUG_KRB5_TKT_RENEWAL) t = timeval_set(time(NULL)+30, 0); #else t = timeval_set(krb5_event_refresh_time(ticket_end), 0); #endif if (!entry->refresh_time) { entry->refresh_time = t.tv_sec; } entry->event = tevent_add_timer(winbind_event_context(), entry, t, krb5_ticket_refresh_handler, entry); } if (!entry->event) { ntret = remove_ccache(username); if (!NT_STATUS_IS_OK(ntret)) { DEBUG(0, ("add_ccache_to_list: Failed to remove krb5 " "ccache %s for user %s\n", entry->ccname, entry->username)); DEBUG(0, ("add_ccache_to_list: error is %s\n", nt_errstr(ntret))); return ntret; } return NT_STATUS_NO_MEMORY; } DEBUG(10,("add_ccache_to_list: added krb5_ticket handler\n")); } /* * If we're set up to renew our krb5 tickets, we must * cache the credentials in memory for the ticket * renew function (or increase the reference count * if we're logging in more than once). Fix inspired * by patch from Ian Gordon <*****@*****.**> * for bugid #9098. */ ntret = winbindd_add_memory_creds(username, uid, pass); DEBUG(10, ("winbindd_add_memory_creds returned: %s\n", nt_errstr(ntret))); return NT_STATUS_OK; } entry = talloc(NULL, struct WINBINDD_CCACHE_ENTRY); if (!entry) { return NT_STATUS_NO_MEMORY; } ZERO_STRUCTP(entry); if (username) { entry->username = talloc_strdup(entry, username); if (!entry->username) { goto no_mem; } } if (princ_name) { entry->principal_name = talloc_strdup(entry, princ_name); if (!entry->principal_name) { goto no_mem; } } if (service) { entry->service = talloc_strdup(entry, service); if (!entry->service) { goto no_mem; } } entry->ccname = talloc_strdup(entry, ccname); if (!entry->ccname) { goto no_mem; } entry->realm = talloc_strdup(entry, realm); if (!entry->realm) { goto no_mem; } entry->create_time = create_time; entry->renew_until = renew_until; entry->uid = uid; entry->ref_count = 1; if (!lp_winbind_refresh_tickets() || renew_until <= 0) { goto add_entry; } if (postponed_request) { t = timeval_current_ofs(MAX(30, lp_winbind_cache_time()), 0); add_krb5_ticket_gain_handler_event(entry, t); } else { /* Renew at 1/2 the ticket expiration time */ #if defined(DEBUG_KRB5_TKT_RENEWAL) t = timeval_set(time(NULL)+30, 0); #else t = timeval_set(krb5_event_refresh_time(ticket_end), 0); #endif if (entry->refresh_time == 0) { entry->refresh_time = t.tv_sec; } entry->event = tevent_add_timer(winbind_event_context(), entry, t, krb5_ticket_refresh_handler, entry); } if (!entry->event) { goto no_mem; } DEBUG(10,("add_ccache_to_list: added krb5_ticket handler\n")); add_entry: DLIST_ADD(ccache_list, entry); DEBUG(10,("add_ccache_to_list: " "added ccache [%s] for user [%s] to the list\n", ccname, username)); if (entry->event) { /* * If we're set up to renew our krb5 tickets, we must * cache the credentials in memory for the ticket * renew function. Fix inspired by patch from * Ian Gordon <*****@*****.**> for * bugid #9098. */ ntret = winbindd_add_memory_creds(username, uid, pass); DEBUG(10, ("winbindd_add_memory_creds returned: %s\n", nt_errstr(ntret))); } return NT_STATUS_OK; no_mem: TALLOC_FREE(entry); return NT_STATUS_NO_MEMORY; }