/src/samba/source4/dsdb/samdb/samdb.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | |
4 | | interface functions for the sam database |
5 | | |
6 | | Copyright (C) Andrew Tridgell 2004 |
7 | | Copyright (C) Volker Lendecke 2004 |
8 | | Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006 |
9 | | |
10 | | This program is free software; you can redistribute it and/or modify |
11 | | it under the terms of the GNU General Public License as published by |
12 | | the Free Software Foundation; either version 3 of the License, or |
13 | | (at your option) any later version. |
14 | | |
15 | | This program is distributed in the hope that it will be useful, |
16 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | | GNU General Public License for more details. |
19 | | |
20 | | You should have received a copy of the GNU General Public License |
21 | | along with this program. If not, see <http://www.gnu.org/licenses/>. |
22 | | */ |
23 | | |
24 | | #include "includes.h" |
25 | | #include "librpc/gen_ndr/ndr_netlogon.h" |
26 | | #include "librpc/gen_ndr/ndr_security.h" |
27 | | #include "lib/events/events.h" |
28 | | #include "lib/ldb-samba/ldb_wrap.h" |
29 | | #include <ldb.h> |
30 | | #include <ldb_errors.h> |
31 | | #include "libcli/security/security.h" |
32 | | #include "libcli/security/claims-conversions.h" |
33 | | #include "libcli/auth/libcli_auth.h" |
34 | | #include "libcli/ldap/ldap_ndr.h" |
35 | | #include "system/time.h" |
36 | | #include "system/filesys.h" |
37 | | #include "ldb_wrap.h" |
38 | | #include "../lib/util/util_ldb.h" |
39 | | #include "dsdb/samdb/samdb.h" |
40 | | #include "../libds/common/flags.h" |
41 | | #include "param/param.h" |
42 | | #include "lib/events/events.h" |
43 | | #include "auth/credentials/credentials.h" |
44 | | #include "param/secrets.h" |
45 | | #include "auth/auth.h" |
46 | | #include "lib/tsocket/tsocket.h" |
47 | | #include "lib/param/loadparm.h" |
48 | | |
49 | | /* |
50 | | connect to the SAM database specified by URL |
51 | | return an opaque context pointer on success, or NULL on failure |
52 | | */ |
53 | | int samdb_connect_url(TALLOC_CTX *mem_ctx, |
54 | | struct tevent_context *ev_ctx, |
55 | | struct loadparm_context *lp_ctx, |
56 | | struct auth_session_info *session_info, |
57 | | unsigned int flags, |
58 | | const char *url, |
59 | | const struct tsocket_address *remote_address, |
60 | | struct ldb_context **ldb_ret, |
61 | | char **errstring) |
62 | 0 | { |
63 | 0 | struct ldb_context *ldb = NULL; |
64 | 0 | int ret; |
65 | 0 | *ldb_ret = NULL; |
66 | 0 | *errstring = NULL; |
67 | | |
68 | | /* We create sam.ldb in provision, and never anywhere else */ |
69 | 0 | flags |= LDB_FLG_DONT_CREATE_DB; |
70 | |
|
71 | 0 | if (remote_address == NULL) { |
72 | 0 | ldb = ldb_wrap_find(url, ev_ctx, lp_ctx, |
73 | 0 | session_info, NULL, flags); |
74 | 0 | if (ldb != NULL) { |
75 | 0 | *ldb_ret = talloc_reference(mem_ctx, ldb); |
76 | 0 | if (*ldb_ret == NULL) { |
77 | 0 | return LDB_ERR_OPERATIONS_ERROR; |
78 | 0 | } |
79 | 0 | return LDB_SUCCESS; |
80 | 0 | } |
81 | 0 | } |
82 | | |
83 | 0 | ldb = samba_ldb_init(mem_ctx, ev_ctx, lp_ctx, session_info, NULL); |
84 | |
|
85 | 0 | if (ldb == NULL) { |
86 | 0 | *errstring = talloc_asprintf(mem_ctx, |
87 | 0 | "Failed to set up Samba ldb " |
88 | 0 | "wrappers with samba_ldb_init() " |
89 | 0 | "to connect to %s", |
90 | 0 | url); |
91 | 0 | return LDB_ERR_OPERATIONS_ERROR; |
92 | 0 | } |
93 | | |
94 | 0 | dsdb_set_global_schema(ldb); |
95 | |
|
96 | 0 | ret = samba_ldb_connect(ldb, lp_ctx, url, flags); |
97 | 0 | if (ret != LDB_SUCCESS) { |
98 | 0 | *errstring = talloc_asprintf(mem_ctx, |
99 | 0 | "Failed to connect to %s: %s", |
100 | 0 | url, |
101 | 0 | ldb_errstring(ldb)); |
102 | 0 | talloc_free(ldb); |
103 | 0 | return LDB_ERR_OPERATIONS_ERROR; |
104 | 0 | } |
105 | | |
106 | | /* |
107 | | * If a remote_address was specified, then set it on the DB |
108 | | * and do not add to the wrap list (as we need to keep the LDB |
109 | | * pointer unique for the address). |
110 | | * |
111 | | * We use this for audit logging and for the "netlogon" attribute |
112 | | */ |
113 | 0 | if (remote_address != NULL) { |
114 | 0 | ldb_set_opaque(ldb, "remoteAddress", |
115 | 0 | discard_const(remote_address)); |
116 | 0 | *ldb_ret = ldb; |
117 | 0 | return LDB_SUCCESS; |
118 | 0 | } |
119 | | |
120 | 0 | if (flags & SAMBA_LDB_WRAP_CONNECT_FLAG_NO_SHARE_CONTEXT) { |
121 | 0 | *ldb_ret = ldb; |
122 | 0 | return LDB_SUCCESS; |
123 | 0 | } |
124 | | |
125 | 0 | if (!ldb_wrap_add(url, ev_ctx, lp_ctx, session_info, NULL, flags, ldb)) { |
126 | 0 | *errstring = talloc_asprintf(mem_ctx, |
127 | 0 | "Failed to add cached DB reference" |
128 | 0 | " to %s", |
129 | 0 | url); |
130 | 0 | talloc_free(ldb); |
131 | 0 | return LDB_ERR_OPERATIONS_ERROR; |
132 | 0 | } |
133 | | |
134 | 0 | *ldb_ret = ldb; |
135 | 0 | return LDB_SUCCESS; |
136 | 0 | } |
137 | | |
138 | | |
139 | | /* |
140 | | connect to the SAM database |
141 | | return an opaque context pointer on success, or NULL on failure |
142 | | */ |
143 | | struct ldb_context *samdb_connect(TALLOC_CTX *mem_ctx, |
144 | | struct tevent_context *ev_ctx, |
145 | | struct loadparm_context *lp_ctx, |
146 | | struct auth_session_info *session_info, |
147 | | const struct tsocket_address *remote_address, |
148 | | unsigned int flags) |
149 | 0 | { |
150 | 0 | char *errstring; |
151 | 0 | struct ldb_context *ldb; |
152 | 0 | int ret = samdb_connect_url(mem_ctx, |
153 | 0 | ev_ctx, |
154 | 0 | lp_ctx, |
155 | 0 | session_info, |
156 | 0 | flags, |
157 | 0 | "sam.ldb", |
158 | 0 | remote_address, |
159 | 0 | &ldb, |
160 | 0 | &errstring); |
161 | 0 | if (ret == LDB_SUCCESS) { |
162 | 0 | return ldb; |
163 | 0 | } |
164 | 0 | return NULL; |
165 | 0 | } |
166 | | |
167 | | /**************************************************************************** |
168 | | Create the SID list for this user. |
169 | | ****************************************************************************/ |
170 | | NTSTATUS security_token_create(TALLOC_CTX *mem_ctx, |
171 | | struct loadparm_context *lp_ctx, |
172 | | uint32_t num_sids, |
173 | | const struct auth_SidAttr *sids, |
174 | | uint32_t num_device_sids, |
175 | | const struct auth_SidAttr *device_sids, |
176 | | struct auth_claims auth_claims, |
177 | | uint32_t session_info_flags, |
178 | | struct security_token **token) |
179 | 0 | { |
180 | 0 | struct security_token *ptoken; |
181 | 0 | uint32_t i; |
182 | 0 | NTSTATUS status; |
183 | 0 | enum claims_evaluation_control evaluate_claims; |
184 | 0 | bool sids_are_valid = false; |
185 | 0 | bool device_sids_are_valid = false; |
186 | 0 | bool authentication_was_compounded = session_info_flags & AUTH_SESSION_INFO_FORCE_COMPOUNDED_AUTHENTICATION; |
187 | | |
188 | | /* |
189 | | * Some special-case callers can't supply the lp_ctx, but do |
190 | | * not interact with claims or conditional ACEs |
191 | | */ |
192 | 0 | if (lp_ctx == NULL) { |
193 | 0 | evaluate_claims = CLAIMS_EVALUATION_INVALID_STATE; |
194 | 0 | } else { |
195 | 0 | enum acl_claims_evaluation claims_evaultion_setting |
196 | 0 | = lpcfg_acl_claims_evaluation(lp_ctx); |
197 | | |
198 | | /* |
199 | | * We are well inside the AD DC, so we do not need to check |
200 | | * the server role etc |
201 | | */ |
202 | 0 | switch (claims_evaultion_setting) { |
203 | 0 | case ACL_CLAIMS_EVALUATION_AD_DC_ONLY: |
204 | 0 | evaluate_claims = CLAIMS_EVALUATION_ALWAYS; |
205 | 0 | break; |
206 | 0 | default: |
207 | 0 | evaluate_claims = CLAIMS_EVALUATION_NEVER; |
208 | 0 | } |
209 | 0 | } |
210 | | |
211 | 0 | ptoken = security_token_initialise(mem_ctx, evaluate_claims); |
212 | 0 | NT_STATUS_HAVE_NO_MEMORY(ptoken); |
213 | | |
214 | 0 | if (num_sids > UINT32_MAX - 6) { |
215 | 0 | talloc_free(ptoken); |
216 | 0 | return NT_STATUS_INVALID_PARAMETER; |
217 | 0 | } |
218 | 0 | ptoken->sids = talloc_array(ptoken, struct dom_sid, num_sids + 6 /* over-allocate */); |
219 | 0 | if (ptoken->sids == NULL) { |
220 | 0 | talloc_free(ptoken); |
221 | 0 | return NT_STATUS_NO_MEMORY; |
222 | 0 | } |
223 | | |
224 | 0 | ptoken->num_sids = 0; |
225 | |
|
226 | 0 | for (i = 0; i < num_sids; i++) { |
227 | 0 | uint32_t check_sid_idx; |
228 | 0 | for (check_sid_idx = 0; |
229 | 0 | check_sid_idx < ptoken->num_sids; |
230 | 0 | check_sid_idx++) { |
231 | 0 | if (dom_sid_equal(&ptoken->sids[check_sid_idx], &sids[i].sid)) { |
232 | 0 | break; |
233 | 0 | } |
234 | 0 | } |
235 | |
|
236 | 0 | if (check_sid_idx == ptoken->num_sids) { |
237 | 0 | const struct dom_sid *sid = &sids[i].sid; |
238 | |
|
239 | 0 | sids_are_valid = sids_are_valid || dom_sid_equal( |
240 | 0 | sid, &global_sid_Claims_Valid); |
241 | 0 | authentication_was_compounded = authentication_was_compounded || dom_sid_equal( |
242 | 0 | sid, &global_sid_Compounded_Authentication); |
243 | |
|
244 | 0 | ptoken->sids = talloc_realloc(ptoken, ptoken->sids, struct dom_sid, ptoken->num_sids + 1); |
245 | 0 | if (ptoken->sids == NULL) { |
246 | 0 | talloc_free(ptoken); |
247 | 0 | return NT_STATUS_NO_MEMORY; |
248 | 0 | } |
249 | | |
250 | 0 | ptoken->sids[ptoken->num_sids] = *sid; |
251 | 0 | ptoken->num_sids++; |
252 | 0 | } |
253 | 0 | } |
254 | | |
255 | 0 | if (authentication_was_compounded && num_device_sids) { |
256 | 0 | ptoken->device_sids = talloc_array(ptoken, struct dom_sid, num_device_sids); |
257 | 0 | if (ptoken->device_sids == NULL) { |
258 | 0 | talloc_free(ptoken); |
259 | 0 | return NT_STATUS_NO_MEMORY; |
260 | 0 | } |
261 | 0 | for (i = 0; i < num_device_sids; i++) { |
262 | 0 | uint32_t check_sid_idx; |
263 | 0 | for (check_sid_idx = 0; |
264 | 0 | check_sid_idx < ptoken->num_device_sids; |
265 | 0 | check_sid_idx++) { |
266 | 0 | if (dom_sid_equal(&ptoken->device_sids[check_sid_idx], &device_sids[i].sid)) { |
267 | 0 | break; |
268 | 0 | } |
269 | 0 | } |
270 | |
|
271 | 0 | if (check_sid_idx == ptoken->num_device_sids) { |
272 | 0 | const struct dom_sid *device_sid = &device_sids[i].sid; |
273 | |
|
274 | 0 | device_sids_are_valid = device_sids_are_valid || dom_sid_equal( |
275 | 0 | device_sid, &global_sid_Claims_Valid); |
276 | |
|
277 | 0 | ptoken->device_sids = talloc_realloc(ptoken, |
278 | 0 | ptoken->device_sids, |
279 | 0 | struct dom_sid, |
280 | 0 | ptoken->num_device_sids + 1); |
281 | 0 | if (ptoken->device_sids == NULL) { |
282 | 0 | talloc_free(ptoken); |
283 | 0 | return NT_STATUS_NO_MEMORY; |
284 | 0 | } |
285 | | |
286 | 0 | ptoken->device_sids[ptoken->num_device_sids] = *device_sid; |
287 | 0 | ptoken->num_device_sids++; |
288 | 0 | } |
289 | 0 | } |
290 | 0 | } |
291 | | |
292 | | /* The caller may have requested simple privileges, for example if there isn't a local DB */ |
293 | 0 | if (session_info_flags & AUTH_SESSION_INFO_SIMPLE_PRIVILEGES) { |
294 | | /* Shortcuts to prevent recursion and avoid lookups */ |
295 | 0 | if (ptoken->sids == NULL) { |
296 | 0 | ptoken->privilege_mask = 0; |
297 | 0 | } else if (security_token_is_system(ptoken)) { |
298 | 0 | ptoken->privilege_mask = ~0; |
299 | 0 | } else if (security_token_is_anonymous(ptoken)) { |
300 | 0 | ptoken->privilege_mask = 0; |
301 | 0 | } else if (security_token_has_builtin_administrators(ptoken)) { |
302 | 0 | ptoken->privilege_mask = ~0; |
303 | 0 | } else { |
304 | | /* All other 'users' get a empty priv set so far */ |
305 | 0 | ptoken->privilege_mask = 0; |
306 | 0 | } |
307 | 0 | } else { |
308 | | /* setup the privilege mask for this token */ |
309 | 0 | status = samdb_privilege_setup(lp_ctx, ptoken); |
310 | 0 | if (!NT_STATUS_IS_OK(status)) { |
311 | 0 | talloc_free(ptoken); |
312 | 0 | DEBUG(1,("Unable to access privileges database\n")); |
313 | 0 | return status; |
314 | 0 | } |
315 | 0 | } |
316 | | |
317 | | /* |
318 | | * TODO: we might want to regard ‘session_info_flags’ for the device |
319 | | * SIDs as well as for the client SIDs. |
320 | | */ |
321 | | |
322 | 0 | if (sids_are_valid) { |
323 | 0 | status = claims_data_security_claims(ptoken, |
324 | 0 | auth_claims.user_claims, |
325 | 0 | &ptoken->user_claims, |
326 | 0 | &ptoken->num_user_claims); |
327 | 0 | if (!NT_STATUS_IS_OK(status)) { |
328 | 0 | talloc_free(ptoken); |
329 | 0 | return status; |
330 | 0 | } |
331 | 0 | } |
332 | | |
333 | 0 | if (device_sids_are_valid && authentication_was_compounded) { |
334 | 0 | status = claims_data_security_claims(ptoken, |
335 | 0 | auth_claims.device_claims, |
336 | 0 | &ptoken->device_claims, |
337 | 0 | &ptoken->num_device_claims); |
338 | 0 | if (!NT_STATUS_IS_OK(status)) { |
339 | 0 | talloc_free(ptoken); |
340 | 0 | return status; |
341 | 0 | } |
342 | 0 | } |
343 | | |
344 | 0 | security_token_debug(0, 10, ptoken); |
345 | |
|
346 | 0 | *token = ptoken; |
347 | |
|
348 | 0 | return NT_STATUS_OK; |
349 | 0 | } |