s3-netlogon: Connecting with the system token should be sufficient.
[metze/samba/wip.git] / source3 / rpc_server / netlogon / srv_netlog_nt.c
index 5fc27569637763749be23d5d3dcfc922898459b5..53eff5fcb4ad22e18b20ae1fec80fb300b47281a 100644 (file)
@@ -649,7 +649,7 @@ static NTSTATUS get_md4pw(struct samr_Password *md4pw, const char *mach_acct,
 #if 0
 
     /*
-     * Currently this code is redundent as we already have a filter
+     * Currently this code is redundant as we already have a filter
      * by hostname list. What this code really needs to do is to
      * get a hosts allowed/hosts denied list from the SAM database
      * on a per user basis, and make the access decision there.
@@ -698,12 +698,10 @@ static NTSTATUS get_md4pw(struct samr_Password *md4pw, const char *mach_acct,
                goto out;
        }
 
-       become_root();
        status = samr_find_machine_account(mem_ctx, h, mach_acct,
                                           SEC_FLAG_MAXIMUM_ALLOWED,
                                           &domain_sid, &user_rid,
                                           &user_handle);
-       unbecome_root();
        if (!NT_STATUS_IS_OK(status)) {
                goto out;
        }
@@ -1465,21 +1463,25 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p,
        struct auth_usersupplied_info *user_info = NULL;
        struct auth_serversupplied_info *server_info = NULL;
        struct auth_context *auth_context = NULL;
-       uint8_t pipe_session_key[16];
-       bool process_creds = true;
        const char *fn;
 
+#ifdef DEBUG_PASSWORD
+       logon = netlogon_creds_shallow_copy_logon(p->mem_ctx,
+                                                 r->in.logon_level,
+                                                 r->in.logon);
+       if (logon == NULL) {
+               logon = r->in.logon;
+       }
+#endif
+
        switch (p->opnum) {
                case NDR_NETR_LOGONSAMLOGON:
-                       process_creds = true;
                        fn = "_netr_LogonSamLogon";
                        break;
                case NDR_NETR_LOGONSAMLOGONWITHFLAGS:
-                       process_creds = true;
                        fn = "_netr_LogonSamLogonWithFlags";
                        break;
                case NDR_NETR_LOGONSAMLOGONEX:
-                       process_creds = false;
                        fn = "_netr_LogonSamLogonEx";
                        break;
                default:
@@ -1552,6 +1554,10 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p,
 
        status = NT_STATUS_OK;
 
+       netlogon_creds_decrypt_samlogon_logon(creds,
+                                             r->in.logon_level,
+                                             logon);
+
        switch (r->in.logon_level) {
        case NetlogonNetworkInformation:
        case NetlogonNetworkTransitiveInformation:
@@ -1596,6 +1602,23 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p,
        {
                uint8_t chal[8];
 
+#ifdef DEBUG_PASSWORD
+               if (logon != r->in.logon) {
+                       DEBUG(100,("lm owf password:"));
+                       dump_data(100,
+                                 r->in.logon->password->lmpassword.hash, 16);
+
+                       DEBUG(100,("nt owf password:"));
+                       dump_data(100,
+                                 r->in.logon->password->ntpassword.hash, 16);
+               }
+
+               DEBUG(100,("decrypt of lm owf password:"));
+               dump_data(100, logon->password->lmpassword.hash, 16);
+
+               DEBUG(100,("decrypt of nt owf password:"));
+               dump_data(100, logon->password->ntpassword.hash, 16);
+#endif
                status = make_auth_context_subsystem(talloc_tos(),
                                                     &auth_context);
                if (!NT_STATUS_IS_OK(status)) {
@@ -1611,8 +1634,7 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p,
                                                         logon->password->identity_info.parameter_control,
                                                         chal,
                                                         logon->password->lmpassword.hash,
-                                                        logon->password->ntpassword.hash,
-                                                        creds->session_key)) {
+                                                        logon->password->ntpassword.hash)) {
                        status = NT_STATUS_NO_MEMORY;
                }
                break;
@@ -1661,40 +1683,31 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p,
            the SAM Local Security Authority should record that the user is
            logged in to the domain.  */
 
-       if (process_creds) {
-               /* Get the pipe session key from the creds. */
-               memcpy(pipe_session_key, creds->session_key, 16);
-       } else {
-               struct schannel_state *schannel_auth;
-               /* Get the pipe session key from the schannel. */
-               if ((p->auth.auth_type != DCERPC_AUTH_TYPE_SCHANNEL)
-                   || (p->auth.auth_ctx == NULL)) {
-                       return NT_STATUS_INVALID_HANDLE;
-               }
-
-               schannel_auth = talloc_get_type_abort(p->auth.auth_ctx,
-                                                     struct schannel_state);
-               memcpy(pipe_session_key, schannel_auth->creds->session_key, 16);
-       }
-
        switch (r->in.validation_level) {
        case 2:
-               status = serverinfo_to_SamInfo2(server_info, pipe_session_key, 16,
+               status = serverinfo_to_SamInfo2(server_info,
                                                r->out.validation->sam2);
                break;
        case 3:
-               status = serverinfo_to_SamInfo3(server_info, pipe_session_key, 16,
+               status = serverinfo_to_SamInfo3(server_info,
                                                r->out.validation->sam3);
                break;
        case 6:
-               status = serverinfo_to_SamInfo6(server_info, pipe_session_key, 16,
+               status = serverinfo_to_SamInfo6(server_info,
                                                r->out.validation->sam6);
                break;
        }
 
        TALLOC_FREE(server_info);
 
-       return status;
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       netlogon_creds_encrypt_samlogon_validation(creds,
+                                                  r->in.validation_level,
+                                                  r->out.validation);
+       return NT_STATUS_OK;
 }
 
 /****************************************************************
@@ -2274,22 +2287,16 @@ NTSTATUS _netr_ServerTrustPasswordsGet(struct pipes_struct *p,
 /****************************************************************
 ****************************************************************/
 
-WERROR _netr_DsRGetForestTrustInformation(struct pipes_struct *p,
-                                         struct netr_DsRGetForestTrustInformation *r)
-{
-       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
-       return WERR_NOT_SUPPORTED;
-}
-
-/****************************************************************
-****************************************************************/
-
 static NTSTATUS fill_forest_trust_array(TALLOC_CTX *mem_ctx,
                                        struct lsa_ForestTrustInformation *info)
 {
        struct lsa_ForestTrustRecord *e;
        struct pdb_domain_info *dom_info;
        struct lsa_ForestTrustDomainInfo *domain_info;
+       char **upn_suffixes = NULL;
+       uint32_t num_suffixes = 0;
+       uint32_t i = 0;
+       NTSTATUS status;
 
        dom_info = pdb_get_domain_info(mem_ctx);
        if (dom_info == NULL) {
@@ -2297,7 +2304,15 @@ static NTSTATUS fill_forest_trust_array(TALLOC_CTX *mem_ctx,
        }
 
        info->count = 2;
-       info->entries = talloc_array(info, struct lsa_ForestTrustRecord *, 2);
+
+       become_root();
+       status = pdb_enum_upn_suffixes(info, &num_suffixes, &upn_suffixes);
+       unbecome_root();
+       if (NT_STATUS_IS_OK(status) && (num_suffixes > 0)) {
+               info->count += num_suffixes;
+       }
+
+       info->entries = talloc_array(info, struct lsa_ForestTrustRecord *, info->count);
        if (info->entries == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -2315,6 +2330,21 @@ static NTSTATUS fill_forest_trust_array(TALLOC_CTX *mem_ctx,
 
        info->entries[0] = e;
 
+       if (num_suffixes > 0) {
+               for (i = 0; i < num_suffixes ; i++) {
+                       e = talloc(info, struct lsa_ForestTrustRecord);
+                       if (e == NULL) {
+                               return NT_STATUS_NO_MEMORY;
+                       }
+
+                       e->flags = 0;
+                       e->type = LSA_FOREST_TRUST_TOP_LEVEL_NAME;
+                       e->time = 0; /* so far always 0 in traces. */
+                       e->forest_trust_data.top_level_name.string = upn_suffixes[i];
+                       info->entries[1 + i] = e;
+               }
+       }
+
        e = talloc(info, struct lsa_ForestTrustRecord);
        if (e == NULL) {
                return NT_STATUS_NO_MEMORY;
@@ -2333,11 +2363,75 @@ static NTSTATUS fill_forest_trust_array(TALLOC_CTX *mem_ctx,
        domain_info->netbios_domain_name.string = talloc_steal(info,
                                                               dom_info->name);
 
-       info->entries[1] = e;
+       info->entries[info->count - 1] = e;
 
        return NT_STATUS_OK;
 }
 
+/****************************************************************
+****************************************************************/
+
+WERROR _netr_DsRGetForestTrustInformation(struct pipes_struct *p,
+                                         struct netr_DsRGetForestTrustInformation *r)
+{
+       NTSTATUS status;
+       struct lsa_ForestTrustInformation *info, **info_ptr;
+
+       if (!(p->pipe_bound && (p->auth.auth_type != DCERPC_AUTH_TYPE_NONE)
+                      && (p->auth.auth_level != DCERPC_AUTH_LEVEL_NONE))) {
+               p->fault_state = DCERPC_FAULT_ACCESS_DENIED;
+               return WERR_ACCESS_DENIED;
+       }
+
+       if (r->in.flags & (~DS_GFTI_UPDATE_TDO)) {
+               p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+               return WERR_INVALID_FLAGS;
+       }
+
+       if ((r->in.flags & DS_GFTI_UPDATE_TDO) && (lp_server_role() != ROLE_DOMAIN_PDC)) {
+               p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+               return WERR_NERR_NOTPRIMARY;
+       }
+
+       if ((r->in.trusted_domain_name == NULL) && (r->in.flags & DS_GFTI_UPDATE_TDO)) {
+               p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+               return WERR_INVALID_PARAMETER;
+       }
+
+       /* retrieve forest trust information and stop further processing */
+       if (r->in.trusted_domain_name == NULL) {
+               info_ptr = talloc(p->mem_ctx, struct lsa_ForestTrustInformation *);
+               if (info_ptr == NULL) {
+                       p->fault_state = DCERPC_FAULT_CANT_PERFORM;
+                       return WERR_NOMEM;
+               }
+               info = talloc_zero(info_ptr, struct lsa_ForestTrustInformation);
+               if (info == NULL) {
+                       p->fault_state = DCERPC_FAULT_CANT_PERFORM;
+                       return WERR_NOMEM;
+               }
+
+               /* Fill forest trust information and expand UPN suffixes list */
+               status = fill_forest_trust_array(p->mem_ctx, info);
+               if (!NT_STATUS_IS_OK(status)) {
+                       p->fault_state = DCERPC_FAULT_CANT_PERFORM;
+                       return WERR_NOMEM;
+               }
+
+               *info_ptr = info;
+               r->out.forest_trust_info = info_ptr;
+
+               return WERR_OK;
+
+       }
+
+       /* TODO: implement remaining parts of DsrGetForestTrustInformation (opnum 43)
+        *       when trusted_domain_name is not NULL */
+
+       p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+       return WERR_NOT_SUPPORTED;
+}
+
 /****************************************************************
  _netr_GetForestTrustInformation
 ****************************************************************/
@@ -2382,6 +2476,7 @@ NTSTATUS _netr_GetForestTrustInformation(struct pipes_struct *p,
                return NT_STATUS_NO_MEMORY;
        }
 
+       /* Fill forest trust information, do expand UPN suffixes list */
        status = fill_forest_trust_array(p->mem_ctx, info);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
@@ -2398,7 +2493,7 @@ NTSTATUS _netr_GetForestTrustInformation(struct pipes_struct *p,
 
 static NTSTATUS get_password_from_trustAuth(TALLOC_CTX *mem_ctx,
                                            const DATA_BLOB *trustAuth_blob,
-                                           const DATA_BLOB *session_key,
+                                           struct netlogon_creds_CredentialState *creds,
                                            struct samr_Password *current_pw_enc,
                                            struct samr_Password *previous_pw_enc)
 {
@@ -2411,29 +2506,26 @@ static NTSTATUS get_password_from_trustAuth(TALLOC_CTX *mem_ctx,
                return NT_STATUS_UNSUCCESSFUL;
        }
 
-
        if (trustAuth.count != 0 && trustAuth.current.count != 0 &&
            trustAuth.current.array[0].AuthType == TRUST_AUTH_TYPE_CLEAR) {
-               mdfour(previous_pw_enc->hash,
+               mdfour(current_pw_enc->hash,
                       trustAuth.current.array[0].AuthInfo.clear.password,
                       trustAuth.current.array[0].AuthInfo.clear.size);
+               netlogon_creds_des_encrypt(creds, current_pw_enc);
        } else {
                return NT_STATUS_UNSUCCESSFUL;
        }
 
-       arcfour_crypt_blob(current_pw_enc->hash, sizeof(current_pw_enc->hash),
-                          session_key);
 
        if (trustAuth.previous.count != 0 &&
            trustAuth.previous.array[0].AuthType == TRUST_AUTH_TYPE_CLEAR) {
                mdfour(previous_pw_enc->hash,
                       trustAuth.previous.array[0].AuthInfo.clear.password,
                       trustAuth.previous.array[0].AuthInfo.clear.size);
+               netlogon_creds_des_encrypt(creds, previous_pw_enc);
        } else {
-               mdfour(previous_pw_enc->hash, NULL, 0);
+               ZERO_STRUCTP(previous_pw_enc);
        }
-       arcfour_crypt_blob(previous_pw_enc->hash, sizeof(previous_pw_enc->hash),
-                          session_key);
 
        return NT_STATUS_OK;
 }
@@ -2452,10 +2544,6 @@ NTSTATUS _netr_ServerGetTrustInfo(struct pipes_struct *p,
        bool trusted;
        struct netr_TrustInfo *trust_info;
        struct pdb_trusted_domain *td;
-       DATA_BLOB trustAuth_blob;
-       struct samr_Password *new_owf_enc;
-       struct samr_Password *old_owf_enc;
-       DATA_BLOB session_key;
        struct loadparm_context *lp_ctx;
 
        lp_ctx = loadparm_init_s3(p->mem_ctx, loadparm_s3_helpers());
@@ -2529,36 +2617,24 @@ NTSTATUS _netr_ServerGetTrustInfo(struct pipes_struct *p,
                        *r->out.trust_info = trust_info;
                }
 
-               new_owf_enc = talloc_zero(p->mem_ctx, struct samr_Password);
-               old_owf_enc = talloc_zero(p->mem_ctx, struct samr_Password);
-               if (new_owf_enc == NULL || old_owf_enc == NULL) {
-                       return NT_STATUS_NO_MEMORY;
-               }
-
-/* TODO: which trustAuth shall we use if we have in/out trust or do they have to
- * be equal ? */
-               if (td->trust_direction & NETR_TRUST_FLAG_INBOUND) {
-                       trustAuth_blob = td->trust_auth_incoming;
-               } else if (td->trust_direction & NETR_TRUST_FLAG_OUTBOUND) {
-                       trustAuth_blob = td->trust_auth_outgoing;
+               if (td->trust_auth_incoming.data == NULL) {
+                       return NT_STATUS_INVALID_PARAMETER;
                }
 
-               session_key.data = creds->session_key;
-               session_key.length = sizeof(creds->session_key);
-               status = get_password_from_trustAuth(p->mem_ctx, &trustAuth_blob,
-                                                    &session_key,
-                                                    new_owf_enc, old_owf_enc);
+               status = get_password_from_trustAuth(p->mem_ctx,
+                                                    &td->trust_auth_incoming,
+                                                    creds,
+                                                    r->out.new_owf_password,
+                                                    r->out.old_owf_password);
 
                if (!NT_STATUS_IS_OK(status)) {
                        return status;
                }
 
-               r->out.new_owf_password = new_owf_enc;
-               r->out.old_owf_password = old_owf_enc;
        } else {
 /* TODO: look for machine password */
-               r->out.new_owf_password = NULL;
-               r->out.old_owf_password = NULL;
+               ZERO_STRUCTP(r->out.new_owf_password);
+               ZERO_STRUCTP(r->out.old_owf_password);
 
                return NT_STATUS_NOT_IMPLEMENTED;
        }