schannel_tdb: make code compilable in both trees
[samba.git] / source3 / rpc_server / srv_netlog_nt.c
index 491754f76a77891140dc4659a6940b81951551c0..b9bfda9a83bbbaa6c062f28a9825d088a7be2760 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
@@ -25,9 +25,8 @@
 /* This is the implementation of the netlogon pipe. */
 
 #include "includes.h"
-#include "../libcli/auth/libcli_auth.h"
-#include "../libcli/auth/schannel_state.h"
 #include "../libcli/auth/schannel.h"
+#include "../librpc/gen_ndr/srv_netlogon.h"
 
 extern userdom_struct current_user_info;
 
@@ -95,6 +94,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 +174,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 +192,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 +285,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 +309,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 +358,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;
        }
@@ -570,7 +724,8 @@ NTSTATUS _netr_ServerAuthenticate3(pipes_struct *p,
 
        /* Store off the state so we can continue after client disconnect. */
        become_root();
-       status = schannel_store_session_key(p->mem_ctx, creds);
+       status = schannel_save_creds_state(p->mem_ctx,
+                                          NULL, lp_private_dir(), creds);
        unbecome_root();
 
        if (!NT_STATUS_IS_OK(status)) {
@@ -611,6 +766,36 @@ NTSTATUS _netr_ServerAuthenticate2(pipes_struct *p,
        return _netr_ServerAuthenticate3(p, &a);
 }
 
+/*************************************************************************
+ * If schannel is required for this call test that it actually is available.
+ *************************************************************************/
+static NTSTATUS schannel_check_required(struct pipe_auth_data *auth_info,
+                                       const char *computer_name,
+                                       bool integrity, bool privacy)
+{
+       if (auth_info && auth_info->auth_type == PIPE_AUTH_TYPE_SCHANNEL) {
+               if (!privacy && !integrity) {
+                       return NT_STATUS_OK;
+               }
+
+               if ((!privacy && integrity) &&
+                   auth_info->auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
+                       return NT_STATUS_OK;
+               }
+
+               if ((privacy || integrity) &&
+                   auth_info->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+                       return NT_STATUS_OK;
+               }
+       }
+
+       /* test didn't pass */
+       DEBUG(0, ("schannel_check_required: [%s] is not using schannel\n",
+                 computer_name));
+
+       return NT_STATUS_ACCESS_DENIED;
+}
+
 /*************************************************************************
  *************************************************************************/
 
@@ -622,25 +807,23 @@ static NTSTATUS netr_creds_server_step_check(pipes_struct *p,
                                             struct netlogon_creds_CredentialState **creds_out)
 {
        NTSTATUS status;
-       struct tdb_context *tdb;
        bool schannel_global_required = (lp_server_schannel() == true) ? true:false;
-       bool schannel_in_use = (p->auth.auth_type == PIPE_AUTH_TYPE_SCHANNEL) ? true:false; /* &&
-               (p->auth.auth_level == DCERPC_AUTH_LEVEL_INTEGRITY ||
-                p->auth.auth_level == DCERPC_AUTH_LEVEL_PRIVACY); */
 
-       tdb = open_schannel_session_store(mem_ctx);
-       if (!tdb) {
-               return NT_STATUS_ACCESS_DENIED;
+       if (schannel_global_required) {
+               status = schannel_check_required(&p->auth,
+                                                computer_name,
+                                                false, false);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
        }
 
-       status = schannel_creds_server_step_check_tdb(tdb, mem_ctx,
-                                                     computer_name,
-                                                     schannel_global_required,
-                                                     schannel_in_use,
-                                                     received_authenticator,
-                                                     return_authenticator,
-                                                     creds_out);
-       tdb_close(tdb);
+       status = schannel_check_creds_state(mem_ctx, NULL,
+                                           lp_private_dir(),
+                                           computer_name,
+                                           received_authenticator,
+                                           return_authenticator,
+                                           creds_out);
 
        return status;
 }
@@ -903,8 +1086,8 @@ static NTSTATUS _netr_LogonSamLogon_base(pipes_struct *p,
        NTSTATUS status = NT_STATUS_OK;
        union netr_LogonLevel *logon = r->in.logon;
        const char *nt_username, *nt_domain, *nt_workstation;
-       auth_usersupplied_info *user_info = NULL;
-       auth_serversupplied_info *server_info = NULL;
+       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;
@@ -1205,7 +1388,9 @@ NTSTATUS _netr_LogonSamLogonEx(pipes_struct *p,
        struct netlogon_creds_CredentialState *creds = NULL;
 
        become_root();
-       status = schannel_fetch_session_key(p->mem_ctx, r->in.computer_name, &creds);
+       status = schannel_get_creds_state(p->mem_ctx,
+                                         NULL, lp_private_dir(),
+                                         r->in.computer_name, &creds);
        unbecome_root();
        if (!NT_STATUS_IS_OK(status)) {
                return status;
@@ -1307,21 +1492,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;
 }
 
 /****************************************************************
@@ -1556,11 +1852,11 @@ WERROR _netr_DsRGetForestTrustInformation(pipes_struct *p,
 /****************************************************************
 ****************************************************************/
 
-WERROR _netr_GetForestTrustInformation(pipes_struct *p,
-                                      struct netr_GetForestTrustInformation *r)
+NTSTATUS _netr_GetForestTrustInformation(pipes_struct *p,
+                                        struct netr_GetForestTrustInformation *r)
 {
        p->rng_fault_state = true;
-       return WERR_NOT_SUPPORTED;
+       return NT_STATUS_NOT_IMPLEMENTED;
 }
 
 /****************************************************************