s4-lsa: fixed breakage of lsa server
[ira/wip.git] / source4 / rpc_server / lsa / lsa_lookup.c
index c6b9e3bd406c78eeca6147ab5da4418ae3feff7c..a164ad6d94ecb831b05a9c92eae1ca8f8f917775 100644 (file)
@@ -43,6 +43,11 @@ static const struct {
                .sid = SID_CREATOR_GROUP,
                .rtype = SID_NAME_WKN_GRP,
        },
+       {
+               .name = "Owner Rights",
+               .sid = SID_OWNER_RIGHTS,
+               .rtype = SID_NAME_WKN_GRP,
+       },
        {
                .domain = "NT AUTHORITY",
                .name = "Dialup",
@@ -111,7 +116,7 @@ static const struct {
        },
        {
                .domain = "NT AUTHORITY",
-               .name = "Termainal Server User",
+               .name = "Terminal Server User",
                .sid = SID_NT_TERMINAL_SERVER_USERS,
                .rtype = SID_NAME_WKN_GRP,
        },
@@ -145,6 +150,42 @@ static const struct {
                .sid = SID_NT_NETWORK_SERVICE,
                .rtype = SID_NAME_WKN_GRP,
        },
+       {
+               .domain = "NT AUTHORITY",
+               .name = "Digest Authentication",
+               .sid = SID_NT_DIGEST_AUTHENTICATION,
+               .rtype = SID_NAME_WKN_GRP,
+       },
+       {
+               .domain = "NT AUTHORITY",
+               .name = "Enterprise Domain Controllers",
+               .sid = SID_NT_ENTERPRISE_DCS,
+               .rtype = SID_NAME_WKN_GRP,
+       },
+       {
+               .domain = "NT AUTHORITY",
+               .name = "NTLM Authentication",
+               .sid = SID_NT_NTLM_AUTHENTICATION,
+               .rtype = SID_NAME_WKN_GRP,
+       },
+       {
+               .domain = "NT AUTHORITY",
+               .name = "Other Organization",
+               .sid = SID_NT_OTHER_ORGANISATION,
+               .rtype = SID_NAME_WKN_GRP,
+       },
+       {
+               .domain = "NT AUTHORITY",
+               .name = "SChannel Authentication",
+               .sid = SID_NT_SCHANNEL_AUTHENTICATION,
+               .rtype = SID_NAME_WKN_GRP,
+       },
+       {
+               .domain = "NT AUTHORITY",
+               .name = "IUSR",
+               .sid = SID_NT_IUSR,
+               .rtype = SID_NAME_WKN_GRP,
+       },
        {
                .sid = NULL,
        }
@@ -195,10 +236,12 @@ static NTSTATUS lookup_well_known_sids(TALLOC_CTX *mem_ctx,
 /*
   lookup a SID for 1 name
 */
-static NTSTATUS dcesrv_lsa_lookup_name(struct loadparm_context *lp_ctx,
+static NTSTATUS dcesrv_lsa_lookup_name(struct tevent_context *ev_ctx, 
+                                      struct loadparm_context *lp_ctx,
                                       struct lsa_policy_state *state, TALLOC_CTX *mem_ctx,
-                               const char *name, const char **authority_name, 
-                               struct dom_sid **sid, enum lsa_SidType *rtype)
+                                      const char *name, const char **authority_name, 
+                                      struct dom_sid **sid, enum lsa_SidType *rtype,
+                                      uint32_t *rid)
 {
        int ret, atype, i;
        struct ldb_message **res;
@@ -218,7 +261,7 @@ static NTSTATUS dcesrv_lsa_lookup_name(struct loadparm_context *lp_ctx,
                }
                username = p + 1;
        } else if (strchr_m(name, '@')) {
-               status = crack_name_to_nt4_name(mem_ctx, lp_ctx, DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL, name, &domain, &username);
+               status = crack_name_to_nt4_name(mem_ctx, ev_ctx, lp_ctx, DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL, name, &domain, &username);
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(3, ("Failed to crack name %s into an NT4 name: %s\n", name, nt_errstr(status)));
                        return status;
@@ -232,6 +275,15 @@ static NTSTATUS dcesrv_lsa_lookup_name(struct loadparm_context *lp_ctx,
                /* Look up table of well known names */
                status = lookup_well_known_names(mem_ctx, NULL, username, authority_name, sid, rtype);
                if (NT_STATUS_IS_OK(status)) {
+                       dom_sid_split_rid(NULL, *sid, NULL, rid);
+                       return NT_STATUS_OK;
+               }
+
+               if (username == NULL) {
+                       *authority_name = NAME_BUILTIN;
+                       *sid = dom_sid_parse_talloc(mem_ctx, SID_BUILTIN);
+                       *rtype = SID_NAME_DOMAIN;
+                       *rid = 0xFFFFFFFF;
                        return NT_STATUS_OK;
                }
 
@@ -239,24 +291,28 @@ static NTSTATUS dcesrv_lsa_lookup_name(struct loadparm_context *lp_ctx,
                        *authority_name = NAME_NT_AUTHORITY;
                        *sid =  dom_sid_parse_talloc(mem_ctx, SID_NT_AUTHORITY);
                        *rtype = SID_NAME_DOMAIN;
+                       dom_sid_split_rid(NULL, *sid, NULL, rid);
                        return NT_STATUS_OK;
                }
                if (strcasecmp_m(username, NAME_BUILTIN) == 0) { 
                        *authority_name = NAME_BUILTIN;
                        *sid = dom_sid_parse_talloc(mem_ctx, SID_BUILTIN);
                        *rtype = SID_NAME_DOMAIN;
+                       *rid = 0xFFFFFFFF;
                        return NT_STATUS_OK;
                }
                if (strcasecmp_m(username, state->domain_dns) == 0) { 
                        *authority_name = state->domain_name;
                        *sid =  state->domain_sid;
                        *rtype = SID_NAME_DOMAIN;
+                       *rid = 0xFFFFFFFF;
                        return NT_STATUS_OK;
                }
                if (strcasecmp_m(username, state->domain_name) == 0) { 
                        *authority_name = state->domain_name;
                        *sid =  state->domain_sid;
                        *rtype = SID_NAME_DOMAIN;
+                       *rid = 0xFFFFFFFF;
                        return NT_STATUS_OK;
                }
                
@@ -265,7 +321,7 @@ static NTSTATUS dcesrv_lsa_lookup_name(struct loadparm_context *lp_ctx,
                if (!name) {
                        return NT_STATUS_NO_MEMORY;
                }
-               status = dcesrv_lsa_lookup_name(lp_ctx, state, mem_ctx, name, authority_name, sid, rtype);
+               status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype, rid);
                if (NT_STATUS_IS_OK(status)) {
                        return status;
                }
@@ -275,7 +331,7 @@ static NTSTATUS dcesrv_lsa_lookup_name(struct loadparm_context *lp_ctx,
                if (!name) {
                        return NT_STATUS_NO_MEMORY;
                }
-               status = dcesrv_lsa_lookup_name(lp_ctx, state, mem_ctx, name, authority_name, sid, rtype);
+               status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype, rid);
                if (NT_STATUS_IS_OK(status)) {
                        return status;
                }
@@ -285,7 +341,7 @@ static NTSTATUS dcesrv_lsa_lookup_name(struct loadparm_context *lp_ctx,
                if (!name) {
                        return NT_STATUS_NO_MEMORY;
                }
-               status = dcesrv_lsa_lookup_name(lp_ctx, state, mem_ctx, name, authority_name, sid, rtype);
+               status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype, rid);
                if (NT_STATUS_IS_OK(status)) {
                        return status;
                }
@@ -296,12 +352,17 @@ static NTSTATUS dcesrv_lsa_lookup_name(struct loadparm_context *lp_ctx,
                        *authority_name = NAME_NT_AUTHORITY;
                        *sid = dom_sid_parse_talloc(mem_ctx, SID_NT_AUTHORITY);
                        *rtype = SID_NAME_DOMAIN;
+                       dom_sid_split_rid(NULL, *sid, NULL, rid);
                        return NT_STATUS_OK;
                }
 
                /* Look up table of well known names */
-               return lookup_well_known_names(mem_ctx, domain, username, authority_name, 
-                                              sid, rtype);
+               status = lookup_well_known_names(mem_ctx, domain, username, authority_name, 
+                                                sid, rtype);
+               if (NT_STATUS_IS_OK(status)) {
+                       dom_sid_split_rid(NULL, *sid, NULL, rid);
+               }
+               return status;
        } else if (strcasecmp_m(domain, NAME_BUILTIN) == 0) {
                *authority_name = NAME_BUILTIN;
                domain_dn = state->builtin_dn;
@@ -329,6 +390,7 @@ static NTSTATUS dcesrv_lsa_lookup_name(struct loadparm_context *lp_ctx,
        if (!*username) {
                *sid = domain_sid;
                *rtype = SID_NAME_DOMAIN;
+               *rid = 0xFFFFFFFF;
                return NT_STATUS_OK;
        }
        
@@ -352,11 +414,12 @@ static NTSTATUS dcesrv_lsa_lookup_name(struct loadparm_context *lp_ctx,
 
                atype = samdb_result_uint(res[i], "sAMAccountType", 0);
                        
-               *rtype = samdb_atype_map(atype);
+               *rtype = ds_atype_map(atype);
                if (*rtype == SID_NAME_UNKNOWN) {
                        return STATUS_SOME_UNMAPPED;
                }
 
+               dom_sid_split_rid(NULL, *sid, NULL, rid);
                return NT_STATUS_OK;
        }
 
@@ -461,7 +524,7 @@ static NTSTATUS dcesrv_lsa_lookup_sid(struct lsa_policy_state *state, TALLOC_CTX
 
                atype = samdb_result_uint(res[0], "sAMAccountType", 0);
 
-               *rtype = samdb_atype_map(atype);
+               *rtype = ds_atype_map(atype);
 
                return NT_STATUS_OK;
        }
@@ -480,20 +543,33 @@ NTSTATUS dcesrv_lsa_LookupSids2(struct dcesrv_call_state *dce_call,
                                struct lsa_LookupSids2 *r)
 {
        struct lsa_policy_state *state;
+       struct lsa_RefDomainList *domains = NULL;
        int i;
        NTSTATUS status = NT_STATUS_OK;
 
-       r->out.domains = NULL;
+       if (r->in.level < LSA_LOOKUP_NAMES_ALL ||
+           r->in.level > LSA_LOOKUP_NAMES_RODC_REFERRAL_TO_FULL_DC) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       *r->out.domains = NULL;
+
+       /* NOTE: the WSPP test suite tries SIDs with invalid revision numbers,
+          and expects NT_STATUS_INVALID_PARAMETER back - we just treat it as 
+          an unknown SID. We could add a SID validator here. (tridge) 
+          MS-DTYP 2.4.2
+       */
 
        status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, &state);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       r->out.domains = talloc_zero(mem_ctx,  struct lsa_RefDomainList);
-       if (r->out.domains == NULL) {
+       domains = talloc_zero(r->out.domains,  struct lsa_RefDomainList);
+       if (domains == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
+       *r->out.domains = domains;
 
        r->out.names = talloc_zero(mem_ctx,  struct lsa_TransNameArray2);
        if (r->out.names == NULL) {
@@ -539,9 +615,9 @@ NTSTATUS dcesrv_lsa_LookupSids2(struct dcesrv_call_state *dce_call,
                /* set up the authority table */
                status2 = dcesrv_lsa_authority_list(state, mem_ctx, rtype, 
                                                    authority_name, sid, 
-                                                   r->out.domains, &sid_index);
+                                                   domains, &sid_index);
                if (!NT_STATUS_IS_OK(status2)) {
-                       return status2;
+                       continue;
                }
 
                r->out.names->names[i].sid_type    = rtype;
@@ -551,7 +627,7 @@ NTSTATUS dcesrv_lsa_LookupSids2(struct dcesrv_call_state *dce_call,
 
                (*r->out.count)++;
        }
-       
+
        if (*r->out.count == 0) {
                return NT_STATUS_NONE_MAPPED;
        }
@@ -578,6 +654,8 @@ NTSTATUS dcesrv_lsa_LookupSids3(struct dcesrv_call_state *dce_call,
        NTSTATUS status;
        struct dcesrv_handle *h;
 
+       ZERO_STRUCT(r2);
+       
        /* No policy handle on the wire, so make one up here */
        r2.in.handle = talloc(mem_ctx, struct policy_handle);
        if (!r2.in.handle) {
@@ -601,15 +679,13 @@ NTSTATUS dcesrv_lsa_LookupSids3(struct dcesrv_call_state *dce_call,
        r2.in.names    = r->in.names;
        r2.in.level    = r->in.level;
        r2.in.count    = r->in.count;
-       r2.in.unknown1 = r->in.unknown1;
-       r2.in.unknown2 = r->in.unknown2;
+       r2.in.lookup_options = r->in.lookup_options;
+       r2.in.client_revision = r->in.client_revision;
        r2.out.count   = r->out.count;
        r2.out.names   = r->out.names;
+       r2.out.domains = r->out.domains;
 
        status = dcesrv_lsa_LookupSids2(dce_call, mem_ctx, &r2);
-       if (dce_call->fault_code != 0) {
-               return status;
-       }
 
        r->out.domains = r2.out.domains;
        r->out.names   = r2.out.names;
@@ -629,20 +705,22 @@ NTSTATUS dcesrv_lsa_LookupSids(struct dcesrv_call_state *dce_call, TALLOC_CTX *m
        NTSTATUS status;
        int i;
 
+       ZERO_STRUCT(r2);
+
        r2.in.handle   = r->in.handle;
        r2.in.sids     = r->in.sids;
        r2.in.names    = NULL;
        r2.in.level    = r->in.level;
        r2.in.count    = r->in.count;
-       r2.in.unknown1 = 0;
-       r2.in.unknown2 = 0;
+       r2.in.lookup_options = 0;
+       r2.in.client_revision = 0;
        r2.out.count   = r->out.count;
        r2.out.names   = NULL;
+       r2.out.domains = r->out.domains;
 
        status = dcesrv_lsa_LookupSids2(dce_call, mem_ctx, &r2);
-       if (dce_call->fault_code != 0) {
-               return status;
-       }
+       /* we deliberately don't check for error from the above,
+          as even on error we are supposed to return the names  */
 
        r->out.domains = r2.out.domains;
        if (!r2.out.names) {
@@ -681,17 +759,24 @@ NTSTATUS dcesrv_lsa_LookupNames3(struct dcesrv_call_state *dce_call,
        struct dcesrv_handle *policy_handle;
        int i;
        struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+       struct lsa_RefDomainList *domains;
 
        DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);
 
+       if (r->in.level < LSA_LOOKUP_NAMES_ALL ||
+           r->in.level > LSA_LOOKUP_NAMES_RODC_REFERRAL_TO_FULL_DC) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
        policy_state = policy_handle->data;
 
-       r->out.domains = NULL;
+       *r->out.domains = NULL;
 
-       r->out.domains = talloc_zero(mem_ctx,  struct lsa_RefDomainList);
-       if (r->out.domains == NULL) {
+       domains = talloc_zero(mem_ctx,  struct lsa_RefDomainList);
+       if (domains == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
+       *r->out.domains = domains;
 
        r->out.sids = talloc_zero(mem_ctx,  struct lsa_TransSidArray3);
        if (r->out.sids == NULL) {
@@ -710,7 +795,7 @@ NTSTATUS dcesrv_lsa_LookupNames3(struct dcesrv_call_state *dce_call,
                const char *name = r->in.names[i].string;
                const char *authority_name;
                struct dom_sid *sid;
-               uint32_t sid_index;
+               uint32_t sid_index, rid;
                enum lsa_SidType rtype;
                NTSTATUS status2;
 
@@ -719,23 +804,24 @@ NTSTATUS dcesrv_lsa_LookupNames3(struct dcesrv_call_state *dce_call,
                r->out.sids->sids[i].sid_type    = SID_NAME_UNKNOWN;
                r->out.sids->sids[i].sid         = NULL;
                r->out.sids->sids[i].sid_index   = 0xFFFFFFFF;
-               r->out.sids->sids[i].unknown     = 0;
+               r->out.sids->sids[i].flags       = 0;
 
-               status2 = dcesrv_lsa_lookup_name(lp_ctx, policy_state, mem_ctx, name, &authority_name, &sid, &rtype);
+               status2 = dcesrv_lsa_lookup_name(dce_call->event_ctx, lp_ctx, policy_state, mem_ctx, name, 
+                                                &authority_name, &sid, &rtype, &rid);
                if (!NT_STATUS_IS_OK(status2) || sid->num_auths == 0) {
                        continue;
                }
 
                status2 = dcesrv_lsa_authority_list(policy_state, mem_ctx, rtype, authority_name, 
-                                                   sid, r->out.domains, &sid_index);
+                                                   sid, domains, &sid_index);
                if (!NT_STATUS_IS_OK(status2)) {
-                       return status2;
+                       continue;
                }
 
                r->out.sids->sids[i].sid_type    = rtype;
                r->out.sids->sids[i].sid         = sid;
                r->out.sids->sids[i].sid_index   = sid_index;
-               r->out.sids->sids[i].unknown     = 0;
+               r->out.sids->sids[i].flags       = 0;
 
                (*r->out.count)++;
        }
@@ -764,6 +850,8 @@ NTSTATUS dcesrv_lsa_LookupNames4(struct dcesrv_call_state *dce_call, TALLOC_CTX
        NTSTATUS status;
        struct dcesrv_handle *h;
 
+       ZERO_STRUCT(r2);
+
        /* No policy handle on the wire, so make one up here */
        r2.in.handle = talloc(mem_ctx, struct policy_handle);
        if (!r2.in.handle) {
@@ -785,18 +873,16 @@ NTSTATUS dcesrv_lsa_LookupNames4(struct dcesrv_call_state *dce_call, TALLOC_CTX
 
        r2.in.num_names = r->in.num_names;
        r2.in.names = r->in.names;
+       r2.in.level = r->in.level;
        r2.in.sids = r->in.sids;
        r2.in.count = r->in.count;
-       r2.in.unknown1 = r->in.unknown1;
-       r2.in.unknown2 = r->in.unknown2;
+       r2.in.lookup_options = r->in.lookup_options;
+       r2.in.client_revision = r->in.client_revision;
        r2.out.domains = r->out.domains;
        r2.out.sids = r->out.sids;
        r2.out.count = r->out.count;
        
        status = dcesrv_lsa_LookupNames3(dce_call, mem_ctx, &r2);
-       if (dce_call->fault_code != 0) {
-               return status;
-       }
        
        r->out.domains = r2.out.domains;
        r->out.sids = r2.out.sids;
@@ -815,17 +901,24 @@ NTSTATUS dcesrv_lsa_LookupNames2(struct dcesrv_call_state *dce_call,
        struct dcesrv_handle *h;
        int i;
        struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+       struct lsa_RefDomainList *domains;
 
-       r->out.domains = NULL;
+       *r->out.domains = NULL;
 
        DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
 
+       if (r->in.level < LSA_LOOKUP_NAMES_ALL ||
+           r->in.level > LSA_LOOKUP_NAMES_RODC_REFERRAL_TO_FULL_DC) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
        state = h->data;
 
-       r->out.domains = talloc_zero(mem_ctx,  struct lsa_RefDomainList);
-       if (r->out.domains == NULL) {
+       domains = talloc_zero(mem_ctx,  struct lsa_RefDomainList);
+       if (domains == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
+       *r->out.domains = domains;
 
        r->out.sids = talloc_zero(mem_ctx,  struct lsa_TransSidArray2);
        if (r->out.sids == NULL) {
@@ -844,30 +937,33 @@ NTSTATUS dcesrv_lsa_LookupNames2(struct dcesrv_call_state *dce_call,
                const char *name = r->in.names[i].string;
                const char *authority_name;
                struct dom_sid *sid;
-               uint32_t rtype, sid_index;
+               uint32_t rtype, sid_index, rid=0;
                NTSTATUS status2;
 
                r->out.sids->count++;
 
                r->out.sids->sids[i].sid_type    = SID_NAME_UNKNOWN;
-               r->out.sids->sids[i].rid         = 0xFFFFFFFF;
+               /* MS-LSAT 3.1.4.7 - rid zero is considered equivalent
+                  to sid NULL - so we should return 0 rid for
+                  unmapped entries */
+               r->out.sids->sids[i].rid         = 0;
                r->out.sids->sids[i].sid_index   = 0xFFFFFFFF;
                r->out.sids->sids[i].unknown     = 0;
 
-               status2 = dcesrv_lsa_lookup_name(lp_ctx, state, mem_ctx, name, 
-                                                &authority_name, &sid, &rtype);
+               status2 = dcesrv_lsa_lookup_name(dce_call->event_ctx, lp_ctx, state, mem_ctx, name, 
+                                                &authority_name, &sid, &rtype, &rid);
                if (!NT_STATUS_IS_OK(status2)) {
                        continue;
                }
 
                status2 = dcesrv_lsa_authority_list(state, mem_ctx, rtype, authority_name, 
-                                                   sid, r->out.domains, &sid_index);
+                                                   sid, domains, &sid_index);
                if (!NT_STATUS_IS_OK(status2)) {
-                       return status2;
+                       continue;
                }
 
                r->out.sids->sids[i].sid_type    = rtype;
-               r->out.sids->sids[i].rid         = sid->sub_auths[sid->num_auths-1];
+               r->out.sids->sids[i].rid         = rid;
                r->out.sids->sids[i].sid_index   = sid_index;
                r->out.sids->sids[i].unknown     = 0;
 
@@ -894,22 +990,24 @@ NTSTATUS dcesrv_lsa_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *
        NTSTATUS status;
        int i;
 
+       ZERO_STRUCT(r2);
+
        r2.in.handle    = r->in.handle;
        r2.in.num_names = r->in.num_names;
        r2.in.names     = r->in.names;
        r2.in.sids      = NULL;
        r2.in.level     = r->in.level;
        r2.in.count     = r->in.count;
-       r2.in.unknown1  = 0;
-       r2.in.unknown2  = 0;
+       r2.in.lookup_options = 0;
+       r2.in.client_revision = 0;
        r2.out.count    = r->out.count;
+       r2.out.domains  = r->out.domains;
 
        status = dcesrv_lsa_LookupNames2(dce_call, mem_ctx, &r2);
-       if (dce_call->fault_code != 0) {
+       if (r2.out.sids == NULL) {
                return status;
        }
 
-       r->out.domains = r2.out.domains;
        r->out.sids = talloc(mem_ctx, struct lsa_TransSidArray);
        if (r->out.sids == NULL) {
                return NT_STATUS_NO_MEMORY;