auth_winbind: use wbcAuthenticateUserEx()
authorStefan Metzmacher <metze@samba.org>
Mon, 4 Feb 2008 17:18:36 +0000 (18:18 +0100)
committerStefan Metzmacher <metze@samba.org>
Wed, 13 Feb 2008 12:30:16 +0000 (13:30 +0100)
smbd doesn't need $(WBCOMMON_OBJ) anymore,
it works with any libwbclient.so now
and may talk to an older winbindd.

metze

source/Makefile.in
source/auth/auth_util.c
source/auth/auth_winbind.c

index f91bdf5c1035fced923fd048b6d2ba75f942fd8b..e1a643636562be0c871c828987cbf8044dd828f0 100644 (file)
@@ -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 \
index ce47e94eb54f3279e8b2b200625bb94e665f9ff6..6efd31d574e3b6b9622db98b2065b83e43bad6f7 100644 (file)
@@ -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
 ***************************************************************************/
index b24aa3a75b3a036c0d362d073000996ff210adcc..26a1b7f10103f7f9960b749f1161ce411e2d9dab 100644 (file)
 #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(&params, &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;
 }