From b397b5cb8f0a9ca5d5b2fa3349635a4cebd81779 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 4 Feb 2008 18:18:36 +0100 Subject: auth_winbind: use wbcAuthenticateUserEx() smbd doesn't need $(WBCOMMON_OBJ) anymore, it works with any libwbclient.so now and may talk to an older winbindd. metze (This used to be commit e3435930a307cff3066fe2047ed8c5c48911f001) --- source3/Makefile.in | 5 +- source3/auth/auth_util.c | 233 ++++++++++++++++++++++++++++++++++++++++++++ source3/auth/auth_winbind.c | 113 +++++++++------------ 3 files changed, 279 insertions(+), 72 deletions(-) (limited to 'source3') diff --git a/source3/Makefile.in b/source3/Makefile.in index f91bdf5c10..e1a6436365 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -640,9 +640,8 @@ SMBD_OBJ_BASE = $(PARAM_WITHOUT_REG_OBJ) $(SMBD_OBJ_SRV) $(LIBSMB_OBJ) \ $(NOTIFY_OBJ) $(GROUPDB_OBJ) $(AUTH_OBJ) \ $(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) \ $(LIBADS_OBJ) $(KRBCLIENT_OBJ) $(LIBADS_SERVER_OBJ) \ - $(REGISTRY_OBJ) $(POPT_LIB_OBJ) \ - $(BUILDOPT_OBJ) $(SMBLDAP_OBJ) $(LDB_OBJ) $(LIBNET_OBJ) \ - $(WBCOMMON_OBJ) @LIBWBCLIENT_STATIC@ + $(REGISTRY_OBJ) $(POPT_LIB_OBJ) $(BUILDOPT_OBJ) \ + $(SMBLDAP_OBJ) $(LDB_OBJ) $(LIBNET_OBJ) @LIBWBCLIENT_STATIC@ PRINTING_OBJ = printing/pcap.o printing/print_svid.o printing/print_aix.o \ printing/print_cups.o printing/print_generic.o \ diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c index ce47e94eb5..6efd31d574 100644 --- a/source3/auth/auth_util.c +++ b/source3/auth/auth_util.c @@ -1654,6 +1654,239 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx, return NT_STATUS_OK; } +/***************************************************************************** + Make a server_info struct from the wbcAuthUserInfo returned by a domain logon +******************************************************************************/ + +NTSTATUS make_server_info_wbcAuthUserInfo(TALLOC_CTX *mem_ctx, + const char *sent_nt_username, + const char *domain, + const struct wbcAuthUserInfo *info, + auth_serversupplied_info **server_info) +{ + char zeros[16]; + + NTSTATUS nt_status = NT_STATUS_OK; + char *found_username = NULL; + const char *nt_domain; + const char *nt_username; + struct samu *sam_account = NULL; + DOM_SID user_sid; + DOM_SID group_sid; + bool username_was_mapped; + uint32_t i; + + uid_t uid = (uid_t)-1; + gid_t gid = (gid_t)-1; + + auth_serversupplied_info *result; + + result = make_server_info(NULL); + if (result == NULL) { + DEBUG(4, ("make_server_info failed!\n")); + return NT_STATUS_NO_MEMORY; + } + + /* + Here is where we should check the list of + trusted domains, and verify that the SID + matches. + */ + + memcpy(&user_sid, &info->sids[0].sid, sizeof(user_sid)); + memcpy(&group_sid, &info->sids[1].sid, sizeof(group_sid)); + + if (info->account_name) { + nt_username = talloc_strdup(result, info->account_name); + } else { + /* If the server didn't give us one, just use the one we sent + * them */ + nt_username = talloc_strdup(result, sent_nt_username); + } + if (!nt_username) { + TALLOC_FREE(result); + return NT_STATUS_NO_MEMORY; + } + + if (info->domain_name) { + nt_domain = talloc_strdup(result, info->domain_name); + } else { + /* If the server didn't give us one, just use the one we sent + * them */ + nt_domain = talloc_strdup(result, domain); + } + if (!nt_domain) { + TALLOC_FREE(result); + return NT_STATUS_NO_MEMORY; + } + + /* try to fill the SAM account.. If getpwnam() fails, then try the + add user script (2.2.x behavior). + + We use the _unmapped_ username here in an attempt to provide + consistent username mapping behavior between kerberos and NTLM[SSP] + authentication in domain mode security. I.E. Username mapping + should be applied to the fully qualified username + (e.g. DOMAIN\user) and not just the login name. Yes this means we + called map_username() unnecessarily in make_user_info_map() but + that is how the current code is designed. Making the change here + is the least disruptive place. -- jerry */ + + if ( !(sam_account = samu_new( result )) ) { + TALLOC_FREE(result); + return NT_STATUS_NO_MEMORY; + } + + /* this call will try to create the user if necessary */ + + nt_status = fill_sam_account(result, nt_domain, sent_nt_username, + &found_username, &uid, &gid, sam_account, + &username_was_mapped); + + /* if we still don't have a valid unix account check for + 'map to guest = bad uid' */ + + if (!NT_STATUS_IS_OK(nt_status)) { + TALLOC_FREE( result ); + if ( lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID ) { + make_server_info_guest(server_info); + return NT_STATUS_OK; + } + return nt_status; + } + + if (!pdb_set_nt_username(sam_account, nt_username, PDB_CHANGED)) { + TALLOC_FREE(result); + return NT_STATUS_NO_MEMORY; + } + + if (!pdb_set_username(sam_account, nt_username, PDB_CHANGED)) { + TALLOC_FREE(result); + return NT_STATUS_NO_MEMORY; + } + + if (!pdb_set_domain(sam_account, nt_domain, PDB_CHANGED)) { + TALLOC_FREE(result); + return NT_STATUS_NO_MEMORY; + } + + if (!pdb_set_user_sid(sam_account, &user_sid, PDB_CHANGED)) { + TALLOC_FREE(result); + return NT_STATUS_UNSUCCESSFUL; + } + + if (!pdb_set_group_sid(sam_account, &group_sid, PDB_CHANGED)) { + TALLOC_FREE(result); + return NT_STATUS_UNSUCCESSFUL; + } + + if (!pdb_set_fullname(sam_account, info->full_name, PDB_CHANGED)) { + TALLOC_FREE(result); + return NT_STATUS_NO_MEMORY; + } + + if (!pdb_set_logon_script(sam_account, info->logon_script, PDB_CHANGED)) { + TALLOC_FREE(result); + return NT_STATUS_NO_MEMORY; + } + + if (!pdb_set_profile_path(sam_account, info->profile_path, PDB_CHANGED)) { + TALLOC_FREE(result); + return NT_STATUS_NO_MEMORY; + } + + if (!pdb_set_homedir(sam_account, info->home_directory, PDB_CHANGED)) { + TALLOC_FREE(result); + return NT_STATUS_NO_MEMORY; + } + + if (!pdb_set_dir_drive(sam_account, info->home_drive, PDB_CHANGED)) { + TALLOC_FREE(result); + return NT_STATUS_NO_MEMORY; + } + + if (!pdb_set_acct_ctrl(sam_account, info->acct_flags, PDB_CHANGED)) { + TALLOC_FREE(result); + return NT_STATUS_NO_MEMORY; + } + + if (!pdb_set_pass_last_set_time( + sam_account, + nt_time_to_unix(info->pass_last_set_time), + PDB_CHANGED)) { + TALLOC_FREE(result); + return NT_STATUS_NO_MEMORY; + } + + if (!pdb_set_pass_can_change_time( + sam_account, + nt_time_to_unix(info->pass_can_change_time), + PDB_CHANGED)) { + TALLOC_FREE(result); + return NT_STATUS_NO_MEMORY; + } + + if (!pdb_set_pass_must_change_time( + sam_account, + nt_time_to_unix(info->pass_must_change_time), + PDB_CHANGED)) { + TALLOC_FREE(result); + return NT_STATUS_NO_MEMORY; + } + + /* save this here to _net_sam_logon() doesn't fail (it assumes a + valid struct samu) */ + + result->sam_account = sam_account; + result->unix_name = talloc_strdup(result, found_username); + + result->login_server = talloc_strdup(result, info->logon_server); + + /* Fill in the unix info we found on the way */ + + result->uid = uid; + result->gid = gid; + + /* Create a 'combined' list of all SIDs we might want in the SD */ + + result->num_sids = info->num_sids - 2; + result->sids = talloc_array(result, DOM_SID, result->num_sids); + if (result->sids == NULL) { + TALLOC_FREE(result); + return NT_STATUS_NO_MEMORY; + } + + for (i=0; i < result->num_sids; i++) { + memcpy(&result->sids[i], &info->sids[i+2].sid, sizeof(result->sids[i])); + } + + /* ensure we are never given NULL session keys */ + + ZERO_STRUCT(zeros); + + if (memcmp(info->user_session_key, zeros, sizeof(zeros)) == 0) { + result->user_session_key = data_blob_null; + } else { + result->user_session_key = data_blob_talloc( + result, info->user_session_key, + sizeof(info->user_session_key)); + } + + if (memcmp(info->lm_session_key, zeros, 8) == 0) { + result->lm_session_key = data_blob_null; + } else { + result->lm_session_key = data_blob_talloc( + result, info->lm_session_key, + sizeof(info->lm_session_key)); + } + + result->was_mapped = username_was_mapped; + + *server_info = result; + + return NT_STATUS_OK; +} + /*************************************************************************** Free a user_info struct ***************************************************************************/ diff --git a/source3/auth/auth_winbind.c b/source3/auth/auth_winbind.c index b24aa3a75b..26a1b7f101 100644 --- a/source3/auth/auth_winbind.c +++ b/source3/auth/auth_winbind.c @@ -25,31 +25,6 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_AUTH -static NTSTATUS get_info3_from_ndr(TALLOC_CTX *mem_ctx, struct winbindd_response *response, NET_USER_INFO_3 *info3) -{ - uint8 *info3_ndr; - size_t len = response->length - sizeof(struct winbindd_response); - prs_struct ps; - if (len > 0) { - info3_ndr = (uint8 *)response->extra_data.data; - if (!prs_init(&ps, len, mem_ctx, UNMARSHALL)) { - return NT_STATUS_NO_MEMORY; - } - prs_copy_data_in(&ps, (char *)info3_ndr, len); - prs_set_offset(&ps,0); - if (!net_io_user_info3("", info3, &ps, 1, 3, False)) { - DEBUG(2, ("get_info3_from_ndr: could not parse info3 struct!\n")); - return NT_STATUS_UNSUCCESSFUL; - } - prs_mem_free(&ps); - - return NT_STATUS_OK; - } else { - DEBUG(2, ("get_info3_from_ndr: No info3 struct found!\n")); - return NT_STATUS_UNSUCCESSFUL; - } -} - /* Authenticate a user with a challenge/response */ static NTSTATUS check_winbind_security(const struct auth_context *auth_context, @@ -58,11 +33,11 @@ static NTSTATUS check_winbind_security(const struct auth_context *auth_context, const auth_usersupplied_info *user_info, auth_serversupplied_info **server_info) { - struct winbindd_request request; - struct winbindd_response response; - NSS_STATUS result; NTSTATUS nt_status; - NET_USER_INFO_3 info3; + wbcErr wbc_status; + struct wbcAuthUserParams params; + struct wbcAuthUserInfo *info = NULL; + struct wbcAuthErrorInfo *err = NULL; if (!user_info) { return NT_STATUS_INVALID_PARAMETER; @@ -82,36 +57,34 @@ static NTSTATUS check_winbind_security(const struct auth_context *auth_context, /* Send off request */ - ZERO_STRUCT(request); - ZERO_STRUCT(response); + params.account_name = user_info->smb_name; + params.domain_name = user_info->domain; + params.workstation_name = user_info->wksta_name; - request.flags = WBFLAG_PAM_INFO3_NDR; + params.flags = 0; + params.parameter_control= user_info->logon_parameters; - request.data.auth_crap.logon_parameters = user_info->logon_parameters; + params.level = WBC_AUTH_USER_LEVEL_RESPONSE; - fstrcpy(request.data.auth_crap.user, user_info->smb_name); - fstrcpy(request.data.auth_crap.domain, user_info->domain); - fstrcpy(request.data.auth_crap.workstation, user_info->wksta_name); + memcpy(params.password.response.challenge, + auth_context->challenge.data, + sizeof(params.password.response.challenge)); - memcpy(request.data.auth_crap.chal, auth_context->challenge.data, sizeof(request.data.auth_crap.chal)); - - request.data.auth_crap.lm_resp_len = MIN(user_info->lm_resp.length, - sizeof(request.data.auth_crap.lm_resp)); - request.data.auth_crap.nt_resp_len = MIN(user_info->nt_resp.length, - sizeof(request.data.auth_crap.nt_resp)); - - memcpy(request.data.auth_crap.lm_resp, user_info->lm_resp.data, - request.data.auth_crap.lm_resp_len); - memcpy(request.data.auth_crap.nt_resp, user_info->nt_resp.data, - request.data.auth_crap.nt_resp_len); + params.password.response.nt_length = user_info->nt_resp.length; + params.password.response.nt_data = user_info->nt_resp.data; + params.password.response.lm_length = user_info->lm_resp.length; + params.password.response.lm_data = user_info->lm_resp.data; /* we are contacting the privileged pipe */ become_root(); - result = winbindd_priv_request_response(WINBINDD_PAM_AUTH_CRAP, - &request, &response); + wbc_status = wbcAuthenticateUserEx(¶ms, &info, &err); unbecome_root(); - if ( result == NSS_STATUS_UNAVAIL ) { + if (wbc_status == WBC_ERR_NO_MEMORY) { + return NT_STATUS_NO_MEMORY; + } + + if (wbc_status == WBC_ERR_WINBIND_NOT_AVAILABLE) { struct auth_methods *auth_method = (struct auth_methods *)my_private_data; @@ -123,27 +96,29 @@ static NTSTATUS check_winbind_security(const struct auth_context *auth_context, DEBUG(0,("check_winbind_security: ERROR! my_private_data == NULL!\n")); } - nt_status = NT_STATUS(response.data.auth.nt_status); - - if (result == NSS_STATUS_SUCCESS && response.extra_data.data) { - if (NT_STATUS_IS_OK(nt_status)) { - if (NT_STATUS_IS_OK(nt_status = get_info3_from_ndr(mem_ctx, &response, &info3))) { - nt_status = make_server_info_info3(mem_ctx, - user_info->smb_name, user_info->domain, - server_info, &info3); - } - - if (NT_STATUS_IS_OK(nt_status)) { - if (user_info->was_mapped) { - (*server_info)->was_mapped = user_info->was_mapped; - } - } - } - } else if (NT_STATUS_IS_OK(nt_status)) { - nt_status = NT_STATUS_NO_LOGON_SERVERS; + if (wbc_status == WBC_ERR_AUTH_ERROR) { + nt_status = NT_STATUS(err->nt_status); + wbcFreeMemory(err); + return nt_status; + } + + if (!WBC_ERROR_IS_OK(wbc_status)) { + return NT_STATUS_LOGON_FAILURE; + } + + nt_status = make_server_info_wbcAuthUserInfo(mem_ctx, + user_info->smb_name, + user_info->domain, + info, server_info); + wbcFreeMemory(info); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + if (user_info->was_mapped) { + (*server_info)->was_mapped = user_info->was_mapped; } - SAFE_FREE(response.extra_data.data); return nt_status; } -- cgit