s3: auth: Use wbcAuthenticateUserEx to prime the caches.
[metze/samba/wip.git] / source3 / auth / auth_generic.c
index 6b146a084bc5a2c00c4469af3e9d4ce63a88ff5c..f9b918496fd381f15dd7c1c13a84f73651a8d054 100644 (file)
@@ -28,6 +28,7 @@
 #include "lib/param/param.h"
 #ifdef HAVE_KRB5
 #include "auth/kerberos/pac_utils.h"
+#include "nsswitch/libwbclient/wbclient.h"
 #endif
 #include "librpc/crypto/gse.h"
 #include "auth/credentials/credentials.h"
@@ -45,6 +46,7 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx,
 {
        TALLOC_CTX *tmp_ctx;
        struct PAC_LOGON_INFO *logon_info = NULL;
+       struct netr_SamInfo3 *info3_copy = NULL;
        bool is_mapped;
        bool is_guest;
        char *ntuser;
@@ -62,6 +64,51 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx,
 
        if (pac_blob) {
 #ifdef HAVE_KRB5
+               struct wbcAuthUserParams params = {};
+               struct wbcAuthUserInfo *info = NULL;
+               struct wbcAuthErrorInfo *err = NULL;
+               wbcErr wbc_err;
+
+               /*
+                * Let winbind decode the PAC.
+                * This will also store the user
+                * data in the netsamlogon cache.
+                *
+                * We need to do this *before* we
+                * call get_user_from_kerberos_info()
+                * as that does a user lookup that
+                * expects info in the netsamlogon cache.
+                *
+                * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=11259
+                */
+               params.level = WBC_AUTH_USER_LEVEL_PAC;
+               params.password.pac.data = pac_blob->data;
+               params.password.pac.length = pac_blob->length;
+
+               become_root();
+               wbc_err = wbcAuthenticateUserEx(&params, &info, &err);
+               unbecome_root();
+
+               /*
+                * As this is merely a cache prime
+                * WBC_ERR_WINBIND_NOT_AVAILABLE
+                * is not a fatal error, treat it
+                * as success.
+                */
+
+               switch (wbc_err) {
+                       case WBC_ERR_WINBIND_NOT_AVAILABLE:
+                       case WBC_ERR_SUCCESS:
+                               break;
+                       case WBC_ERR_AUTH_ERROR:
+                               status = NT_STATUS(err->nt_status);
+                               wbcFreeMemory(err);
+                               goto done;
+                       default:
+                               status = NT_STATUS_LOGON_FAILURE;
+                               goto done;
+               }
+
                status = kerberos_pac_logon_info(tmp_ctx, *pac_blob, NULL, NULL,
                                                 NULL, NULL, 0, &logon_info);
 #else
@@ -94,26 +141,31 @@ static NTSTATUS auth3_generate_session_info_pac(struct auth4_context *auth_ctx,
                                             &ntuser, &ntdomain,
                                             &username, &pw);
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("Failed to map kerberos principal to system user "
-                         "(%s)\n", nt_errstr(status)));
+               DBG_NOTICE("Failed to map kerberos principal to system user "
+                         "(%s)\n", nt_errstr(status));
                status = NT_STATUS_ACCESS_DENIED;
                goto done;
        }
 
-       /* save the PAC data if we have it */
+       /* Get the info3 from the PAC data if we have it */
        if (logon_info) {
-               netsamlogon_cache_store(ntuser, &logon_info->info3);
+               status = create_info3_from_pac_logon_info(tmp_ctx,
+                                       logon_info,
+                                       &info3_copy);
+               if (!NT_STATUS_IS_OK(status)) {
+                       goto done;
+               }
        }
 
        /* setup the string used by %U */
        sub_set_smb_name(username);
 
        /* reload services so that the new %U is taken into account */
-       lp_load(get_dyn_CONFIGFILE(), false, false, true, true);
+       lp_load_with_shares(get_dyn_CONFIGFILE());
 
        status = make_session_info_krb5(mem_ctx,
                                        ntuser, ntdomain, username, pw,
-                                       &logon_info->info3, is_guest, is_mapped, NULL /* No session key for now, caller will sort it out */,
+                                       info3_copy, is_guest, is_mapped, NULL /* No session key for now, caller will sort it out */,
                                        session_info);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("Failed to map kerberos pac to server info (%s)\n",