]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s3:auth: Split auth3_generate_session_info_pac() into functions
authorAndreas Schneider <asn@samba.org>
Thu, 11 Apr 2024 08:21:16 +0000 (10:21 +0200)
committerAndrew Bartlett <abartlet@samba.org>
Tue, 16 Apr 2024 03:58:31 +0000 (03:58 +0000)
This gets rid of the multiple goto and just have a single destructor
goto.
Best view this commit with `git show -b <sha> --color-moved=zebra`

Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source3/auth/auth_generic.c

index 7e4eea54d358cce5dc93030953ea486000eff635..b8e14649d6a6059ae39e78ba1e866160e65037da 100644 (file)
 #include "librpc/gen_ndr/dcerpc.h"
 #include "source3/lib/substitute.h"
 
-static NTSTATUS auth3_generate_session_info_pac(
-       struct auth4_context *auth_ctx,
+static NTSTATUS generate_pac_session_info(
        TALLOC_CTX *mem_ctx,
-       struct smb_krb5_context *smb_krb5_context,
-       DATA_BLOB *pac_blob,
        const char *princ_name,
-       const struct tsocket_address *remote_address,
-       uint32_t session_info_flags,
-       struct auth_session_info **session_info)
+       const char *rhost,
+       DATA_BLOB *pac_blob,
+       struct auth_session_info **psession_info)
 {
-       enum server_role server_role = lp_server_role();
-       TALLOC_CTX *tmp_ctx;
-       bool is_mapped;
-       bool is_guest;
-       char *ntuser;
-       char *ntdomain;
-       char *username;
-       const char *rhost;
-       struct passwd *pw;
        NTSTATUS status;
+       struct wbcAuthUserParams params = {0};
+       struct wbcAuthUserInfo *info = NULL;
+       struct wbcAuthErrorInfo *err = NULL;
+       struct auth_serversupplied_info *server_info = NULL;
+       char *original_user_name = NULL;
+       char *p = NULL;
+       wbcErr wbc_err;
 
-       tmp_ctx = talloc_new(mem_ctx);
-       if (!tmp_ctx) {
+       /*
+        * Let winbind decode the PAC.
+        * This will also store the user
+        * data in the netsamlogon cache.
+        *
+        * This used to be a cache prime
+        * optimization, but now we delegate
+        * all logic to winbindd, as we require
+        * winbindd as domain member anyway.
+        */
+       params.level = WBC_AUTH_USER_LEVEL_PAC;
+       params.password.pac.data = pac_blob->data;
+       params.password.pac.length = pac_blob->length;
+
+       /* we are contacting the privileged pipe */
+       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_SUCCESS:
+               break;
+       case WBC_ERR_WINBIND_NOT_AVAILABLE:
+               status = NT_STATUS_NO_LOGON_SERVERS;
+               DBG_ERR("winbindd not running - "
+                       "but required as domain member: %s\n",
+                       nt_errstr(status));
+               return status;
+       case WBC_ERR_AUTH_ERROR:
+               wbcFreeMemory(err);
+               return NT_STATUS(err->nt_status);
+       case WBC_ERR_NO_MEMORY:
                return NT_STATUS_NO_MEMORY;
+       default:
+               return NT_STATUS_LOGON_FAILURE;
        }
 
-       if (tsocket_address_is_inet(remote_address, "ip")) {
-               rhost = tsocket_address_inet_addr_string(remote_address,
-                                                        tmp_ctx);
-               if (rhost == NULL) {
-                       status = NT_STATUS_NO_MEMORY;
-                       goto done;
-               }
-       } else {
-               rhost = "127.0.0.1";
+       status = make_server_info_wbcAuthUserInfo(mem_ctx,
+                                                 info->account_name,
+                                                 info->domain_name,
+                                                 info,
+                                                 &server_info);
+       wbcFreeMemory(info);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("make_server_info_wbcAuthUserInfo failed: %s\n",
+                          nt_errstr(status)));
+               return status;
        }
 
-       if (server_role != ROLE_STANDALONE) {
-               struct wbcAuthUserParams params = {0};
-               struct wbcAuthUserInfo *info = NULL;
-               struct wbcAuthErrorInfo *err = NULL;
-               struct auth_serversupplied_info *server_info = NULL;
-               char *original_user_name = NULL;
-               char *p = NULL;
-               wbcErr wbc_err;
-
-               if (pac_blob == NULL) {
-                       /*
-                        * This should already be caught at the main
-                        * gensec layer, but better check twice
-                        */
-                       status = NT_STATUS_INTERNAL_ERROR;
-                       goto done;
-               }
+       /* We skip doing this step if the caller asked us not to */
+       if (!(server_info->guest)) {
+               const char *unix_username = server_info->unix_name;
 
-               /*
-                * Let winbind decode the PAC.
-                * This will also store the user
-                * data in the netsamlogon cache.
-                *
-                * This used to be a cache prime
-                * optimization, but now we delegate
-                * all logic to winbindd, as we require
-                * winbindd as domain member anyway.
-                */
-               params.level = WBC_AUTH_USER_LEVEL_PAC;
-               params.password.pac.data = pac_blob->data;
-               params.password.pac.length = pac_blob->length;
-
-               /* we are contacting the privileged pipe */
+               /* We might not be root if we are an RPC call */
                become_root();
-               wbc_err = wbcAuthenticateUserEx(&params, &info, &err);
+               status = smb_pam_accountcheck(unix_username, rhost);
                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_SUCCESS:
-                       break;
-               case WBC_ERR_WINBIND_NOT_AVAILABLE:
-                       status = NT_STATUS_NO_LOGON_SERVERS;
-                       DBG_ERR("winbindd not running - "
-                               "but required as domain member: %s\n",
-                               nt_errstr(status));
-                       goto done;
-               case WBC_ERR_AUTH_ERROR:
-                       status = NT_STATUS(err->nt_status);
-                       wbcFreeMemory(err);
-                       goto done;
-               case WBC_ERR_NO_MEMORY:
-                       status = NT_STATUS_NO_MEMORY;
-                       goto done;
-               default:
-                       status = NT_STATUS_LOGON_FAILURE;
-                       goto done;
-               }
-
-               status = make_server_info_wbcAuthUserInfo(tmp_ctx,
-                                                         info->account_name,
-                                                         info->domain_name,
-                                                         info,
-                                                         &server_info);
-               wbcFreeMemory(info);
                if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(10, ("make_server_info_wbcAuthUserInfo failed: %s\n",
-                                  nt_errstr(status)));
-                       goto done;
-               }
-
-               /* We skip doing this step if the caller asked us not to */
-               if (!(server_info->guest)) {
-                       const char *unix_username = server_info->unix_name;
-
-                       /* We might not be root if we are an RPC call */
-                       become_root();
-                       status = smb_pam_accountcheck(unix_username, rhost);
-                       unbecome_root();
-
-                       if (!NT_STATUS_IS_OK(status)) {
-                               DEBUG(3, ("check_ntlm_password:  PAM Account for user [%s] "
+                       DEBUG(3, ("check_ntlm_password:  PAM Account for user [%s] "
                                          "FAILED with error %s\n",
                                          unix_username, nt_errstr(status)));
-                               goto done;
-                       }
-
-                       DEBUG(5, ("check_ntlm_password:  PAM Account for user [%s] "
-                                 "succeeded\n", unix_username));
+                       return status;
                }
 
-               DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name));
+               DEBUG(5, ("check_ntlm_password:  PAM Account for user [%s] "
+                         "succeeded\n", unix_username));
+       }
+
+       DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name));
 
-               p = strchr_m(princ_name, '@');
-               if (!p) {
-                       DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
+       p = strchr_m(princ_name, '@');
+       if (!p) {
+               DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
                                  princ_name));
-                       status = NT_STATUS_LOGON_FAILURE;
-                       goto done;
-               }
+               return NT_STATUS_LOGON_FAILURE;
+       }
 
-               original_user_name = talloc_strndup(tmp_ctx,
-                                                   princ_name,
-                                                   p - princ_name);
-               if (original_user_name == NULL) {
-                       status = NT_STATUS_NO_MEMORY;
-                       goto done;
-               }
+       original_user_name = talloc_strndup(mem_ctx,
+                                           princ_name,
+                                           p - princ_name);
+       if (original_user_name == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
 
-               status = create_local_token(mem_ctx,
-                                           server_info,
-                                           NULL,
-                                           original_user_name,
-                                           session_info);
-               if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(10, ("create_local_token failed: %s\n",
+       status = create_local_token(
+               mem_ctx, server_info, NULL, original_user_name, psession_info);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("create_local_token failed: %s\n",
                                   nt_errstr(status)));
-                       goto done;
-               }
-
-               goto session_info_ready;
+               return status;
        }
 
-       /* This is the standalone legacy code path */
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS generate_krb5_session_info(
+       TALLOC_CTX *mem_ctx,
+       const char *princ_name,
+       const char *rhost,
+       DATA_BLOB *pac_blob,
+       struct auth_session_info **psession_info)
+{
+       bool is_mapped = false;
+       bool is_guest = false;
+       char *ntuser = NULL;
+       char *ntdomain = NULL;
+       char *username = NULL;
+       struct passwd *pw = NULL;
+       NTSTATUS status;
 
        if (pac_blob != NULL) {
                /*
@@ -213,14 +179,11 @@ static NTSTATUS auth3_generate_session_info_pac(
                 */
                status = NT_STATUS_BAD_TOKEN_TYPE;
                DBG_WARNING("Unexpected PAC for [%s] in standalone mode - %s\n",
-                           princ_name,
-                           nt_errstr(status));
-               if (!NT_STATUS_IS_OK(status)) {
-                       goto done;
-               }
+                           princ_name, nt_errstr(status));
+               return status;
        }
 
-       status = get_user_from_kerberos_info(tmp_ctx,
+       status = get_user_from_kerberos_info(mem_ctx,
                                             rhost,
                                             princ_name,
                                             &is_mapped,
@@ -231,10 +194,8 @@ static NTSTATUS auth3_generate_session_info_pac(
                                             &pw);
        if (!NT_STATUS_IS_OK(status)) {
                DBG_NOTICE("Failed to map kerberos principal to system user "
-                          "(%s)\n",
-                          nt_errstr(status));
-               status = NT_STATUS_ACCESS_DENIED;
-               goto done;
+                         "(%s)\n", nt_errstr(status));
+               return NT_STATUS_ACCESS_DENIED;
        }
 
        status = make_session_info_krb5(mem_ctx,
@@ -244,31 +205,88 @@ static NTSTATUS auth3_generate_session_info_pac(
                                        pw,
                                        is_guest,
                                        is_mapped,
-                                       session_info);
+                                       psession_info);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("Failed to map kerberos pac to server info (%s)\n",
                          nt_errstr(status)));
                status = nt_status_squash(status);
+               return status;
+       }
+
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS auth3_generate_session_info_pac(
+       struct auth4_context *auth_ctx,
+       TALLOC_CTX *mem_ctx,
+       struct smb_krb5_context *smb_krb5_context,
+       DATA_BLOB *pac_blob,
+       const char *princ_name,
+       const struct tsocket_address *remote_address,
+       uint32_t session_info_flags,
+       struct auth_session_info **psession_info)
+{
+       enum server_role server_role = lp_server_role();
+       struct auth_session_info *session_info = NULL;
+       const char *rhost;
+       NTSTATUS status;
+       TALLOC_CTX *tmp_ctx = NULL;
+
+       tmp_ctx = talloc_new(mem_ctx);
+       if (tmp_ctx == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if (tsocket_address_is_inet(remote_address, "ip")) {
+               rhost = tsocket_address_inet_addr_string(remote_address,
+                                                        tmp_ctx);
+               if (rhost == NULL) {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto done;
+               }
+       } else {
+               rhost = "127.0.0.1";
+       }
+
+       switch (server_role) {
+       case ROLE_DOMAIN_MEMBER:
+       case ROLE_DOMAIN_BDC:
+       case ROLE_DOMAIN_PDC:
+       case ROLE_ACTIVE_DIRECTORY_DC:
+       case ROLE_IPA_DC:
+               /* This requires a complete MS-PAC including logon_info */
+               status = generate_pac_session_info(
+                       tmp_ctx, princ_name, rhost, pac_blob, &session_info);
+               break;
+       case ROLE_STANDALONE:
+               status = generate_krb5_session_info(
+                       tmp_ctx, princ_name, rhost, pac_blob, &session_info);
+               break;
+       default:
+               status = NT_STATUS_INVALID_PARAMETER;
                goto done;
        }
 
-session_info_ready:
+       if (!NT_STATUS_IS_OK(status)) {
+               goto done;
+       }
 
        /* setup the string used by %U */
-       set_current_user_info((*session_info)->unix_info->sanitized_username,
-                             (*session_info)->unix_info->unix_name,
-                             (*session_info)->info->domain_name);
+       set_current_user_info(session_info->unix_info->sanitized_username,
+                             session_info->unix_info->unix_name,
+                             session_info->info->domain_name);
 
        /* reload services so that the new %U is taken into account */
        lp_load_with_shares(get_dyn_CONFIGFILE());
 
        DEBUG(5, (__location__ "OK: user: %s domain: %s client: %s\n",
-                 (*session_info)->info->account_name,
-                 (*session_info)->info->domain_name,
+                 session_info->info->account_name,
+                 session_info->info->domain_name,
                  rhost));
 
-       status = NT_STATUS_OK;
+       *psession_info = talloc_move(mem_ctx, &session_info);
 
+       status = NT_STATUS_OK;
 done:
        TALLOC_FREE(tmp_ctx);
        return status;