More LSA server and testuite work.
[ira/wip.git] / source4 / rpc_server / lsa / dcesrv_lsa.c
index 25d6f8c8f71128774bf9a3965f96907925b4c6e1..f67b5dee10467e91b5c37c680f99dd67431c2e43 100644 (file)
 */
 
 #include "rpc_server/lsa/lsa.h"
+#include "util/util_ldb.h"
+#include "libcli/ldap/ldap_ndr.h"
+#include "system/kerberos.h"
+#include "auth/kerberos/kerberos.h"
 
 /*
   this type allows us to distinguish handle types
@@ -92,29 +96,57 @@ static NTSTATUS dcesrv_lsa_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX
 */
 static NTSTATUS dcesrv_lsa_Delete(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                           struct lsa_Delete *r)
+{
+       return NT_STATUS_NOT_SUPPORTED;
+}
+
+
+/* 
+  lsa_DeleteObject
+*/
+static NTSTATUS dcesrv_lsa_DeleteObject(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                      struct lsa_DeleteObject *r)
 {
        struct dcesrv_handle *h;
        int ret;
 
        DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
+
        if (h->wire_handle.handle_type == LSA_HANDLE_SECRET) {
                struct lsa_secret_state *secret_state = h->data;
-               ret = samdb_delete(secret_state->sam_ldb, mem_ctx, secret_state->secret_dn);
+
+               /* Ensure user is permitted to delete this... */
+               switch (security_session_user_level(dce_call->conn->auth_state.session_info))
+               {
+               case SECURITY_SYSTEM:
+               case SECURITY_ADMINISTRATOR:
+                       break;
+               default:
+                       /* Users and annonymous are not allowed delete things */
+                       return NT_STATUS_ACCESS_DENIED;
+               }
+
+               ret = ldb_delete(secret_state->sam_ldb, 
+                                secret_state->secret_dn);
                talloc_free(h);
                if (ret != 0) {
                        return NT_STATUS_INVALID_HANDLE;
                }
 
+               ZERO_STRUCTP(r->out.handle);
+
                return NT_STATUS_OK;
        } else if (h->wire_handle.handle_type == LSA_HANDLE_TRUSTED_DOMAIN) {
                struct lsa_trusted_domain_state *trusted_domain_state = h->data;
-               ret = samdb_delete(trusted_domain_state->policy->sam_ldb, mem_ctx
-                                  trusted_domain_state->trusted_domain_dn);
+               ret = ldb_delete(trusted_domain_state->policy->sam_ldb
+                                trusted_domain_state->trusted_domain_dn);
                talloc_free(h);
                if (ret != 0) {
                        return NT_STATUS_INVALID_HANDLE;
                }
 
+               ZERO_STRUCTP(r->out.handle);
+
                return NT_STATUS_OK;
        } else if (h->wire_handle.handle_type == LSA_HANDLE_ACCOUNT) {
                struct lsa_RightSet *rights;
@@ -151,6 +183,8 @@ static NTSTATUS dcesrv_lsa_Delete(struct dcesrv_call_state *dce_call, TALLOC_CTX
                if (!NT_STATUS_IS_OK(status)) {
                        return status;
                }
+
+               ZERO_STRUCTP(r->out.handle);
        } 
        
        return NT_STATUS_INVALID_HANDLE;
@@ -262,7 +296,7 @@ static WERROR dcesrv_dssetup_DsRoleGetPrimaryDomainInformation(struct dcesrv_cal
 
                ZERO_STRUCT(domain_guid);
 
-               switch (lp_server_role(global_loadparm)) {
+               switch (lp_server_role(dce_call->conn->dce_ctx->lp_ctx)) {
                case ROLE_STANDALONE:
                        role            = DS_ROLE_STANDALONE_SERVER;
                        break;
@@ -278,13 +312,13 @@ static WERROR dcesrv_dssetup_DsRoleGetPrimaryDomainInformation(struct dcesrv_cal
                        break;
                }
 
-               switch (lp_server_role(global_loadparm)) {
+               switch (lp_server_role(dce_call->conn->dce_ctx->lp_ctx)) {
                case ROLE_STANDALONE:
-                       domain          = talloc_strdup(mem_ctx, lp_workgroup(global_loadparm));
+                       domain          = talloc_strdup(mem_ctx, lp_workgroup(dce_call->conn->dce_ctx->lp_ctx));
                        W_ERROR_HAVE_NO_MEMORY(domain);
                        break;
                case ROLE_DOMAIN_MEMBER:
-                       domain          = talloc_strdup(mem_ctx, lp_workgroup(global_loadparm));
+                       domain          = talloc_strdup(mem_ctx, lp_workgroup(dce_call->conn->dce_ctx->lp_ctx));
                        W_ERROR_HAVE_NO_MEMORY(domain);
                        /* TODO: what is with dns_domain and forest and guid? */
                        break;
@@ -443,6 +477,8 @@ static NTSTATUS dcesrv_lsa_ClearAuditLog(struct dcesrv_call_state *dce_call, TAL
 
 /* 
   lsa_CreateAccount 
+
+  This call does not seem to have any long-term effects, hence no database operations
 */
 static NTSTATUS dcesrv_lsa_CreateAccount(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                                  struct lsa_CreateAccount *r)
@@ -641,9 +677,26 @@ static NTSTATUS dcesrv_lsa_CreateTrustedDomain(struct dcesrv_call_state *dce_cal
 
        /* create the trusted_domain */
        ret = ldb_add(trusted_domain_state->policy->sam_ldb, msg);
-       if (ret != LDB_SUCCESS) {
-               DEBUG(0,("Failed to create trusted_domain record %s: %s\n",
-                        ldb_dn_get_linearized(msg->dn), ldb_errstring(trusted_domain_state->policy->sam_ldb)));
+       switch (ret) {
+       case  LDB_SUCCESS:
+               break;
+       case  LDB_ERR_ENTRY_ALREADY_EXISTS:
+               ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
+               DEBUG(0,("Failed to create trusted domain record %s: %s\n",
+                        ldb_dn_get_linearized(msg->dn),
+                        ldb_errstring(trusted_domain_state->policy->sam_ldb)));
+               return NT_STATUS_DOMAIN_EXISTS;
+       case  LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
+               ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
+               DEBUG(0,("Failed to create trusted domain record %s: %s\n",
+                        ldb_dn_get_linearized(msg->dn),
+                        ldb_errstring(trusted_domain_state->policy->sam_ldb)));
+               return NT_STATUS_ACCESS_DENIED;
+       default:
+               ldb_transaction_cancel(trusted_domain_state->policy->sam_ldb);
+               DEBUG(0,("Failed to create user record %s: %s\n",
+                        ldb_dn_get_linearized(msg->dn),
+                        ldb_errstring(trusted_domain_state->policy->sam_ldb)));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
@@ -826,7 +879,7 @@ static NTSTATUS dcesrv_lsa_DeleteTrustedDomain(struct dcesrv_call_state *dce_cal
 {
        NTSTATUS status;
        struct lsa_OpenTrustedDomain open;
-       struct lsa_Delete delete;
+       struct lsa_DeleteObject delete;
        struct dcesrv_handle *h;
 
        open.in.handle = r->in.handle;
@@ -845,7 +898,8 @@ static NTSTATUS dcesrv_lsa_DeleteTrustedDomain(struct dcesrv_call_state *dce_cal
        talloc_steal(mem_ctx, h);
 
        delete.in.handle = open.out.trustdom_handle;
-       status = dcesrv_lsa_Delete(dce_call, mem_ctx, &delete);
+       delete.out.handle = open.out.trustdom_handle;
+       status = dcesrv_lsa_DeleteObject(dce_call, mem_ctx, &delete);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -889,6 +943,7 @@ static NTSTATUS dcesrv_lsa_QueryTrustedDomainInfo(struct dcesrv_call_state *dce_
                "trustDirection",
                "trustType",
                "trustAttributes", 
+               "msDs-supportedEncryptionTypes",
                NULL
        };
 
@@ -932,12 +987,19 @@ static NTSTATUS dcesrv_lsa_QueryTrustedDomainInfo(struct dcesrv_call_state *dce_
                ZERO_STRUCT(r->out.info->full_info);
                return fill_trust_domain_ex(mem_ctx, msg, &r->out.info->full_info.info_ex);
 
-       case LSA_TRUSTED_DOMAIN_INFO_INFO_ALL:
-               ZERO_STRUCT(r->out.info->info_all);
-               return fill_trust_domain_ex(mem_ctx, msg, &r->out.info->info_all.info_ex);
+       case LSA_TRUSTED_DOMAIN_INFO_FULL_INFO_2_INTERNAL:
+               ZERO_STRUCT(r->out.info->info2_internal);
+               r->out.info->info2_internal.posix_offset.posix_offset
+                       = samdb_result_uint(msg, "posixOffset", 0);                                        
+               return fill_trust_domain_ex(mem_ctx, msg, &r->out.info->info2_internal.info_ex);
+               
+       case LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRTYPION_TYPES:
+               r->out.info->enc_types.enc_types
+                       = samdb_result_uint(msg, "msDs-supportedEncryptionTypes", KERB_ENCTYPE_RC4_HMAC_MD5);
+               break;
 
-       case LSA_TRUSTED_DOMAIN_INFO_CONTROLLERS_INFO:
-       case LSA_TRUSTED_DOMAIN_INFO_11:
+       case LSA_TRUSTED_DOMAIN_INFO_CONTROLLERS:
+       case LSA_TRUSTED_DOMAIN_INFO_INFO_EX2_INTERNAL:
                /* oops, we don't want to return the info after all */
                talloc_free(r->out.info);
                r->out.info = NULL;
@@ -1095,9 +1157,6 @@ static NTSTATUS dcesrv_lsa_EnumTrustDom(struct dcesrv_call_state *dce_call, TALL
        if (count == -1) {
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
-       if (count == 0 || r->in.max_size == 0) {
-               return NT_STATUS_OK;
-       }
 
        /* convert to lsa_TrustInformation format */
        entries = talloc_array(mem_ctx, struct lsa_DomainInfo, count);
@@ -1183,9 +1242,6 @@ static NTSTATUS dcesrv_lsa_EnumTrustedDomainsEx(struct dcesrv_call_state *dce_ca
        if (count == -1) {
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
-       if (count == 0 || r->in.max_size == 0) {
-               return NT_STATUS_OK;
-       }
 
        /* convert to lsa_DomainInformation format */
        entries = talloc_array(mem_ctx, struct lsa_TrustDomainInfoInfoEx, count);
@@ -1477,7 +1533,7 @@ static NTSTATUS dcesrv_lsa_AddRemoveAccountRights(struct dcesrv_call_state *dce_
                return NT_STATUS_OK;
        }
 
-       ret = samdb_modify(state->sam_ldb, mem_ctx, msg);
+       ret = ldb_modify(state->sam_ldb, msg);
        if (ret != 0) {
                if (ldb_flag == LDB_FLAG_MOD_DELETE && ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
                        return NT_STATUS_OBJECT_NAME_NOT_FOUND;
@@ -1653,6 +1709,16 @@ static NTSTATUS dcesrv_lsa_CreateSecret(struct dcesrv_call_state *dce_call, TALL
        DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);
        ZERO_STRUCTP(r->out.sec_handle);
        
+       switch (security_session_user_level(dce_call->conn->auth_state.session_info))
+       {
+       case SECURITY_SYSTEM:
+       case SECURITY_ADMINISTRATOR:
+               break;
+       default:
+               /* Users and annonymous are not allowed create secrets */
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
        policy_state = policy_handle->data;
 
        if (!r->in.name.string) {
@@ -1711,7 +1777,8 @@ static NTSTATUS dcesrv_lsa_CreateSecret(struct dcesrv_call_state *dce_call, TALL
                        return NT_STATUS_INVALID_PARAMETER;
                }
 
-               secret_state->sam_ldb = talloc_reference(secret_state, secrets_db_connect(mem_ctx));
+               secret_state->sam_ldb = talloc_reference(secret_state, 
+                                                        secrets_db_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx));
                /* search for the secret record */
                ret = gendb_search(secret_state->sam_ldb, mem_ctx,
                                   ldb_dn_new(mem_ctx, secret_state->sam_ldb, "cn=LSA Secrets"),
@@ -1746,7 +1813,7 @@ static NTSTATUS dcesrv_lsa_CreateSecret(struct dcesrv_call_state *dce_call, TALL
        secret_state->secret_dn = talloc_reference(secret_state, msg->dn);
 
        /* create the secret */
-       ret = samdb_add(secret_state->sam_ldb, mem_ctx, msg);
+       ret = ldb_add(secret_state->sam_ldb, msg);
        if (ret != 0) {
                DEBUG(0,("Failed to create secret record %s: %s\n",
                         ldb_dn_get_linearized(msg->dn), 
@@ -1798,6 +1865,16 @@ static NTSTATUS dcesrv_lsa_OpenSecret(struct dcesrv_call_state *dce_call, TALLOC
                return NT_STATUS_INVALID_PARAMETER;
        }
        
+       switch (security_session_user_level(dce_call->conn->auth_state.session_info))
+       {
+       case SECURITY_SYSTEM:
+       case SECURITY_ADMINISTRATOR:
+               break;
+       default:
+               /* Users and annonymous are not allowed to access secrets */
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
        secret_state = talloc(mem_ctx, struct lsa_secret_state);
        if (!secret_state) {
                return NT_STATUS_NO_MEMORY;
@@ -1829,9 +1906,10 @@ static NTSTATUS dcesrv_lsa_OpenSecret(struct dcesrv_call_state *dce_call, TALLOC
                }
        
        } else {
-               secret_state->sam_ldb = talloc_reference(secret_state, secrets_db_connect(mem_ctx));
-
                secret_state->global = false;
+               secret_state->sam_ldb = talloc_reference(secret_state, 
+                                secrets_db_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx));
+
                name = r->in.name.string;
                if (strlen(name) < 1) {
                        return NT_STATUS_INVALID_PARAMETER;
@@ -1935,22 +2013,14 @@ static NTSTATUS dcesrv_lsa_SetSecret(struct dcesrv_call_state *dce_call, TALLOC_
                }
 
                if (!r->in.new_val) {
-                       /* This behaviour varies depending of if this is a local, or a global secret... */
-                       if (secret_state->global) {
-                               /* set old value mtime */
-                               if (samdb_msg_add_uint64(secret_state->sam_ldb, 
-                                                        mem_ctx, msg, "lastSetTime", nt_now) != 0) { 
-                                       return NT_STATUS_NO_MEMORY; 
-                               }
-                       } else {
-                               if (samdb_msg_add_delete(secret_state->sam_ldb, 
-                                                        mem_ctx, msg, "currentValue")) {
-                                       return NT_STATUS_NO_MEMORY;
-                               }
-                               if (samdb_msg_add_delete(secret_state->sam_ldb, 
-                                                        mem_ctx, msg, "lastSetTime")) {
-                                       return NT_STATUS_NO_MEMORY;
-                               }
+                       /* set old value mtime */
+                       if (samdb_msg_add_uint64(secret_state->sam_ldb, 
+                                                mem_ctx, msg, "lastSetTime", nt_now) != 0) { 
+                               return NT_STATUS_NO_MEMORY; 
+                       }
+                       if (samdb_msg_add_delete(secret_state->sam_ldb, 
+                                                mem_ctx, msg, "currentValue")) {
+                               return NT_STATUS_NO_MEMORY;
                        }
                }
        }
@@ -2063,6 +2133,17 @@ static NTSTATUS dcesrv_lsa_QuerySecret(struct dcesrv_call_state *dce_call, TALLO
 
        DCESRV_PULL_HANDLE(h, r->in.sec_handle, LSA_HANDLE_SECRET);
 
+       /* Ensure user is permitted to read this... */
+       switch (security_session_user_level(dce_call->conn->auth_state.session_info))
+       {
+       case SECURITY_SYSTEM:
+       case SECURITY_ADMINISTRATOR:
+               break;
+       default:
+               /* Users and annonymous are not allowed to read secrets */
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
        secret_state = h->data;
 
        /* pull all the user attributes */
@@ -2248,16 +2329,6 @@ static NTSTATUS dcesrv_lsa_LookupPrivDisplayName(struct dcesrv_call_state *dce_c
 }
 
 
-/* 
-  lsa_DeleteObject
-*/
-static NTSTATUS dcesrv_lsa_DeleteObject(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct lsa_DeleteObject *r)
-{
-       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
-}
-
-
 /* 
   lsa_EnumAccountsWithUserRight
 */
@@ -2433,7 +2504,42 @@ static NTSTATUS dcesrv_lsa_QueryDomainInformationPolicy(struct dcesrv_call_state
                                                 TALLOC_CTX *mem_ctx,
                                                 struct lsa_QueryDomainInformationPolicy *r)
 {
-       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+       r->out.info = talloc(mem_ctx, union lsa_DomainInformationPolicy);
+       if (!r->out.info) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       switch (r->in.level) {
+       case LSA_DOMAIN_INFO_POLICY_EFS:
+               talloc_free(r->out.info);
+               r->out.info = NULL;
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       case LSA_DOMAIN_INFO_POLICY_KERBEROS:
+       {
+               struct lsa_DomainInfoKerberos *k = &r->out.info->kerberos_info;
+               struct smb_krb5_context *smb_krb5_context;
+               int ret = smb_krb5_init_context(mem_ctx, 
+                                                       dce_call->event_ctx, 
+                                                       dce_call->conn->dce_ctx->lp_ctx,
+                                                       &smb_krb5_context);
+               if (ret != 0) {
+                       talloc_free(r->out.info);
+                       r->out.info = NULL;
+                       return NT_STATUS_INTERNAL_ERROR;
+               }
+               k->enforce_restrictions = 0; /* FIXME, details missing from MS-LSAD 2.2.53 */
+               k->service_tkt_lifetime = 0; /* Need to find somewhere to store this, and query in KDC too */
+               k->user_tkt_lifetime = 0;    /* Need to find somewhere to store this, and query in KDC too */
+               k->user_tkt_renewaltime = 0; /* Need to find somewhere to store this, and query in KDC too */
+               k->clock_skew = krb5_get_max_time_skew(smb_krb5_context->krb5_context);
+               talloc_free(smb_krb5_context);
+               return NT_STATUS_OK;
+       }
+       default:
+               talloc_free(r->out.info);
+               r->out.info = NULL;
+               return NT_STATUS_INVALID_INFO_CLASS;
+       }
 }
 
 /*