eaeab236fc0111d41ef6c67db685d012df387e7f
[samba.git] / source4 / rpc_server / common / sid_helper.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    common sid helper functions
5
6    Copyright (C) Catalyst.NET Ltd 2017
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "rpc_server/dcerpc_server.h"
24 #include "librpc/gen_ndr/ndr_security.h"
25 #include "source4/dsdb/samdb/samdb.h"
26 #include "rpc_server/common/sid_helper.h"
27 #include "libcli/security/security.h"
28
29 /*
30   see if any SIDs in list1 are in list2
31  */
32 bool sid_list_match(uint32_t num_sids1,
33                     const struct dom_sid *list1,
34                     uint32_t num_sids2,
35                     const struct dom_sid *list2)
36 {
37         unsigned int i, j;
38         /* do we ever have enough SIDs here to worry about O(n^2) ? */
39         for (i=0; i < num_sids1; i++) {
40                 for (j=0; j < num_sids2; j++) {
41                         if (dom_sid_equal(&list1[i], &list2[j])) {
42                                 return true;
43                         }
44                 }
45         }
46         return false;
47 }
48
49 /*
50  * Return an array of SIDs from a ldb_message given an attribute name assumes
51  * the SIDs are in NDR form (with additional sids applied on the end).
52  */
53 WERROR samdb_result_sid_array_ndr(struct ldb_context *sam_ctx,
54                                   struct ldb_message *msg,
55                                   TALLOC_CTX *mem_ctx,
56                                   const char *attr,
57                                   uint32_t *num_sids,
58                                   struct dom_sid **sids,
59                                   const struct dom_sid *additional_sids,
60                                   unsigned int num_additional)
61 {
62         struct ldb_message_element *el;
63         unsigned int i, j;
64
65         el = ldb_msg_find_element(msg, attr);
66         if (!el) {
67                 *sids = NULL;
68                 return WERR_OK;
69         }
70
71         /* Make array long enough for NULL and additional SID */
72         (*sids) = talloc_array(mem_ctx, struct dom_sid,
73                                el->num_values + num_additional);
74         W_ERROR_HAVE_NO_MEMORY(*sids);
75
76         for (i=0; i<el->num_values; i++) {
77                 enum ndr_err_code ndr_err;
78
79                 ndr_err = ndr_pull_struct_blob_all_noalloc(&el->values[i], &(*sids)[i],
80                                                (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
81                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
82                         return WERR_INTERNAL_DB_CORRUPTION;
83                 }
84         }
85
86         for (j = 0; j < num_additional; j++) {
87                 (*sids)[i++] = additional_sids[j];
88         }
89
90         *num_sids = i;
91
92         return WERR_OK;
93 }
94
95 /*
96   return an array of SIDs from a ldb_message given an attribute name
97   assumes the SIDs are in extended DN format
98  */
99 WERROR samdb_result_sid_array_dn(struct ldb_context *sam_ctx,
100                                  struct ldb_message *msg,
101                                  TALLOC_CTX *mem_ctx,
102                                  const char *attr,
103                                  uint32_t *num_sids,
104                                  struct dom_sid **sids)
105 {
106         struct ldb_message_element *el;
107         unsigned int i;
108
109         el = ldb_msg_find_element(msg, attr);
110         if (!el) {
111                 *sids = NULL;
112                 return WERR_OK;
113         }
114
115         (*sids) = talloc_array(mem_ctx, struct dom_sid, el->num_values + 1);
116         W_ERROR_HAVE_NO_MEMORY(*sids);
117
118         for (i=0; i<el->num_values; i++) {
119                 struct ldb_dn *dn = ldb_dn_from_ldb_val(mem_ctx, sam_ctx, &el->values[i]);
120                 NTSTATUS status;
121                 struct dom_sid sid = { 0, };
122
123                 status = dsdb_get_extended_dn_sid(dn, &sid, "SID");
124                 if (!NT_STATUS_IS_OK(status)) {
125                         return WERR_INTERNAL_DB_CORRUPTION;
126                 }
127                 (*sids)[i] = sid;
128         }
129         *num_sids = i;
130
131         return WERR_OK;
132 }
133
134 WERROR samdb_confirm_rodc_allowed_to_repl_to_sid_list(struct ldb_context *sam_ctx,
135                                                       struct ldb_message *rodc_msg,
136                                                       uint32_t num_token_sids,
137                                                       struct dom_sid *token_sids)
138 {
139         uint32_t num_never_reveal_sids, num_reveal_sids;
140         struct dom_sid *never_reveal_sids, *reveal_sids;
141         TALLOC_CTX *frame = talloc_stackframe();
142         WERROR werr = samdb_result_sid_array_dn(sam_ctx, rodc_msg,
143                                                 frame, "msDS-NeverRevealGroup",
144                                                 &num_never_reveal_sids,
145                                                 &never_reveal_sids);
146         if (!W_ERROR_IS_OK(werr)) {
147                 TALLOC_FREE(frame);
148                 return WERR_DS_DRA_SECRETS_DENIED;
149         }
150
151         werr = samdb_result_sid_array_dn(sam_ctx, rodc_msg,
152                                          frame, "msDS-RevealOnDemandGroup",
153                                          &num_reveal_sids,
154                                          &reveal_sids);
155         if (!W_ERROR_IS_OK(werr)) {
156                 TALLOC_FREE(frame);
157                 return WERR_DS_DRA_SECRETS_DENIED;
158         }
159
160         if (never_reveal_sids &&
161             sid_list_match(num_token_sids,
162                            token_sids,
163                            num_never_reveal_sids,
164                            never_reveal_sids)) {
165                 TALLOC_FREE(frame);
166                 return WERR_DS_DRA_SECRETS_DENIED;
167         }
168
169         if (reveal_sids &&
170             sid_list_match(num_token_sids,
171                            token_sids,
172                            num_reveal_sids,
173                            reveal_sids)) {
174                 TALLOC_FREE(frame);
175                 return WERR_OK;
176         }
177
178         TALLOC_FREE(frame);
179         return WERR_DS_DRA_SECRETS_DENIED;
180
181 }