Start implementing the server-sde NETLOGON PAC verification.
[kai/samba.git] / source4 / rpc_server / netlogon / dcerpc_netlogon.c
index 3d9262b995ee65bc1d094072c2793c1df7990276..5672d29cb2852845fa2ea8353756b6a5fd8fecf4 100644 (file)
@@ -27,6 +27,7 @@
 #include "auth/auth.h"
 #include "auth/auth_sam_reply.h"
 #include "dsdb/samdb/samdb.h"
+#include "dsdb/common/flags.h"
 #include "rpc_server/samr/proto.h"
 #include "util/util_ldb.h"
 #include "libcli/auth/libcli_auth.h"
@@ -76,7 +77,7 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_ca
        struct creds_CredentialState *creds;
        void *sam_ctx;
        struct samr_Password *mach_pwd;
-       uint16_t acct_flags;
+       uint32_t user_account_control;
        int num_records;
        struct ldb_message **msgs;
        NTSTATUS nt_status;
@@ -92,7 +93,7 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_ca
                return NT_STATUS_ACCESS_DENIED;
        }
 
-       sam_ctx = samdb_connect(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, 
+       sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, 
                                system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx));
        if (sam_ctx == NULL) {
                return NT_STATUS_INVALID_SYSTEM_SERVICE;
@@ -113,27 +114,28 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_ca
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
-       acct_flags = samdb_result_acct_flags(msgs[0], 
-                                            "userAccountControl");
+       
+       user_account_control = ldb_msg_find_attr_as_uint(msgs[0], "userAccountControl", 0);
 
-       if (acct_flags & ACB_DISABLED) {
+       if (user_account_control & UF_ACCOUNTDISABLE) {
                DEBUG(1, ("Account [%s] is disabled\n", r->in.account_name));
                return NT_STATUS_ACCESS_DENIED;
        }
 
        if (r->in.secure_channel_type == SEC_CHAN_WKSTA) {
-               if (!(acct_flags & ACB_WSTRUST)) {
-                       DEBUG(1, ("Client asked for a workstation secure channel, but is not a workstation (member server) acb flags: 0x%x\n", acct_flags));
+               if (!(user_account_control & UF_WORKSTATION_TRUST_ACCOUNT)) {
+                       DEBUG(1, ("Client asked for a workstation secure channel, but is not a workstation (member server) acb flags: 0x%x\n", user_account_control));
                        return NT_STATUS_ACCESS_DENIED;
                }
        } else if (r->in.secure_channel_type == SEC_CHAN_DOMAIN) {
-               if (!(acct_flags & ACB_DOMTRUST)) {
-                       DEBUG(1, ("Client asked for a trusted domain secure channel, but is not a trusted domain: acb flags: 0x%x\n", acct_flags));
+               if (!(user_account_control & UF_INTERDOMAIN_TRUST_ACCOUNT)) {
+                       DEBUG(1, ("Client asked for a trusted domain secure channel, but is not a trusted domain: acb flags: 0x%x\n", user_account_control));
+                       
                        return NT_STATUS_ACCESS_DENIED;
                }
        } else if (r->in.secure_channel_type == SEC_CHAN_BDC) {
-               if (!(acct_flags & ACB_SVRTRUST)) {
-                       DEBUG(1, ("Client asked for a server secure channel, but is not a server (domain controller): acb flags: 0x%x\n", acct_flags));
+               if (!(user_account_control & UF_SERVER_TRUST_ACCOUNT)) {
+                       DEBUG(1, ("Client asked for a server secure channel, but is not a server (domain controller): acb flags: 0x%x\n", user_account_control));
                        return NT_STATUS_ACCESS_DENIED;
                }
        } else {
@@ -174,7 +176,7 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3(struct dcesrv_call_state *dce_ca
 
 
        /* remember this session key state */
-       nt_status = schannel_store_session_key(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, creds);
+       nt_status = schannel_store_session_key(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, creds);
 
        return nt_status;
 }
@@ -234,7 +236,8 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate2(struct dcesrv_call_state *dce_ca
   the caller needs some of that information.
 
 */
-static NTSTATUS dcesrv_netr_creds_server_step_check(struct loadparm_context *lp_ctx,
+static NTSTATUS dcesrv_netr_creds_server_step_check(struct event_context *event_ctx, 
+                                                   struct loadparm_context *lp_ctx,
                                                    const char *computer_name,
                                             TALLOC_CTX *mem_ctx, 
                                             struct netr_Authenticator *received_authenticator,
@@ -246,7 +249,7 @@ static NTSTATUS dcesrv_netr_creds_server_step_check(struct loadparm_context *lp_
        struct ldb_context *ldb;
        int ret;
 
-       ldb = schannel_db_connect(mem_ctx, lp_ctx);
+       ldb = schannel_db_connect(mem_ctx, event_ctx, lp_ctx);
        if (!ldb) {
                return NT_STATUS_ACCESS_DENIED;
        }
@@ -298,13 +301,13 @@ static NTSTATUS dcesrv_netr_ServerPasswordSet(struct dcesrv_call_state *dce_call
        struct ldb_context *sam_ctx;
        NTSTATUS nt_status;
 
-       nt_status = dcesrv_netr_creds_server_step_check(dce_call->conn->dce_ctx->lp_ctx,
+       nt_status = dcesrv_netr_creds_server_step_check(dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx,
                                                        r->in.computer_name, mem_ctx, 
                                                 &r->in.credential, &r->out.return_authenticator,
                                                 &creds);
        NT_STATUS_NOT_OK_RETURN(nt_status);
 
-       sam_ctx = samdb_connect(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx));
+       sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx));
        if (sam_ctx == NULL) {
                return NT_STATUS_INVALID_SYSTEM_SERVICE;
        }
@@ -337,13 +340,13 @@ static NTSTATUS dcesrv_netr_ServerPasswordSet2(struct dcesrv_call_state *dce_cal
 
        struct samr_CryptPassword password_buf;
 
-       nt_status = dcesrv_netr_creds_server_step_check(dce_call->conn->dce_ctx->lp_ctx,
+       nt_status = dcesrv_netr_creds_server_step_check(dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx,
                                                        r->in.computer_name, mem_ctx, 
                                                 &r->in.credential, &r->out.return_authenticator,
                                                 &creds);
        NT_STATUS_NOT_OK_RETURN(nt_status);
 
-       sam_ctx = samdb_connect(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx));
+       sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx));
        if (sam_ctx == NULL) {
                return NT_STATUS_INVALID_SYSTEM_SERVICE;
        }
@@ -418,9 +421,10 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_cal
        user_info->remote_host = NULL;
 
        switch (r->in.logon_level) {
-       case 1:
-       case 3:
-       case 5:
+       case NetlogonInteractiveInformation:
+       case NetlogonServiceInformation:
+       case NetlogonInteractiveTransitiveInformation:
+       case NetlogonServiceTransitiveInformation:
                if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
                        creds_arcfour_crypt(creds, 
                                            r->in.logon.password->lmpassword.hash, 
@@ -457,8 +461,8 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_cal
                *user_info->password.hash.nt = r->in.logon.password->ntpassword;
 
                break;
-       case 2:
-       case 6:
+       case NetlogonNetworkInformation:
+       case NetlogonNetworkTransitiveInformation:
 
                /* TODO: we need to deny anonymous access here */
                nt_status = auth_context_create(mem_ctx, 
@@ -480,6 +484,58 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_cal
                user_info->password.response.nt = data_blob_talloc(mem_ctx, r->in.logon.network->nt.data, r->in.logon.network->nt.length);
        
                break;
+
+               
+       case NetlogonGenericInformation:
+       {
+               if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
+                       creds_arcfour_crypt(creds, 
+                                           r->in.logon.generic->data, r->in.logon.generic->length);
+               } else {
+                       /* Using DES to verify kerberos tickets makes no sense */
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+
+               if (strcmp(r->in.logon.generic->package_name.string, "Kerberos")) {
+                       struct PAC_Validate pac_validate;
+                       DATA_BLOB srv_sig;
+                       struct PAC_SIGNATURE_DATA kdc_sig;
+                       DATA_BLOB pac_validate_blob = data_blob_const(r->in.logon.generic->data, 
+                                                                     r->in.logon.generic->length);
+                       ndr_err = ndr_pull_struct_blob(&pac_validate_blob, mem_ctx, 
+                                                      lp_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx), 
+                                                      &pac_validate,
+                                                      (ndr_pull_flags_fn_t)ndr_pull_PAC_Validate);
+                       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                               return NT_STATUS_INVALID_PARAMETER;
+                       }
+
+                       if (pac_validate->MessageType != 3) {
+                               /* We don't implement any other message types - such as certificate validation - yet */
+                               return NT_STATUS_INVALID_PARAMETER;
+                       }
+                       
+                       if (pac_validate->ChecksumAndSignature.length != (pac_validate->ChecksumLength + pac_validate->SignatureLength)
+                           || pac_validate->ChecksumAndSignature.length < pac_validate->ChecksumLength
+                           || pac_validate->ChecksumAndSignature.length < pac_validate->SignatureLength ) {
+                               return NT_STATUS_INVALID_PARAMETER;
+                       }
+
+                       srv_sig = data_blob_const(pac_validate->ChecksumAndSignature.data, 
+                                                 pac_validate->ChecksumLength);
+
+                       kdc_sig.type = pac_validate->SignatureType;
+                       kdc_sig.signature = data_blob_const(&pac_validate->ChecksumAndSignature.data[pac_validate->ChecksumLength],
+                                                           pac_validate->SignatureLength);
+                       check_pac_checksum(mem_ctx, srv_sig, &kdc_sig, 
+                                          context, keyblock);
+                                          
+
+               }
+
+               /* Until we get an implemetnation of these other packages */
+               return NT_STATUS_INVALID_PARAMETER;
+       }
        default:
                return NT_STATUS_INVALID_PARAMETER;
        }
@@ -559,7 +615,7 @@ static NTSTATUS dcesrv_netr_LogonSamLogonEx(struct dcesrv_call_state *dce_call,
 {
        NTSTATUS nt_status;
        struct creds_CredentialState *creds;
-       nt_status = schannel_fetch_session_key(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, r->in.computer_name, lp_workgroup(dce_call->conn->dce_ctx->lp_ctx), &creds);
+       nt_status = schannel_fetch_session_key(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, r->in.computer_name, lp_workgroup(dce_call->conn->dce_ctx->lp_ctx), &creds);
        if (!NT_STATUS_IS_OK(nt_status)) {
                return nt_status;
        }
@@ -587,7 +643,7 @@ static NTSTATUS dcesrv_netr_LogonSamLogonWithFlags(struct dcesrv_call_state *dce
        return_authenticator = talloc(mem_ctx, struct netr_Authenticator);
        NT_STATUS_HAVE_NO_MEMORY(return_authenticator);
 
-       nt_status = dcesrv_netr_creds_server_step_check(dce_call->conn->dce_ctx->lp_ctx,
+       nt_status = dcesrv_netr_creds_server_step_check(dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx,
                                                        r->in.computer_name, mem_ctx, 
                                                 r->in.credential, return_authenticator,
                                                 &creds);
@@ -797,11 +853,11 @@ static WERROR dcesrv_netr_NETRLOGONSETSERVICEBITS(struct dcesrv_call_state *dce_
 }
 
 
-/* 
-  netr_NETRLOGONGETTRUSTRID 
+/*
+  netr_LogonGetTrustRid
 */
-static WERROR dcesrv_netr_NETRLOGONGETTRUSTRID(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct netr_NETRLOGONGETTRUSTRID *r)
+static WERROR dcesrv_netr_LogonGetTrustRid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct netr_LogonGetTrustRid *r)
 {
        DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
 }
@@ -889,14 +945,14 @@ static NTSTATUS dcesrv_netr_LogonGetDomainInfo(struct dcesrv_call_state *dce_cal
 
        const char *local_domain;
 
-       status = dcesrv_netr_creds_server_step_check(dce_call->conn->dce_ctx->lp_ctx,
+       status = dcesrv_netr_creds_server_step_check(dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx,
                                                     r->in.computer_name, mem_ctx, 
                                              r->in.credential, 
                                              r->out.return_authenticator,
                                              NULL);
        NT_STATUS_NOT_OK_RETURN(status);
 
-       sam_ctx = samdb_connect(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info);
+       sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info);
        if (sam_ctx == NULL) {
                return NT_STATUS_INVALID_SYSTEM_SERVICE;
        }
@@ -1001,7 +1057,7 @@ static WERROR dcesrv_netr_DsRGetDCNameEx2(struct dcesrv_call_state *dce_call, TA
 
        ZERO_STRUCT(r->out);
 
-       sam_ctx = samdb_connect(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info);
+       sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info);
        if (sam_ctx == NULL) {
                return WERR_DS_SERVICE_UNAVAILABLE;
        }
@@ -1163,7 +1219,7 @@ static WERROR dcesrv_netr_DsrEnumerateDomainTrusts(struct dcesrv_call_state *dce
 
        ZERO_STRUCT(r->out);
 
-       sam_ctx = samdb_connect(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info);
+       sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info);
        if (sam_ctx == NULL) {
                return WERR_GENERAL_FAILURE;
        }
@@ -1212,11 +1268,11 @@ static WERROR dcesrv_netr_DsrEnumerateDomainTrusts(struct dcesrv_call_state *dce
 }
 
 
-/* 
-  netr_DSRDEREGISTERDNSHOSTRECORDS 
+/*
+  netr_DsrDeregisterDNSHostRecords
 */
-static WERROR dcesrv_netr_DSRDEREGISTERDNSHOSTRECORDS(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct netr_DSRDEREGISTERDNSHOSTRECORDS *r)
+static WERROR dcesrv_netr_DsrDeregisterDNSHostRecords(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct netr_DsrDeregisterDNSHostRecords *r)
 {
        DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
 }