s4:rpc_server: Fix code spelling
[samba.git] / source4 / rpc_server / netlogon / dcerpc_netlogon.c
index a9b16e5c42a3549156eaa2099d390501d2ec621b..d77d524cb28cc78e86ab0c413511ef1010ba7e46 100644 (file)
@@ -42,6 +42,7 @@
 #include "librpc/gen_ndr/ndr_irpc.h"
 #include "librpc/gen_ndr/ndr_winbind.h"
 #include "librpc/gen_ndr/ndr_winbind_c.h"
+#include "librpc/rpc/server/netlogon/schannel_util.h"
 #include "lib/socket/netif.h"
 #include "lib/util/util_str_escape.h"
 #include "lib/param/loadparm.h"
@@ -68,9 +69,11 @@ static NTSTATUS dcesrv_interface_netlogon_bind(struct dcesrv_connection_context
        bool global_reject_md5_client = lpcfg_reject_md5_clients(lp_ctx);
        int schannel = lpcfg_server_schannel(lp_ctx);
        bool schannel_global_required = (schannel == true);
+       bool global_require_seal = lpcfg_server_schannel_require_seal(lp_ctx);
        static bool warned_global_nt4_once = false;
        static bool warned_global_md5_once = false;
        static bool warned_global_schannel_once = false;
+       static bool warned_global_seal_once = false;
 
        if (global_allow_nt4_crypto && !warned_global_nt4_once) {
                /*
@@ -102,6 +105,16 @@ static NTSTATUS dcesrv_interface_netlogon_bind(struct dcesrv_connection_context
                warned_global_schannel_once = true;
        }
 
+       if (!global_require_seal && !warned_global_seal_once) {
+               /*
+                * We want admins to notice their misconfiguration!
+                */
+               D_ERR("CVE-2022-38023 (and others): "
+                     "Please configure 'server schannel require seal = yes' (the default), "
+                     "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
+               warned_global_seal_once = true;
+       }
+
        return dcesrv_interface_bind_reject_connect(context, iface);
 }
 
@@ -204,7 +217,7 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_check_downgrade(
        reject_des_client = !allow_nt4_crypto;
 
        /*
-        * If weak cryto is disabled, do not announce that we support RC4.
+        * If weak crypto is disabled, do not announce that we support RC4.
         */
        if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_DISALLOWED) {
                /* Without RC4 and DES we require AES */
@@ -481,7 +494,7 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper(
                       NETLOGON_NEG_AUTHENTICATED_RPC;
 
        /*
-        * If weak cryto is disabled, do not announce that we support RC4.
+        * If weak crypto is disabled, do not announce that we support RC4.
         */
        if (lpcfg_weak_crypto(dce_call->conn->dce_ctx->lp_ctx) ==
            SAMBA_WEAK_CRYPTO_DISALLOWED) {
@@ -826,7 +839,9 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(
                status,
                lpcfg_workgroup(dce_call->conn->dce_ctx->lp_ctx),
                trust_account_in_db,
-               sid);
+               sid,
+               NULL /* client_audit_info */,
+               NULL /* server_audit_info */);
 
        return status;
 }
@@ -877,208 +892,6 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate2(struct dcesrv_call_state *dce_ca
        return dcesrv_netr_ServerAuthenticate3(dce_call, mem_ctx, &r3);
 }
 
-static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call,
-                                          const struct netlogon_creds_CredentialState *creds,
-                                          enum dcerpc_AuthType auth_type,
-                                          enum dcerpc_AuthLevel auth_level,
-                                          uint16_t opnum)
-{
-       struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
-       TALLOC_CTX *frame = talloc_stackframe();
-       NTSTATUS nt_status;
-       int schannel = lpcfg_server_schannel(lp_ctx);
-       bool schannel_global_required = (schannel == true);
-       bool schannel_required = schannel_global_required;
-       const char *explicit_opt = NULL;
-       int CVE_2020_1472_warn_level = lpcfg_parm_int(lp_ctx, NULL,
-               "CVE_2020_1472", "warn_about_unused_debug_level", DBGLVL_ERR);
-       int CVE_2020_1472_error_level = lpcfg_parm_int(lp_ctx, NULL,
-               "CVE_2020_1472", "error_debug_level", DBGLVL_ERR);
-       unsigned int dbg_lvl = DBGLVL_DEBUG;
-       const char *opname = "<unknown>";
-       const char *reason = "<unknown>";
-
-       if (opnum < ndr_table_netlogon.num_calls) {
-               opname = ndr_table_netlogon.calls[opnum].name;
-       }
-
-       if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
-               if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
-                       reason = "WITH SEALED";
-               } else if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
-                       reason = "WITH SIGNED";
-               } else {
-                       smb_panic("Schannel without SIGN/SEAL");
-               }
-       } else {
-               reason = "WITHOUT";
-       }
-
-       /*
-        * We don't use lpcfg_parm_bool(), as we
-        * need the explicit_opt pointer in order to
-        * adjust the debug messages.
-        */
-       explicit_opt = lpcfg_get_parametric(lp_ctx,
-                                           NULL,
-                                           "server require schannel",
-                                           creds->account_name);
-       if (explicit_opt != NULL) {
-               schannel_required = lp_bool(explicit_opt);
-       }
-
-       if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
-               nt_status = NT_STATUS_OK;
-
-               if (explicit_opt != NULL && !schannel_required) {
-                       dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_warn_level);
-               } else if (!schannel_required) {
-                       dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO);
-               }
-
-               DEBUG(dbg_lvl, (
-                     "CVE-2020-1472(ZeroLogon): "
-                     "%s request (opnum[%u]) %s schannel from "
-                     "client_account[%s] client_computer_name[%s] %s\n",
-                     opname, opnum, reason,
-                     log_escape(frame, creds->account_name),
-                     log_escape(frame, creds->computer_name),
-                     nt_errstr(nt_status)));
-
-               if (explicit_opt != NULL && !schannel_required) {
-                       DEBUG(CVE_2020_1472_warn_level, (
-                             "CVE-2020-1472(ZeroLogon): "
-                             "Option 'server require schannel:%s = no' not needed for '%s'!\n",
-                             log_escape(frame, creds->account_name),
-                             log_escape(frame, creds->computer_name)));
-               }
-
-               TALLOC_FREE(frame);
-               return nt_status;
-       }
-
-       if (schannel_required) {
-               nt_status = NT_STATUS_ACCESS_DENIED;
-
-               if (explicit_opt != NULL) {
-                       dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE);
-               } else {
-                       dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level);
-               }
-
-               DEBUG(dbg_lvl, (
-                     "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: "
-                     "%s request (opnum[%u]) %s schannel from "
-                     "client_account[%s] client_computer_name[%s] %s\n",
-                     opname, opnum, reason,
-                     log_escape(frame, creds->account_name),
-                     log_escape(frame, creds->computer_name),
-                     nt_errstr(nt_status)));
-               if (explicit_opt != NULL) {
-                       D_NOTICE("CVE-2020-1472(ZeroLogon): Option "
-                               "'server require schannel:%s = yes' "
-                               "rejects access for client.\n",
-                               log_escape(frame, creds->account_name));
-               } else {
-                       DEBUG(CVE_2020_1472_error_level, (
-                             "CVE-2020-1472(ZeroLogon): Check if option "
-                             "'server require schannel:%s = no' "
-                             "might be needed for a legacy client.\n",
-                             log_escape(frame, creds->account_name)));
-               }
-               TALLOC_FREE(frame);
-               return nt_status;
-       }
-
-       nt_status = NT_STATUS_OK;
-
-       if (explicit_opt != NULL) {
-               dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO);
-       } else {
-               dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level);
-       }
-
-       DEBUG(dbg_lvl, (
-             "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: "
-             "%s request (opnum[%u]) %s schannel from "
-             "client_account[%s] client_computer_name[%s] %s\n",
-             opname, opnum, reason,
-             log_escape(frame, creds->account_name),
-             log_escape(frame, creds->computer_name),
-             nt_errstr(nt_status)));
-
-       if (explicit_opt != NULL) {
-               D_INFO("CVE-2020-1472(ZeroLogon): Option "
-                      "'server require schannel:%s = no' "
-                      "still needed for '%s'!\n",
-                      log_escape(frame, creds->account_name),
-                      log_escape(frame, creds->computer_name));
-       } else {
-               /*
-                * admins should set
-                * server require schannel:COMPUTER$ = no
-                * in order to avoid the level 0 messages.
-                * Over time they can switch the global value
-                * to be strict.
-                */
-               DEBUG(CVE_2020_1472_error_level, (
-                     "CVE-2020-1472(ZeroLogon): "
-                     "Please use 'server require schannel:%s = no' "
-                     "for '%s' to avoid this warning!\n",
-                     log_escape(frame, creds->account_name),
-                     log_escape(frame, creds->computer_name)));
-       }
-
-       TALLOC_FREE(frame);
-       return NT_STATUS_OK;
-}
-
-/*
- * NOTE: The following functions are nearly identical to the ones available in
- * source3/rpc_server/srv_nelog_nt.c
- * The reason we keep 2 copies is that they use different structures to
- * represent the auth_info and the decrpc pipes.
- */
-static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dce_call,
-                                                   TALLOC_CTX *mem_ctx,
-                                                   const char *computer_name,
-                                                   struct netr_Authenticator *received_authenticator,
-                                                   struct netr_Authenticator *return_authenticator,
-                                                   struct netlogon_creds_CredentialState **creds_out)
-{
-       NTSTATUS nt_status;
-       struct netlogon_creds_CredentialState *creds = NULL;
-       enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
-       enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
-
-       dcesrv_call_auth_info(dce_call, &auth_type, &auth_level);
-
-       nt_status = schannel_check_creds_state(mem_ctx,
-                                              dce_call->conn->dce_ctx->lp_ctx,
-                                              computer_name,
-                                              received_authenticator,
-                                              return_authenticator,
-                                              &creds);
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               ZERO_STRUCTP(return_authenticator);
-               return nt_status;
-       }
-
-       nt_status = dcesrv_netr_check_schannel(dce_call,
-                                              creds,
-                                              auth_type,
-                                              auth_level,
-                                              dce_call->pkt.u.request.opnum);
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               TALLOC_FREE(creds);
-               ZERO_STRUCTP(return_authenticator);
-               return nt_status;
-       }
-
-       *creds_out = creds;
-       return NT_STATUS_OK;
-}
-
 /*
   Change the machine account password for the currently connected
   client.  Supplies only the NT#.
@@ -1615,7 +1428,7 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base_call(struct dcesrv_netr_LogonSamL
                        return NT_STATUS_OK;
                }
 
-               /* Until we get an implemetnation of these other packages */
+               /* Until we get an implementation of these other packages */
                return NT_STATUS_INVALID_PARAMETER;
        }
        default:
@@ -1658,6 +1471,7 @@ static void dcesrv_netr_LogonSamLogon_base_auth_done(struct tevent_req *subreq)
        case 2:
                nt_status = auth_convert_user_info_dc_saminfo2(mem_ctx,
                                                               user_info_dc,
+                                                              AUTH_INCLUDE_RESOURCE_GROUPS,
                                                               &sam2);
                if (!NT_STATUS_IS_OK(nt_status)) {
                        r->out.result = nt_status;
@@ -1671,7 +1485,8 @@ static void dcesrv_netr_LogonSamLogon_base_auth_done(struct tevent_req *subreq)
        case 3:
                nt_status = auth_convert_user_info_dc_saminfo3(mem_ctx,
                                                               user_info_dc,
-                                                              &sam3);
+                                                              AUTH_INCLUDE_RESOURCE_GROUPS,
+                                                              &sam3, NULL);
                if (!NT_STATUS_IS_OK(nt_status)) {
                        r->out.result = nt_status;
                        dcesrv_netr_LogonSamLogon_base_reply(state);
@@ -1684,7 +1499,8 @@ static void dcesrv_netr_LogonSamLogon_base_auth_done(struct tevent_req *subreq)
        case 6:
                nt_status = auth_convert_user_info_dc_saminfo6(mem_ctx,
                                                               user_info_dc,
-                                                              &sam6);
+                                                              AUTH_INCLUDE_RESOURCE_GROUPS,
+                                                              &sam6, NULL);
                if (!NT_STATUS_IS_OK(nt_status)) {
                        r->out.result = nt_status;
                        dcesrv_netr_LogonSamLogon_base_reply(state);
@@ -2056,7 +1872,7 @@ static WERROR dcesrv_netr_GetDcName(struct dcesrv_call_state *dce_call, TALLOC_C
                }
 
                /*
-                * TODO: Should we also varify that only valid
+                * TODO: Should we also verify that only valid
                 *       netbios name characters are used?
                 */
        }
@@ -2548,6 +2364,30 @@ static NTSTATUS dcesrv_netr_LogonGetCapabilities(struct dcesrv_call_state *dce_c
        struct netlogon_creds_CredentialState *creds;
        NTSTATUS status;
 
+       switch (r->in.query_level) {
+       case 1:
+               break;
+       case 2:
+               /*
+                * Until we know the details behind KB5028166
+                * just return DCERPC_NCA_S_FAULT_INVALID_TAG
+                * like an unpatched Windows Server.
+                */
+               FALL_THROUGH;
+       default:
+               /*
+                * There would not be a way to marshall the
+                * the response. Which would mean our final
+                * ndr_push would fail an we would return
+                * an RPC-level fault with DCERPC_FAULT_BAD_STUB_DATA.
+                *
+                * But it's important to match a Windows server
+                * especially before KB5028166, see also our bug #15418
+                * Otherwise Windows client would stop talking to us.
+                */
+               DCESRV_FAULT(DCERPC_NCA_S_FAULT_INVALID_TAG);
+       }
+
        status = dcesrv_netr_creds_server_step_check(dce_call,
                                                     mem_ctx,
                                                     r->in.computer_name,
@@ -2559,10 +2399,6 @@ static NTSTATUS dcesrv_netr_LogonGetCapabilities(struct dcesrv_call_state *dce_c
        }
        NT_STATUS_NOT_OK_RETURN(status);
 
-       if (r->in.query_level != 1) {
-               return NT_STATUS_NOT_SUPPORTED;
-       }
-
        r->out.capabilities->server_capabilities = creds->negotiate_flags;
 
        return NT_STATUS_OK;
@@ -2809,8 +2645,8 @@ static NTSTATUS dcesrv_netr_LogonGetDomainInfo(struct dcesrv_call_state *dce_cal
                                                frame);
                local  = tsocket_address_string(dce_call->conn->local_address,
                                                frame);
-               DBG_ERR(("Bad credentials - "
-                        "computer[%s] remote[%s] local[%s]\n"),
+               DBG_ERR("Bad credentials - "
+                       "computer[%s] remote[%s] local[%s]\n",
                        log_escape(frame, r->in.computer_name),
                        remote,
                        local);
@@ -3036,7 +2872,7 @@ static NTSTATUS dcesrv_netr_LogonGetDomainInfo(struct dcesrv_call_state *dce_cal
 
                ZERO_STRUCTP(domain_info);
 
-               /* Informations about the local and trusted domains */
+               /* Information about the local and trusted domains */
 
                status = fill_our_one_domain_info(mem_ctx,
                                                  our_tdo,
@@ -3378,7 +3214,9 @@ static WERROR dcesrv_netr_DsRGetDCName_base_call(struct dcesrv_netr_DsRGetDCName
        const char *domain_name = NULL;
        const char *pdc_ip;
        bool different_domain = true;
+       bool force_remote_lookup = false;
        uint32_t valid_flags;
+       uint32_t this_dc_valid_flags;
        int dc_level;
 
        ZERO_STRUCTP(r->out.info);
@@ -3443,17 +3281,8 @@ static WERROR dcesrv_netr_DsRGetDCName_base_call(struct dcesrv_netr_DsRGetDCName
         * ...
         */
 
-       dc_level = dsdb_dc_functional_level(sam_ctx);
        valid_flags = DSGETDC_VALID_FLAGS;
-       if (dc_level >= DS_DOMAIN_FUNCTION_2012) {
-               valid_flags |= DS_DIRECTORY_SERVICE_8_REQUIRED;
-       }
-       if (dc_level >= DS_DOMAIN_FUNCTION_2012_R2) {
-               valid_flags |= DS_DIRECTORY_SERVICE_9_REQUIRED;
-       }
-       if (dc_level >= DS_DOMAIN_FUNCTION_2016) {
-               valid_flags |= DS_DIRECTORY_SERVICE_10_REQUIRED;
-       }
+
        if (r->in.flags & ~valid_flags) {
                /*
                 * TODO: add tests to prove this (maybe based on the
@@ -3548,12 +3377,44 @@ static WERROR dcesrv_netr_DsRGetDCName_base_call(struct dcesrv_netr_DsRGetDCName
                different_domain = false;
        }
 
+       if (!different_domain) {
+               dc_level = dsdb_dc_functional_level(sam_ctx);
+
+               /*
+                * Do not return a local response if we do not support the
+                * functional level or feature (eg web services)
+                */
+               this_dc_valid_flags = valid_flags;
+
+               /* Samba does not implement this */
+               this_dc_valid_flags &= ~DS_WEB_SERVICE_REQUIRED;
+
+               if (dc_level < DS_DOMAIN_FUNCTION_2012) {
+                       this_dc_valid_flags &= ~DS_DIRECTORY_SERVICE_8_REQUIRED;
+               }
+               if (dc_level < DS_DOMAIN_FUNCTION_2012_R2) {
+                       this_dc_valid_flags &= ~DS_DIRECTORY_SERVICE_9_REQUIRED;
+               }
+               if (dc_level < DS_DOMAIN_FUNCTION_2016) {
+                       this_dc_valid_flags &= ~DS_DIRECTORY_SERVICE_10_REQUIRED;
+               }
+               if (r->in.flags & ~this_dc_valid_flags) {
+                       DBG_INFO("Forcing remote lookup to find another DC "
+                                "in this domain %s with more features, "
+                                "as this Samba DC is Functional level %d but flags are 0x08%x\n",
+                                r->in.domain_name, dc_level, (unsigned int)r->in.flags);
+                       force_remote_lookup = true;
+               }
+       }
+
        /* Proof server site parameter "site_name" if it was specified */
        server_site_name = samdb_server_site_name(sam_ctx, state);
        W_ERROR_HAVE_NO_MEMORY(server_site_name);
-       if (different_domain || (r->in.site_name != NULL &&
-                                (strcasecmp_m(r->in.site_name,
-                                            server_site_name) != 0))) {
+       if (force_remote_lookup
+           || different_domain
+           || (r->in.site_name != NULL &&
+               (strcasecmp_m(r->in.site_name,
+                             server_site_name) != 0))) {
 
                struct dcerpc_binding_handle *irpc_handle = NULL;
                struct tevent_req *subreq = NULL;
@@ -4080,11 +3941,9 @@ static WERROR fill_trusted_domains_array(TALLOC_CTX *mem_ctx,
                return WERR_INVALID_FLAGS;
        }
 
-       system_dn = samdb_search_dn(sam_ctx, mem_ctx,
-                                   ldb_get_default_basedn(sam_ctx),
-                                   "(&(objectClass=container)(cn=System))");
-       if (!system_dn) {
-               return WERR_GEN_FAILURE;
+       system_dn = samdb_system_container_dn(sam_ctx, mem_ctx);
+       if (system_dn == NULL) {
+               return WERR_NOT_ENOUGH_MEMORY;
        }
 
        ret = gendb_search(sam_ctx, mem_ctx, system_dn,