s3-netlogon: enable RPC-NETLOGON-ADMIN test against s3.
[ira/wip.git] / source3 / rpc_server / srv_netlog_nt.c
index fd90bf82c7307b3ee5118bc66859e6f700df11a8..39912ac7e40694ef7b454cbb757be26856b45c47 100644 (file)
@@ -6,7 +6,7 @@
  *  Copyright (C) Paul Ashton                       1997.
  *  Copyright (C) Jeremy Allison               1998-2001.
  *  Copyright (C) Andrew Bartlett                   2001.
- *  Copyright (C) Guenther Deschner                2008.
+ *  Copyright (C) Guenther Deschner                2008-2009.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -95,6 +95,68 @@ WERROR _netr_LogonControl2(pipes_struct *p,
        return _netr_LogonControl2Ex(p, &l);
 }
 
+/*************************************************************************
+ *************************************************************************/
+
+static bool wb_change_trust_creds(const char *domain, WERROR *tc_status)
+{
+       wbcErr result;
+       struct wbcAuthErrorInfo *error = NULL;
+
+       result = wbcChangeTrustCredentials(domain, &error);
+       switch (result) {
+       case WBC_ERR_WINBIND_NOT_AVAILABLE:
+               return false;
+       case WBC_ERR_DOMAIN_NOT_FOUND:
+               *tc_status = WERR_NO_SUCH_DOMAIN;
+               return true;
+       case WBC_ERR_SUCCESS:
+               *tc_status = WERR_OK;
+               return true;
+       default:
+               break;
+       }
+
+       if (error && error->nt_status != 0) {
+               *tc_status = ntstatus_to_werror(NT_STATUS(error->nt_status));
+       } else {
+               *tc_status = WERR_TRUST_FAILURE;
+       }
+       wbcFreeMemory(error);
+       return true;
+}
+
+/*************************************************************************
+ *************************************************************************/
+
+static bool wb_check_trust_creds(const char *domain, WERROR *tc_status)
+{
+       wbcErr result;
+       struct wbcAuthErrorInfo *error = NULL;
+
+       result = wbcCheckTrustCredentials(domain, &error);
+       switch (result) {
+       case WBC_ERR_WINBIND_NOT_AVAILABLE:
+               return false;
+       case WBC_ERR_DOMAIN_NOT_FOUND:
+               *tc_status = WERR_NO_SUCH_DOMAIN;
+               return true;
+       case WBC_ERR_SUCCESS:
+               *tc_status = WERR_OK;
+               return true;
+       default:
+               break;
+       }
+
+       if (error && error->nt_status != 0) {
+               *tc_status = ntstatus_to_werror(NT_STATUS(error->nt_status));
+       } else {
+               *tc_status = WERR_TRUST_FAILURE;
+       }
+       wbcFreeMemory(error);
+       return true;
+}
+
 /****************************************************************
  _netr_LogonControl2Ex
 ****************************************************************/
@@ -113,7 +175,9 @@ WERROR _netr_LogonControl2Ex(pipes_struct *p,
        struct netr_NETLOGON_INFO_1 *info1;
        struct netr_NETLOGON_INFO_2 *info2;
        struct netr_NETLOGON_INFO_3 *info3;
+       struct netr_NETLOGON_INFO_4 *info4;
        const char *fn;
+       uint32_t acct_ctrl;
 
        switch (p->hdr_req.opnum) {
        case NDR_NETR_LOGONCONTROL:
@@ -129,10 +193,78 @@ WERROR _netr_LogonControl2Ex(pipes_struct *p,
                return WERR_INVALID_PARAM;
        }
 
+       acct_ctrl = pdb_get_acct_ctrl(p->server_info->sam_account);
+
+       switch (r->in.function_code) {
+       case NETLOGON_CONTROL_TC_VERIFY:
+       case NETLOGON_CONTROL_CHANGE_PASSWORD:
+       case NETLOGON_CONTROL_REDISCOVER:
+               if ((geteuid() != sec_initial_uid()) &&
+                   !nt_token_check_domain_rid(p->server_info->ptok, DOMAIN_RID_ADMINS) &&
+                   !nt_token_check_sid(&global_sid_Builtin_Administrators, p->server_info->ptok) &&
+                   !(acct_ctrl & (ACB_WSTRUST | ACB_SVRTRUST))) {
+                       return WERR_ACCESS_DENIED;
+               }
+               break;
+       default:
+               break;
+       }
+
        tc_status = WERR_NO_SUCH_DOMAIN;
 
        switch (r->in.function_code) {
+       case NETLOGON_CONTROL_QUERY:
+               tc_status = WERR_OK;
+               break;
+       case NETLOGON_CONTROL_REPLICATE:
+       case NETLOGON_CONTROL_SYNCHRONIZE:
+       case NETLOGON_CONTROL_PDC_REPLICATE:
+       case NETLOGON_CONTROL_BACKUP_CHANGE_LOG:
+       case NETLOGON_CONTROL_BREAKPOINT:
+               if (acct_ctrl & ACB_NORMAL) {
+                       return WERR_NOT_SUPPORTED;
+               } else if (acct_ctrl & (ACB_WSTRUST | ACB_SVRTRUST)) {
+                       return WERR_ACCESS_DENIED;
+               } else {
+                       return WERR_ACCESS_DENIED;
+               }
+       case NETLOGON_CONTROL_TRUNCATE_LOG:
+               if (acct_ctrl & ACB_NORMAL) {
+                       break;
+               } else if (acct_ctrl & (ACB_WSTRUST | ACB_SVRTRUST)) {
+                       return WERR_ACCESS_DENIED;
+               } else {
+                       return WERR_ACCESS_DENIED;
+               }
+
+       case NETLOGON_CONTROL_TRANSPORT_NOTIFY:
+       case NETLOGON_CONTROL_FORCE_DNS_REG:
+       case NETLOGON_CONTROL_QUERY_DNS_REG:
+               return WERR_NOT_SUPPORTED;
+       case NETLOGON_CONTROL_FIND_USER:
+               if (!r->in.data || !r->in.data->user) {
+                       return WERR_NOT_SUPPORTED;
+               }
+               break;
+       case NETLOGON_CONTROL_SET_DBFLAG:
+               if (!r->in.data) {
+                       return WERR_NOT_SUPPORTED;
+               }
+               break;
+       case NETLOGON_CONTROL_TC_VERIFY:
+               if (!r->in.data || !r->in.data->domain) {
+                       return WERR_NOT_SUPPORTED;
+               }
+
+               if (!wb_check_trust_creds(r->in.data->domain, &tc_status)) {
+                       return WERR_NOT_SUPPORTED;
+               }
+               break;
        case NETLOGON_CONTROL_TC_QUERY:
+               if (!r->in.data || !r->in.data->domain) {
+                       return WERR_NOT_SUPPORTED;
+               }
+
                domain = r->in.data->domain;
 
                if (!is_trusted_domain(domain)) {
@@ -154,6 +286,10 @@ WERROR _netr_LogonControl2Ex(pipes_struct *p,
                break;
 
        case NETLOGON_CONTROL_REDISCOVER:
+               if (!r->in.data || !r->in.data->domain) {
+                       return WERR_NOT_SUPPORTED;
+               }
+
                domain = r->in.data->domain;
 
                if (!is_trusted_domain(domain)) {
@@ -174,6 +310,16 @@ WERROR _netr_LogonControl2Ex(pipes_struct *p,
 
                break;
 
+       case NETLOGON_CONTROL_CHANGE_PASSWORD:
+               if (!r->in.data || !r->in.data->domain) {
+                       return WERR_NOT_SUPPORTED;
+               }
+
+               if (!wb_change_trust_creds(r->in.data->domain, &tc_status)) {
+                       return WERR_NOT_SUPPORTED;
+               }
+               break;
+
        default:
                /* no idea what this should be */
                DEBUG(0,("%s: unimplemented function level [%d]\n",
@@ -213,6 +359,15 @@ WERROR _netr_LogonControl2Ex(pipes_struct *p,
 
                r->out.query->info3 = info3;
                break;
+       case 4:
+               info4 = TALLOC_ZERO_P(p->mem_ctx, struct netr_NETLOGON_INFO_4);
+               W_ERROR_HAVE_NO_MEMORY(info4);
+
+               info4->trusted_dc_name          = dc_name;
+               info4->trusted_domain_name      = r->in.data->domain;
+
+               r->out.query->info4 = info4;
+               break;
        default:
                return WERR_UNKNOWN_LEVEL;
        }
@@ -281,7 +436,7 @@ WERROR _netr_NetrEnumerateTrustedDomains(pipes_struct *p,
  ******************************************************************/
 
 static NTSTATUS get_md4pw(struct samr_Password *md4pw, const char *mach_acct,
-                         uint16_t sec_chan_type, struct dom_sid *sid)
+                         enum netr_SchannelType sec_chan_type, struct dom_sid *sid)
 {
        struct samu *sampass = NULL;
        const uint8 *pass;
@@ -827,6 +982,7 @@ NTSTATUS _netr_ServerPasswordSet2(pipes_struct *p,
        struct samu *sampass;
        DATA_BLOB plaintext;
        struct samr_CryptPassword password_buf;
+       struct samr_Password nt_hash;
 
        become_root();
        status = netr_creds_server_step_check(p, p->mem_ctx,
@@ -852,6 +1008,8 @@ NTSTATUS _netr_ServerPasswordSet2(pipes_struct *p,
                return NT_STATUS_WRONG_PASSWORD;
        }
 
+       mdfour(nt_hash.hash, plaintext.data, plaintext.length);
+
        status = netr_find_machine_account(p->mem_ctx,
                                           creds->account_name,
                                           &sampass);
@@ -861,8 +1019,8 @@ NTSTATUS _netr_ServerPasswordSet2(pipes_struct *p,
 
        status = netr_set_machine_account_password(sampass,
                                                   sampass,
-                                                  &plaintext,
                                                   NULL,
+                                                  &nt_hash,
                                                   NULL);
        TALLOC_FREE(sampass);
        return status;
@@ -1304,21 +1462,132 @@ NTSTATUS _netr_AccountSync(pipes_struct *p,
 /****************************************************************
 ****************************************************************/
 
+static bool wb_getdcname(TALLOC_CTX *mem_ctx,
+                        const char *domain,
+                        const char **dcname,
+                        uint32_t flags,
+                        WERROR *werr)
+{
+       wbcErr result;
+       struct wbcDomainControllerInfo *dc_info = NULL;
+
+       result = wbcLookupDomainController(domain,
+                                          flags,
+                                          &dc_info);
+       switch (result) {
+       case WBC_ERR_SUCCESS:
+               break;
+       case WBC_ERR_WINBIND_NOT_AVAILABLE:
+               return false;
+       case WBC_ERR_DOMAIN_NOT_FOUND:
+               *werr = WERR_NO_SUCH_DOMAIN;
+               return true;
+       default:
+               *werr = WERR_DOMAIN_CONTROLLER_NOT_FOUND;
+               return true;
+       }
+
+       *dcname = talloc_strdup(mem_ctx, dc_info->dc_name);
+       wbcFreeMemory(dc_info);
+       if (!*dcname) {
+               *werr = WERR_NOMEM;
+               return false;
+       }
+
+       *werr = WERR_OK;
+
+       return true;
+}
+
+/****************************************************************
+ _netr_GetDcName
+****************************************************************/
+
 WERROR _netr_GetDcName(pipes_struct *p,
                       struct netr_GetDcName *r)
 {
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
+       NTSTATUS status;
+       WERROR werr;
+       uint32_t flags;
+       struct netr_DsRGetDCNameInfo *info;
+       bool ret;
+
+       ret = wb_getdcname(p->mem_ctx,
+                          r->in.domainname,
+                          r->out.dcname,
+                          WBC_LOOKUP_DC_IS_FLAT_NAME |
+                          WBC_LOOKUP_DC_RETURN_FLAT_NAME |
+                          WBC_LOOKUP_DC_PDC_REQUIRED,
+                          &werr);
+       if (ret == true) {
+               return werr;
+       }
+
+       flags = DS_PDC_REQUIRED | DS_IS_FLAT_NAME | DS_RETURN_FLAT_NAME;
+
+       status = dsgetdcname(p->mem_ctx,
+                            smbd_messaging_context(),
+                            r->in.domainname,
+                            NULL,
+                            NULL,
+                            flags,
+                            &info);
+       if (!NT_STATUS_IS_OK(status)) {
+               return ntstatus_to_werror(status);
+       }
+
+       *r->out.dcname = talloc_strdup(p->mem_ctx, info->dc_unc);
+       talloc_free(info);
+       if (!*r->out.dcname) {
+               return WERR_NOMEM;
+       }
+
+       return WERR_OK;
 }
 
 /****************************************************************
+ _netr_GetAnyDCName
 ****************************************************************/
 
 WERROR _netr_GetAnyDCName(pipes_struct *p,
                          struct netr_GetAnyDCName *r)
 {
-       p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
+       NTSTATUS status;
+       WERROR werr;
+       uint32_t flags;
+       struct netr_DsRGetDCNameInfo *info;
+       bool ret;
+
+       ret = wb_getdcname(p->mem_ctx,
+                          r->in.domainname,
+                          r->out.dcname,
+                          WBC_LOOKUP_DC_IS_FLAT_NAME |
+                          WBC_LOOKUP_DC_RETURN_FLAT_NAME,
+                          &werr);
+       if (ret == true) {
+               return werr;
+       }
+
+       flags = DS_IS_FLAT_NAME | DS_RETURN_FLAT_NAME;
+
+       status = dsgetdcname(p->mem_ctx,
+                            smbd_messaging_context(),
+                            r->in.domainname,
+                            NULL,
+                            NULL,
+                            flags,
+                            &info);
+       if (!NT_STATUS_IS_OK(status)) {
+               return ntstatus_to_werror(status);
+       }
+
+       *r->out.dcname = talloc_strdup(p->mem_ctx, info->dc_unc);
+       talloc_free(info);
+       if (!*r->out.dcname) {
+               return WERR_NOMEM;
+       }
+
+       return WERR_OK;
 }
 
 /****************************************************************