diff -urp --exclude configure samba-3.5.4.orig/nsswitch/libwbclient/wbclient.h samba-3.5.4/nsswitch/libwbclient/wbclient.h --- samba-3.5.4.orig/nsswitch/libwbclient/wbclient.h 2010-06-18 13:01:04.000000000 +0100 +++ samba-3.5.4/nsswitch/libwbclient/wbclient.h 2010-07-27 10:52:04.789412022 +0100 @@ -445,6 +445,16 @@ struct wbcLogoffUserParams { struct wbcNamedBlob *blobs; }; +/** + * @brief Logoff User Parameters + **/ + +struct wbcEstablishCredParams { + const char *username; + size_t num_blobs; + struct wbcNamedBlob *blobs; +}; + /** @brief Credential cache log-on parameters * */ @@ -1112,6 +1122,17 @@ wbcErr wbcLogoffUserEx(const struct wbcL struct wbcAuthErrorInfo **error); /** + * @brief Establish credentials for a user logged on via non-password auth + * + * @param params A wbcEstablishCredParams structure + * @param error User output details on error + * + * @return #wbcErr + **/ +wbcErr wbcEstablishCredEx(const struct wbcEstablishCredParams *params, + struct wbcAuthErrorInfo **error); + +/** * @brief Change a password for a user * * @param username Name of user to authenticate diff -urp --exclude configure samba-3.5.4.orig/nsswitch/libwbclient/wbc_pam.c samba-3.5.4/nsswitch/libwbclient/wbc_pam.c --- samba-3.5.4.orig/nsswitch/libwbclient/wbc_pam.c 2010-06-18 13:01:04.000000000 +0100 +++ samba-3.5.4/nsswitch/libwbclient/wbc_pam.c 2010-07-27 12:47:27.126322844 +0100 @@ -615,6 +615,93 @@ wbcErr wbcPingDc(const char *domain, str return wbc_status; } +/* Trigger credential establishment for a specific user */ +wbcErr wbcEstablishCredEx(const struct wbcEstablishCredParams *params, + struct wbcAuthErrorInfo **error) +{ + struct winbindd_request request; + struct winbindd_response response; + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + int i; + + /* validate input */ + + if (!params || !params->username) { + wbc_status = WBC_ERR_INVALID_PARAM; + BAIL_ON_WBC_ERROR(wbc_status); + } + + if ((params->num_blobs > 0) && (params->blobs == NULL)) { + wbc_status = WBC_ERR_INVALID_PARAM; + BAIL_ON_WBC_ERROR(wbc_status); + } + if ((params->num_blobs == 0) && (params->blobs != NULL)) { + wbc_status = WBC_ERR_INVALID_PARAM; + BAIL_ON_WBC_ERROR(wbc_status); + } + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + strncpy(request.data.est_cred.user, params->username, + sizeof(request.data.est_cred.user)-1); + + for (i=0; inum_blobs; i++) { + + if (strcasecmp(params->blobs[i].name, "krb5_cc_type") == 0) { + if (params->blobs[i].blob.data) { + strncpy(request.data.est_cred.krb5_cc_type, + (const char *)params->blobs[i].blob.data, + sizeof(request.data.est_cred.krb5_cc_type) - 1); + } + continue; + } + + if (strcasecmp(params->blobs[i].name, "user_uid") == 0) { + if (params->blobs[i].blob.data) { + memcpy(&request.data.est_cred.uid, + params->blobs[i].blob.data, + MIN(params->blobs[i].blob.length, + sizeof(request.data.est_cred.uid))); + } + continue; + } + + if (strcasecmp(params->blobs[i].name, "flags") == 0) { + if (params->blobs[i].blob.data) { + memcpy(&request.flags, + params->blobs[i].blob.data, + MIN(params->blobs[i].blob.length, + sizeof(request.flags))); + } + continue; + } + } + + /* Send request */ + + wbc_status = wbcRequestResponse(WINBINDD_PAM_ESTABLISH_CRED, + &request, + &response); + + /* Take the response above and return it to the caller */ + if (response.data.auth.nt_status != 0) { + if (error) { + wbc_status = wbc_create_error_info(NULL, + &response, + error); + BAIL_ON_WBC_ERROR(wbc_status); + } + + wbc_status = WBC_ERR_AUTH_ERROR; + BAIL_ON_WBC_ERROR(wbc_status); + } + BAIL_ON_WBC_ERROR(wbc_status); + + done: + return wbc_status; +} + /* Trigger an extended logoff notification to Winbind for a specific user */ wbcErr wbcLogoffUserEx(const struct wbcLogoffUserParams *params, struct wbcAuthErrorInfo **error) diff -urp --exclude configure samba-3.5.4.orig/nsswitch/pam_winbind.c samba-3.5.4/nsswitch/pam_winbind.c --- samba-3.5.4.orig/nsswitch/pam_winbind.c 2010-06-18 13:01:04.000000000 +0100 +++ samba-3.5.4/nsswitch/pam_winbind.c 2010-07-27 11:14:24.841804016 +0100 @@ -2593,6 +2593,122 @@ out: return retval; } +static int _pam_establish_cred(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + int retval = PAM_SUCCESS; + struct pwb_context *ctx = NULL; + struct wbcEstablishCredParams estcred; + struct wbcAuthErrorInfo *error = NULL; + const char *user; + wbcErr wbc_status = WBC_ERR_SUCCESS; + + ZERO_STRUCT(estcred); + + retval = _pam_winbind_init_context(pamh, flags, argc, argv, &ctx); + if (retval) { + goto out; + } + + _PAM_LOG_FUNCTION_ENTER("_pam_establish_cred", ctx); + + if ((ctx->ctrl & WINBIND_KRB5_AUTH) && !pam_getenv(pamh, "KRB5CCNAME")) { + uint32_t wbc_flags = 0; + struct passwd *pwd = NULL; + const char *cctype = NULL; + + retval = pam_get_user(pamh, &user, _("Username: ")); + if (retval) { + _pam_log(ctx, LOG_ERR, + "could not identify user"); + goto out; + } + + if (user == NULL) { + _pam_log(ctx, LOG_ERR, + "username was NULL!"); + retval = PAM_USER_UNKNOWN; + goto out; + } + + _pam_log_debug(ctx, LOG_DEBUG, + "username [%s] obtained", user); + + pwd = getpwnam(user); + if (pwd == NULL) { + retval = PAM_USER_UNKNOWN; + goto out; + } + + wbc_flags = WBFLAG_PAM_KRB5 | + WBFLAG_PAM_CONTACT_TRUSTDOM; + + estcred.username = user; + + wbc_status = wbcAddNamedBlob(&estcred.num_blobs, + &estcred.blobs, + "flags", + 0, + (uint8_t *)&wbc_flags, + sizeof(wbc_flags)); + if (!WBC_ERROR_IS_OK(wbc_status)) { + goto out; + } + + wbc_status = wbcAddNamedBlob(&estcred.num_blobs, + &estcred.blobs, + "user_uid", + 0, + (uint8_t *)&pwd->pw_uid, + sizeof(pwd->pw_uid)); + if (!WBC_ERROR_IS_OK(wbc_status)) { + goto out; + } + + cctype = get_krb5_cc_type_from_config(ctx); + if (cctype) { + wbc_status = wbcAddNamedBlob(&estcred.num_blobs, + &estcred.blobs, + "krb5_cc_type", + 0, + (uint8_t *)cctype, + strlen(cctype)+1); + if (!WBC_ERROR_IS_OK(wbc_status)) { + goto out; + } + } + + wbc_status = wbcEstablishCredEx(&estcred, &error); + retval = wbc_auth_error_to_pam_error(ctx, error, wbc_status, + user, "wbcEstablishCredEx"); + wbcFreeMemory(error); + wbcFreeMemory(estcred.blobs); + estcred.blobs = NULL; + + if (!WBC_ERROR_IS_OK(wbc_status)) { + _pam_log(ctx, LOG_INFO, + "failed to logon user %s: %s\n", + user, wbcErrorString(wbc_status)); + } + } + +out: + if (estcred.blobs) { + wbcFreeMemory(estcred.blobs); + } + + if (!WBC_ERROR_IS_OK(wbc_status)) { + retval = wbc_auth_error_to_pam_error(ctx, error, wbc_status, + user, "wbcEstablishCredEx"); + } + + _PAM_LOG_FUNCTION_LEAVE("_pam_establish_cred", ctx, retval); + + TALLOC_FREE(ctx); + + return retval; +} + PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) @@ -2782,9 +2898,7 @@ int pam_sm_setcred(pam_handle_t *pamh, i ret = PAM_SUCCESS; break; case PAM_ESTABLISH_CRED: - _pam_log_debug(ctx, LOG_WARNING, - "PAM_ESTABLISH_CRED not implemented"); - ret = PAM_SUCCESS; + ret = _pam_establish_cred(pamh, flags, argc, argv); break; default: ret = PAM_SYSTEM_ERR; diff -urp --exclude configure samba-3.5.4.orig/nsswitch/winbind_struct_protocol.h samba-3.5.4/nsswitch/winbind_struct_protocol.h --- samba-3.5.4.orig/nsswitch/winbind_struct_protocol.h 2010-07-27 12:51:16.531326140 +0100 +++ samba-3.5.4/nsswitch/winbind_struct_protocol.h 2010-07-27 10:55:52.971451067 +0100 @@ -50,8 +50,9 @@ typedef char fstring[FSTRING_LEN]; * 22: added WINBINDD_PING_DC * 23: added session_key to ccache_ntlm_auth response * added WINBINDD_CCACHE_SAVE + * 24: added WINBINDD_PAM_ESTABLISHCRED */ -#define WINBIND_INTERFACE_VERSION 23 +#define WINBIND_INTERFACE_VERSION 24 /* Have to deal with time_t being 4 or 8 bytes due to structure alignment. On a 64bit Linux box, we have to support a constant structure size @@ -90,6 +91,7 @@ enum winbindd_cmd { WINBINDD_PAM_AUTH_CRAP, WINBINDD_PAM_CHAUTHTOK, WINBINDD_PAM_LOGOFF, + WINBINDD_PAM_ESTABLISH_CRED, WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP, /* List various things */ @@ -300,6 +302,11 @@ struct winbindd_request { fstring krb5ccname; uid_t uid; } logoff; /* pam_winbind session module */ + struct { + fstring user; + fstring krb5_cc_type; + uid_t uid; + } est_cred; fstring sid; /* lookupsid, sid_to_[ug]id */ struct { fstring dom_name; /* lookupname */ --- samba-3.5.4.orig/source3/winbindd/winbindd.c 2010-06-18 13:01:04.000000000 +0100 +++ samba-3.5.4/source3/winbindd/winbindd.c 2010-07-27 10:39:41.900512586 +0100 @@ -424,6 +424,7 @@ static struct winbindd_dispatch_table { { WINBINDD_PAM_AUTH_CRAP, winbindd_pam_auth_crap, "AUTH_CRAP" }, { WINBINDD_PAM_CHAUTHTOK, winbindd_pam_chauthtok, "CHAUTHTOK" }, { WINBINDD_PAM_LOGOFF, winbindd_pam_logoff, "PAM_LOGOFF" }, + { WINBINDD_PAM_ESTABLISH_CRED, winbindd_pam_establish_cred, "PAM_ESTABLISH_CRED" }, { WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP, winbindd_pam_chng_pswd_auth_crap, "CHNG_PSWD_AUTH_CRAP" }, /* Enumeration functions */ diff -urp --exclude configure samba-3.5.4.orig/source3/winbindd/winbindd_cred_cache.c samba-3.5.4/source3/winbindd/winbindd_cred_cache.c --- samba-3.5.4.orig/source3/winbindd/winbindd_cred_cache.c 2010-06-18 13:01:04.000000000 +0100 +++ samba-3.5.4/source3/winbindd/winbindd_cred_cache.c 2010-07-27 12:49:31.704446045 +0100 @@ -489,7 +490,8 @@ NTSTATUS add_ccache_to_list(const char * time_t create_time, time_t ticket_end, time_t renew_until, - bool postponed_request) + bool postponed_request, + bool immediate_gain_request) { struct WINBINDD_CCACHE_ENTRY *entry = NULL; struct timeval t; @@ -551,7 +557,11 @@ NTSTATUS add_ccache_to_list(const char * } if (!entry->event) { - if (postponed_request) { + if (immediate_gain_request) { + DEBUG(10, ("add immediate gain request\n")); + t = timeval_current(); + add_krb5_ticket_gain_handler_event(entry, t); + } else if (postponed_request) { t = timeval_current_ofs(MAX(30, lp_winbind_cache_time()), 0); add_krb5_ticket_gain_handler_event(entry, t); } else { @@ -635,7 +647,10 @@ NTSTATUS add_ccache_to_list(const char * goto add_entry; } - if (postponed_request) { + if (immediate_gain_request) { + t = timeval_current(); + add_krb5_ticket_gain_handler_event(entry, t); + } else if (postponed_request) { t = timeval_current_ofs(MAX(30, lp_winbind_cache_time()), 0); add_krb5_ticket_gain_handler_event(entry, t); } else { diff -urp --exclude configure samba-3.5.4.orig/source3/winbindd/winbindd_domain.c samba-3.5.4/source3/winbindd/winbindd_domain.c --- samba-3.5.4.orig/source3/winbindd/winbindd_domain.c 2010-06-18 13:01:04.000000000 +0100 +++ samba-3.5.4/source3/winbindd/winbindd_domain.c 2010-07-27 10:39:08.445512754 +0100 @@ -55,6 +55,10 @@ static const struct winbindd_child_dispa .struct_cmd = WINBINDD_PAM_LOGOFF, .struct_fn = winbindd_dual_pam_logoff, },{ + .name = "PAM_ESTABLISH_CRED", + .struct_cmd = WINBINDD_PAM_ESTABLISH_CRED, + .struct_fn = winbindd_dual_pam_establish_cred, + },{ .name = "CHNG_PSWD_AUTH_CRAP", .struct_cmd = WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP, .struct_fn = winbindd_dual_pam_chng_pswd_auth_crap, diff -urp --exclude configure samba-3.5.4.orig/source3/winbindd/winbindd_pam.c samba-3.5.4/source3/winbindd/winbindd_pam.c --- samba-3.5.4.orig/source3/winbindd/winbindd_pam.c 2010-06-18 13:01:04.000000000 +0100 +++ samba-3.5.4/source3/winbindd/winbindd_pam.c 2010-07-27 12:20:59.172387308 +0100 @@ -661,7 +661,7 @@ static NTSTATUS winbindd_raw_kerberos_lo time(NULL), ticket_lifetime, renewal_until, - false); + false, false); if (!NT_STATUS_IS_OK(result)) { DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n", @@ -862,6 +862,76 @@ void winbindd_pam_auth(struct winbindd_c request_error(state); } +#ifdef HAVE_KRB5 +static NTSTATUS offline_add_ccache_to_list(struct winbindd_domain *domain, + struct winbindd_cli_state *state, + fstring user, fstring krb5_cc_type, + uid_t uid, bool immediate) +{ + fstring name_domain, name_user; + struct winbindd_tdc_domain *tdc_domain = NULL; + NTSTATUS result; + + parse_domain_user(state->request->data.auth.user, name_domain, name_user); + + if ((state->request->flags & WBFLAG_PAM_KRB5) && + ((tdc_domain = wcache_tdc_fetch_domain(state->mem_ctx, name_domain)) != NULL) && + ((tdc_domain->trust_type & NETR_TRUST_TYPE_UPLEVEL) || + /* used to cope with the case winbindd starting without network. */ + !strequal(tdc_domain->domain_name, tdc_domain->dns_name))) { + + const char *cc = NULL; + char *realm = NULL; + const char *principal_s = NULL; + const char *service = NULL; + bool internal_ccache = false; + + cc = generate_krb5_ccache(state->mem_ctx, krb5_cc_type, uid, + &internal_ccache); + if (cc == NULL) { + return NT_STATUS_NO_MEMORY; + } + + realm = domain->alt_name; + strupper_m(realm); + + principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm); + if (principal_s == NULL) { + return NT_STATUS_NO_MEMORY; + } + + service = talloc_asprintf(state->mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm); + if (service == NULL) { + return NT_STATUS_NO_MEMORY; + } + + if (!internal_ccache) { + + setup_return_cc_name(state, cc); + + result = add_ccache_to_list(principal_s, + cc, + service, + state->request->data.auth.user, + domain->alt_name, + uid, + time(NULL), + time(NULL) + lp_winbind_cache_time(), + time(NULL) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME, + !immediate, immediate); + + if (!NT_STATUS_IS_OK(result)) { + DEBUG(10,("winbindd_dual_pam_auth_cached: failed " + "to add ccache to list: %s\n", + nt_errstr(result))); + } + return result; + } + } + return NT_STATUS_OK; +} +#endif + static NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain, struct winbindd_cli_state *state, struct netr_SamInfo3 **info3) @@ -877,9 +947,6 @@ static NTSTATUS winbindd_dual_pam_auth_c struct netr_SamInfo3 *my_info3; time_t kickoff_time, must_change_time; bool password_good = false; -#ifdef HAVE_KRB5 - struct winbindd_tdc_domain *tdc_domain = NULL; -#endif *info3 = NULL; @@ -942,6 +1009,7 @@ static NTSTATUS winbindd_dual_pam_auth_c } if (password_good) { + uid_t uid = -1; /* User *DOES* know the password, update logon_time and reset * bad_pw_count */ @@ -987,69 +1055,17 @@ static NTSTATUS winbindd_dual_pam_auth_c goto success; } -#ifdef HAVE_KRB5 - if ((state->request->flags & WBFLAG_PAM_KRB5) && - ((tdc_domain = wcache_tdc_fetch_domain(state->mem_ctx, name_domain)) != NULL) && - ((tdc_domain->trust_type & NETR_TRUST_TYPE_UPLEVEL) || - /* used to cope with the case winbindd starting without network. */ - !strequal(tdc_domain->domain_name, tdc_domain->dns_name))) { - - uid_t uid = -1; - const char *cc = NULL; - char *realm = NULL; - const char *principal_s = NULL; - const char *service = NULL; - bool internal_ccache = false; - - uid = get_uid_from_state(state); - if (uid == -1) { - DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - cc = generate_krb5_ccache(state->mem_ctx, - state->request->data.auth.krb5_cc_type, - state->request->data.auth.uid, - &internal_ccache); - if (cc == NULL) { - return NT_STATUS_NO_MEMORY; - } - - realm = domain->alt_name; - strupper_m(realm); - - principal_s = talloc_asprintf(state->mem_ctx, "%s@%s", name_user, realm); - if (principal_s == NULL) { - return NT_STATUS_NO_MEMORY; - } - - service = talloc_asprintf(state->mem_ctx, "%s/%s@%s", KRB5_TGS_NAME, realm, realm); - if (service == NULL) { - return NT_STATUS_NO_MEMORY; - } - - if (!internal_ccache) { - - setup_return_cc_name(state, cc); - - result = add_ccache_to_list(principal_s, - cc, - service, - state->request->data.auth.user, - domain->alt_name, - uid, - time(NULL), - time(NULL) + lp_winbind_cache_time(), - time(NULL) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME, - true); - - if (!NT_STATUS_IS_OK(result)) { - DEBUG(10,("winbindd_dual_pam_auth_cached: failed " - "to add ccache to list: %s\n", - nt_errstr(result))); - } - } + uid = get_uid_from_state(state); + if (uid == -1) { + DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n")); + return NT_STATUS_INVALID_PARAMETER; } + +#ifdef HAVE_KRB5 + offline_add_ccache_to_list(domain, state, + state->request->data.auth.user, + state->request->data.auth.krb5_cc_type, + uid, false); #endif /* HAVE_KRB5 */ success: /* FIXME: we possibly should handle logon hours as well (does xp when @@ -2340,6 +2356,111 @@ process_result: return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR; } +void winbindd_pam_establish_cred(struct winbindd_cli_state *state) +{ + struct winbindd_domain *domain; + fstring name_domain, user; + uid_t caller_uid = (uid_t)-1; + uid_t request_uid = state->request->data.est_cred.uid; + + DEBUG(3, ("[%5lu]: pam establish cred %s\n", (unsigned long)state->pid, + state->request->data.est_cred.user)); + + /* Ensure null termination */ + state->request->data.est_cred.user + [sizeof(state->request->data.est_cred.user)-1]='\0'; + + state->request->data.est_cred.krb5_cc_type + [sizeof(state->request->data.est_cred.krb5_cc_type)-1]='\0'; + + if (request_uid == (gid_t)-1) { + goto failed; + } + + if (!canonicalize_username(state->request->data.est_cred.user, name_domain, user)) { + goto failed; + } + + if ((domain = find_auth_domain(state->request->flags, + name_domain)) == NULL) { + goto failed; + } + + if ((sys_getpeereid(state->sock, &caller_uid)) != 0) { + DEBUG(1,("winbindd_pam_establish_cred: failed to check peerid: %s\n", + strerror(errno))); + goto failed; + } + + switch (caller_uid) { + case -1: + goto failed; + case 0: + /* root must be able to establish creds for any user */ + state->request->data.est_cred.uid = request_uid; + break; + default: + if (caller_uid != request_uid) { + DEBUG(1,("winbindd_pam_establish_cred: caller requested invalid uid\n")); + goto failed; + } + state->request->data.est_cred.uid = caller_uid; + break; + } + + sendto_domain(state, domain); + return; + + failed: + set_auth_errors(state->response, NT_STATUS_NO_SUCH_USER); + DEBUG(5, ("Pam Establish Cred for %s returned %s " + "(PAM: %d)\n", + state->request->data.est_cred.user, + state->response->data.auth.nt_status_string, + state->response->data.auth.pam_error)); + request_error(state); + return; +} + +enum winbindd_result winbindd_dual_pam_establish_cred(struct winbindd_domain *domain, + struct winbindd_cli_state *state) +{ + NTSTATUS result = NT_STATUS_NOT_SUPPORTED; + + DEBUG(3, ("[%5lu]: pam dual establish cred %s\n", (unsigned long)state->pid, + state->request->data.est_cred.user)); + + if (!(state->request->flags & WBFLAG_PAM_KRB5)) { + result = NT_STATUS_OK; + goto process_result; + } + + if (state->request->data.est_cred.krb5_cc_type[0] == '\0') { + result = NT_STATUS_OK; + goto process_result; + } + +#ifdef HAVE_KRB5 + + if (state->request->data.est_cred.uid < 0) { + DEBUG(0,("winbindd_pam_establish_cred: invalid uid\n")); + goto process_result; + } + + result = offline_add_ccache_to_list(domain, state, + state->request->data.est_cred.user, + state->request->data.est_cred.krb5_cc_type, + state->request->data.est_cred.uid, true); +#else + result = NT_STATUS_NOT_SUPPORTED; +#endif + +process_result: + set_auth_errors(state->response, result); + + return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR; +} + /* Change user password with auth crap*/ void winbindd_pam_chng_pswd_auth_crap(struct winbindd_cli_state *state) diff -urp --exclude configure samba-3.5.4.orig/source3/winbindd/winbindd_proto.h samba-3.5.4/source3/winbindd/winbindd_proto.h --- samba-3.5.4.orig/source3/winbindd/winbindd_proto.h 2010-06-18 13:01:04.000000000 +0100 +++ samba-3.5.4/source3/winbindd/winbindd_proto.h 2010-07-27 12:13:40.782387680 +0100 @@ -221,7 +221,8 @@ NTSTATUS add_ccache_to_list(const char * time_t create_time, time_t ticket_end, time_t renew_until, - bool postponed_request); + bool postponed_request, + bool immediate_gain_request); NTSTATUS remove_ccache(const char *username); struct WINBINDD_MEMORY_CREDS *find_memory_creds_by_name(const char *username); NTSTATUS winbindd_add_memory_creds(const char *username, @@ -409,6 +410,9 @@ enum winbindd_result winbindd_dual_pam_c void winbindd_pam_logoff(struct winbindd_cli_state *state); enum winbindd_result winbindd_dual_pam_logoff(struct winbindd_domain *domain, struct winbindd_cli_state *state) ; +void winbindd_pam_establish_cred(struct winbindd_cli_state *state); +enum winbindd_result winbindd_dual_pam_establish_cred(struct winbindd_domain *domain, + struct winbindd_cli_state *state) ; void winbindd_pam_chng_pswd_auth_crap(struct winbindd_cli_state *state); enum winbindd_result winbindd_dual_pam_chng_pswd_auth_crap(struct winbindd_domain *domainSt, struct winbindd_cli_state *state);