From 7d18d058a1203ab7079f9dbdf37962803064d699 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 9 Jan 2010 20:20:36 +0100 Subject: s3: Add wbinfo --ccache-save With this command you can give winbind your password for later use by the automatic ntlm_auth --- nsswitch/libwbclient/wbc_pam.c | 18 ++++++++ nsswitch/libwbclient/wbclient.h | 10 +++++ nsswitch/wbinfo.c | 46 ++++++++++++++++++++ nsswitch/winbind_struct_protocol.h | 9 +++- source3/winbindd/winbindd.c | 1 + source3/winbindd/winbindd_ccache_access.c | 72 +++++++++++++++++++++++++++++++ source3/winbindd/winbindd_domain.c | 4 ++ source3/winbindd/winbindd_proto.h | 3 ++ 8 files changed, 162 insertions(+), 1 deletion(-) diff --git a/nsswitch/libwbclient/wbc_pam.c b/nsswitch/libwbclient/wbc_pam.c index 1f76c0a143..087db2e6c6 100644 --- a/nsswitch/libwbclient/wbc_pam.c +++ b/nsswitch/libwbclient/wbc_pam.c @@ -1119,3 +1119,21 @@ wbcErr wbcCredentialCache(struct wbcCredentialCacheParams *params, { return WBC_ERR_NOT_IMPLEMENTED; } + +/* Authenticate a user with cached credentials */ +wbcErr wbcCredentialSave(const char *user, const char *password) +{ + struct winbindd_request request; + struct winbindd_response response; + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + strncpy(request.data.ccache_save.user, user, + sizeof(request.data.ccache_save.user)-1); + strncpy(request.data.ccache_save.pass, password, + sizeof(request.data.ccache_save.pass)-1); + request.data.ccache_save.uid = getuid(); + + return wbcRequestResponse(WINBINDD_CCACHE_SAVE, &request, &response); +} diff --git a/nsswitch/libwbclient/wbclient.h b/nsswitch/libwbclient/wbclient.h index 33a4ace75c..06f0713c86 100644 --- a/nsswitch/libwbclient/wbclient.h +++ b/nsswitch/libwbclient/wbclient.h @@ -1164,6 +1164,16 @@ wbcErr wbcCredentialCache(struct wbcCredentialCacheParams *params, struct wbcCredentialCacheInfo **info, struct wbcAuthErrorInfo **error); +/** + * @brief Save a password with winbind for doing wbcCredentialCache() later + * + * @param *user Username + * @param *password Password + * + * @return #wbcErr + **/ +wbcErr wbcCredentialSave(const char *user, const char *password); + /********************************************************** * Resolve functions **********************************************************/ diff --git a/nsswitch/wbinfo.c b/nsswitch/wbinfo.c index 45d8684bad..a43ce8f4c9 100644 --- a/nsswitch/wbinfo.c +++ b/nsswitch/wbinfo.c @@ -1530,6 +1530,43 @@ static bool wbinfo_auth_crap(char *username, bool use_ntlmv2, bool use_lanman) return WBC_ERROR_IS_OK(wbc_status); } +/* Save creds with winbind */ + +static bool wbinfo_ccache_save(char *username) +{ + wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE; + char *s = NULL; + char *p = NULL; + char *password = NULL; + char *name = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + + s = talloc_strdup(frame, username); + if (s == NULL) { + return false; + } + + p = strchr(s, '%'); + if (p != NULL) { + *p = 0; + p++; + password = talloc_strdup(frame, p); + } else { + password = wbinfo_prompt_pass(frame, NULL, username); + } + + name = s; + + wbc_status = wbcCredentialSave(name, password); + + d_printf("saving creds %s\n", + WBC_ERROR_IS_OK(wbc_status) ? "succeeded" : "failed"); + + TALLOC_FREE(frame); + + return WBC_ERROR_IS_OK(wbc_status); +} + #ifdef WITH_FAKE_KASERVER /* Authenticate a user with a plaintext password and set a token */ @@ -1736,6 +1773,7 @@ enum { OPT_ONLINESTATUS, OPT_CHANGE_USER_PASSWORD, OPT_PING_DC, + OPT_CCACHE_SAVE, OPT_SID_TO_FULLNAME, OPT_NTLMV2, OPT_LANMAN @@ -1805,6 +1843,9 @@ int main(int argc, char **argv, char **envp) { "user-sids", 0, POPT_ARG_STRING, &string_arg, OPT_USERSIDS, "Get user group sids for user SID", "SID" }, { "authenticate", 'a', POPT_ARG_STRING, &string_arg, 'a', "authenticate user", "user%password" }, { "set-auth-user", 0, POPT_ARG_STRING, &string_arg, OPT_SET_AUTH_USER, "Store user and password used by winbindd (root only)", "user%password" }, + { "ccache-save", 0, POPT_ARG_STRING, &string_arg, + OPT_CCACHE_SAVE, "Store user and password for ccache " + "operation", "user%password" }, { "getdcname", 0, POPT_ARG_STRING, &string_arg, OPT_GETDCNAME, "Get a DC name for a foreign domain", "domainname" }, { "dsgetdcname", 0, POPT_ARG_STRING, &string_arg, OPT_DSGETDCNAME, "Find a DC for a domain", "domainname" }, @@ -2189,6 +2230,11 @@ int main(int argc, char **argv, char **envp) wbinfo_get_auth_user(); goto done; break; + case OPT_CCACHE_SAVE: + if (!wbinfo_ccache_save(string_arg)) { + goto done; + } + break; case OPT_GETDCNAME: if (!wbinfo_getdcname(string_arg)) { goto done; diff --git a/nsswitch/winbind_struct_protocol.h b/nsswitch/winbind_struct_protocol.h index 4d27d5283c..7790155f25 100644 --- a/nsswitch/winbind_struct_protocol.h +++ b/nsswitch/winbind_struct_protocol.h @@ -48,8 +48,9 @@ typedef char fstring[FSTRING_LEN]; * 21: added WINBINDD_GETPWSID * added WINBINDD_GETSIDALIASES * 22: added WINBINDD_PING_DC + * 23: added WINBINDD_CCACHE_SAVE */ -#define WINBIND_INTERFACE_VERSION 22 +#define WINBIND_INTERFACE_VERSION 23 /* 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 @@ -177,6 +178,7 @@ enum winbindd_cmd { /* Complete the challenge phase of the NTLM authentication protocol using cached password. */ WINBINDD_CCACHE_NTLMAUTH, + WINBINDD_CCACHE_SAVE, WINBINDD_NUM_CMDS }; @@ -334,6 +336,11 @@ struct winbindd_request { uint32_t initial_blob_len; /* blobs in extra_data */ uint32_t challenge_blob_len; } ccache_ntlm_auth; + struct { + uid_t uid; + fstring user; + fstring pass; + } ccache_save; struct { fstring domain_name; fstring domain_guid; diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c index f6f4a8fee7..c0b42b811d 100644 --- a/source3/winbindd/winbindd.c +++ b/source3/winbindd/winbindd.c @@ -451,6 +451,7 @@ static struct winbindd_dispatch_table { /* Credential cache access */ { WINBINDD_CCACHE_NTLMAUTH, winbindd_ccache_ntlm_auth, "NTLMAUTH" }, + { WINBINDD_CCACHE_SAVE, winbindd_ccache_save, "CCACHE_SAVE" }, /* WINS functions */ diff --git a/source3/winbindd/winbindd_ccache_access.c b/source3/winbindd/winbindd_ccache_access.c index 2f71aaae52..b0efc6474b 100644 --- a/source3/winbindd/winbindd_ccache_access.c +++ b/source3/winbindd/winbindd_ccache_access.c @@ -278,3 +278,75 @@ enum winbindd_result winbindd_dual_ccache_ntlm_auth(struct winbindd_domain *doma process_result: return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR; } + +void winbindd_ccache_save(struct winbindd_cli_state *state) +{ + struct winbindd_domain *domain; + fstring name_domain, name_user; + + /* 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 passord 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_ntlm_auth.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; + } + + 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; + } + + sendto_domain(state, domain); +} + +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; +} diff --git a/source3/winbindd/winbindd_domain.c b/source3/winbindd/winbindd_domain.c index 45da57e132..2cb6e31a9e 100644 --- a/source3/winbindd/winbindd_domain.c +++ b/source3/winbindd/winbindd_domain.c @@ -66,6 +66,10 @@ static const struct winbindd_child_dispatch_table domain_dispatch_table[] = { .name = "CCACHE_NTLM_AUTH", .struct_cmd = WINBINDD_CCACHE_NTLMAUTH, .struct_fn = winbindd_dual_ccache_ntlm_auth, + },{ + .name = "CCACHE_SAVE", + .struct_cmd = WINBINDD_CCACHE_SAVE, + .struct_fn = winbindd_dual_ccache_save, },{ .name = "NDRCMD", .struct_cmd = WINBINDD_DUAL_NDRCMD, diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index 93d5748c49..f6c4dade4a 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -180,6 +180,9 @@ void wcache_store_ndr(struct winbindd_domain *domain, uint32_t opnum, void winbindd_ccache_ntlm_auth(struct winbindd_cli_state *state); enum winbindd_result winbindd_dual_ccache_ntlm_auth(struct winbindd_domain *domain, struct winbindd_cli_state *state); +void winbindd_ccache_save(struct winbindd_cli_state *state); +enum winbindd_result winbindd_dual_ccache_save( + struct winbindd_domain *domain, struct winbindd_cli_state *state); /* The following definitions come from winbindd/winbindd_cm.c */ -- cgit