Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : endpoint server for the samr pipe
5 :
6 : Copyright (C) Andrew Tridgell 2004
7 : Copyright (C) Volker Lendecke 2004
8 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
9 : Copyright (C) Matthias Dieter Wallnöfer 2009
10 :
11 : This program is free software; you can redistribute it and/or modify
12 : it under the terms of the GNU General Public License as published by
13 : the Free Software Foundation; either version 3 of the License, or
14 : (at your option) any later version.
15 :
16 : This program is distributed in the hope that it will be useful,
17 : but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : GNU General Public License for more details.
20 :
21 : You should have received a copy of the GNU General Public License
22 : along with this program. If not, see <http://www.gnu.org/licenses/>.
23 : */
24 :
25 : #include "includes.h"
26 : #include "librpc/gen_ndr/ndr_samr.h"
27 : #include "rpc_server/dcerpc_server.h"
28 : #include "rpc_server/common/common.h"
29 : #include "rpc_server/samr/dcesrv_samr.h"
30 : #include "system/time.h"
31 : #include <ldb.h>
32 : #include <ldb_errors.h>
33 : #include "../libds/common/flags.h"
34 : #include "dsdb/samdb/samdb.h"
35 : #include "dsdb/common/util.h"
36 : #include "libcli/ldap/ldap_ndr.h"
37 : #include "libcli/security/security.h"
38 : #include "rpc_server/samr/proto.h"
39 : #include "../lib/util/util_ldb.h"
40 : #include "param/param.h"
41 : #include "lib/util/tsort.h"
42 : #include "libds/common/flag_mapping.h"
43 :
44 : #undef strcasecmp
45 :
46 : #define DCESRV_INTERFACE_SAMR_BIND(context, iface) \
47 : dcesrv_interface_samr_bind(context, iface)
48 2526 : static NTSTATUS dcesrv_interface_samr_bind(struct dcesrv_connection_context *context,
49 : const struct dcesrv_interface *iface)
50 : {
51 2526 : return dcesrv_interface_bind_reject_connect(context, iface);
52 : }
53 :
54 : /* these query macros make samr_Query[User|Group|Alias]Info a bit easier to read */
55 :
56 : #define QUERY_STRING(msg, field, attr) \
57 : info->field.string = ldb_msg_find_attr_as_string(msg, attr, "");
58 : #define QUERY_UINT(msg, field, attr) \
59 : info->field = ldb_msg_find_attr_as_uint(msg, attr, 0);
60 : #define QUERY_RID(msg, field, attr) \
61 : info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
62 : #define QUERY_UINT64(msg, field, attr) \
63 : info->field = ldb_msg_find_attr_as_uint64(msg, attr, 0);
64 : #define QUERY_APASSC(msg, field, attr) \
65 : info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
66 : a_state->domain_state->domain_dn, msg, attr);
67 : #define QUERY_BPWDCT(msg, field, attr) \
68 : info->field = samdb_result_effective_badPwdCount(sam_ctx, mem_ctx, \
69 : a_state->domain_state->domain_dn, msg);
70 : #define QUERY_LHOURS(msg, field, attr) \
71 : info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
72 : #define QUERY_AFLAGS(msg, field, attr) \
73 : info->field = samdb_result_acct_flags(msg, attr);
74 :
75 :
76 : /* these are used to make the Set[User|Group]Info code easier to follow */
77 :
78 : #define SET_STRING(msg, field, attr) do { \
79 : struct ldb_message_element *set_el; \
80 : if (r->in.info->field.string == NULL) return NT_STATUS_INVALID_PARAMETER; \
81 : if (r->in.info->field.string[0] == '\0') { \
82 : if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, NULL) != LDB_SUCCESS) { \
83 : return NT_STATUS_NO_MEMORY; \
84 : } \
85 : } \
86 : if (ldb_msg_add_string(msg, attr, r->in.info->field.string) != LDB_SUCCESS) { \
87 : return NT_STATUS_NO_MEMORY; \
88 : } \
89 : set_el = ldb_msg_find_element(msg, attr); \
90 : set_el->flags = LDB_FLAG_MOD_REPLACE; \
91 : } while (0)
92 :
93 : #define SET_UINT(msg, field, attr) do { \
94 : struct ldb_message_element *set_el; \
95 : if (samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
96 : return NT_STATUS_NO_MEMORY; \
97 : } \
98 : set_el = ldb_msg_find_element(msg, attr); \
99 : set_el->flags = LDB_FLAG_MOD_REPLACE; \
100 : } while (0)
101 :
102 : #define SET_INT64(msg, field, attr) do { \
103 : struct ldb_message_element *set_el; \
104 : if (samdb_msg_add_int64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
105 : return NT_STATUS_NO_MEMORY; \
106 : } \
107 : set_el = ldb_msg_find_element(msg, attr); \
108 : set_el->flags = LDB_FLAG_MOD_REPLACE; \
109 : } while (0)
110 :
111 : #define SET_UINT64(msg, field, attr) do { \
112 : struct ldb_message_element *set_el; \
113 : if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != LDB_SUCCESS) { \
114 : return NT_STATUS_NO_MEMORY; \
115 : } \
116 : set_el = ldb_msg_find_element(msg, attr); \
117 : set_el->flags = LDB_FLAG_MOD_REPLACE; \
118 : } while (0)
119 :
120 : /* Set account flags, discarding flags that cannot be set with SAMR */
121 : #define SET_AFLAGS(msg, field, attr) do { \
122 : struct ldb_message_element *set_el; \
123 : if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
124 : return NT_STATUS_NO_MEMORY; \
125 : } \
126 : set_el = ldb_msg_find_element(msg, attr); \
127 : set_el->flags = LDB_FLAG_MOD_REPLACE; \
128 : } while (0)
129 :
130 : #define SET_LHOURS(msg, field, attr) do { \
131 : struct ldb_message_element *set_el; \
132 : if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
133 : return NT_STATUS_NO_MEMORY; \
134 : } \
135 : set_el = ldb_msg_find_element(msg, attr); \
136 : set_el->flags = LDB_FLAG_MOD_REPLACE; \
137 : } while (0)
138 :
139 : #define SET_PARAMETERS(msg, field, attr) do { \
140 : struct ldb_message_element *set_el; \
141 : if (r->in.info->field.length != 0) { \
142 : if (samdb_msg_add_parameters(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != LDB_SUCCESS) { \
143 : return NT_STATUS_NO_MEMORY; \
144 : } \
145 : set_el = ldb_msg_find_element(msg, attr); \
146 : set_el->flags = LDB_FLAG_MOD_REPLACE; \
147 : } \
148 : } while (0)
149 :
150 : /*
151 : * Clear a GUID cache
152 : */
153 422 : static void clear_guid_cache(struct samr_guid_cache *cache)
154 : {
155 422 : cache->handle = 0;
156 422 : cache->size = 0;
157 422 : TALLOC_FREE(cache->entries);
158 422 : }
159 :
160 : /*
161 : * initialize a GUID cache
162 : */
163 7161 : static void initialize_guid_cache(struct samr_guid_cache *cache)
164 : {
165 7161 : cache->handle = 0;
166 7161 : cache->size = 0;
167 7161 : cache->entries = NULL;
168 6645 : }
169 :
170 188 : static NTSTATUS load_guid_cache(
171 : struct samr_guid_cache *cache,
172 : struct samr_domain_state *d_state,
173 : unsigned int ldb_cnt,
174 : struct ldb_message **res)
175 : {
176 188 : NTSTATUS status = NT_STATUS_OK;
177 0 : unsigned int i;
178 188 : TALLOC_CTX *frame = talloc_stackframe();
179 :
180 188 : clear_guid_cache(cache);
181 :
182 : /*
183 : * Store the GUID's in the cache.
184 : */
185 188 : cache->handle = 0;
186 188 : cache->size = ldb_cnt;
187 188 : cache->entries = talloc_array(d_state, struct GUID, ldb_cnt);
188 188 : if (cache->entries == NULL) {
189 0 : clear_guid_cache(cache);
190 0 : status = NT_STATUS_NO_MEMORY;
191 0 : goto exit;
192 : }
193 :
194 : /*
195 : * Extract a list of the GUIDs for all the matching objects
196 : * we cache just the GUIDS to reduce the memory overhead of
197 : * the result cache.
198 : */
199 3663 : for (i = 0; i < ldb_cnt; i++) {
200 3475 : cache->entries[i] = samdb_result_guid(res[i], "objectGUID");
201 : }
202 188 : exit:
203 188 : TALLOC_FREE(frame);
204 188 : return status;
205 : }
206 :
207 : /*
208 : samr_Connect
209 :
210 : create a connection to the SAM database
211 : */
212 2692 : static NTSTATUS dcesrv_samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
213 : struct samr_Connect *r)
214 : {
215 178 : struct samr_connect_state *c_state;
216 178 : struct dcesrv_handle *handle;
217 :
218 2692 : ZERO_STRUCTP(r->out.connect_handle);
219 :
220 2692 : c_state = talloc(mem_ctx, struct samr_connect_state);
221 2692 : if (!c_state) {
222 0 : return NT_STATUS_NO_MEMORY;
223 : }
224 :
225 : /* make sure the sam database is accessible */
226 2692 : c_state->sam_ctx = dcesrv_samdb_connect_as_user(c_state, dce_call);
227 2692 : if (c_state->sam_ctx == NULL) {
228 0 : talloc_free(c_state);
229 0 : return NT_STATUS_INVALID_SYSTEM_SERVICE;
230 : }
231 :
232 2692 : handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_CONNECT);
233 2692 : if (!handle) {
234 0 : talloc_free(c_state);
235 0 : return NT_STATUS_NO_MEMORY;
236 : }
237 :
238 2692 : handle->data = talloc_steal(handle, c_state);
239 :
240 2692 : c_state->access_mask = r->in.access_mask;
241 2692 : *r->out.connect_handle = handle->wire_handle;
242 :
243 2692 : return NT_STATUS_OK;
244 : }
245 :
246 :
247 : /*
248 : samr_Close
249 : */
250 2891 : static NTSTATUS dcesrv_samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
251 : struct samr_Close *r)
252 : {
253 12 : struct dcesrv_handle *h;
254 :
255 2891 : *r->out.handle = *r->in.handle;
256 :
257 2891 : DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
258 :
259 2867 : talloc_free(h);
260 :
261 2867 : ZERO_STRUCTP(r->out.handle);
262 :
263 2867 : return NT_STATUS_OK;
264 : }
265 :
266 :
267 : /*
268 : samr_SetSecurity
269 : */
270 0 : static NTSTATUS dcesrv_samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
271 : struct samr_SetSecurity *r)
272 : {
273 0 : DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
274 : }
275 :
276 :
277 : /*
278 : samr_QuerySecurity
279 : */
280 322 : static NTSTATUS dcesrv_samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
281 : struct samr_QuerySecurity *r)
282 : {
283 0 : struct dcesrv_handle *h;
284 0 : struct sec_desc_buf *sd;
285 :
286 322 : *r->out.sdbuf = NULL;
287 :
288 322 : DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
289 :
290 322 : sd = talloc(mem_ctx, struct sec_desc_buf);
291 322 : if (sd == NULL) {
292 0 : return NT_STATUS_NO_MEMORY;
293 : }
294 :
295 322 : sd->sd = samdb_default_security_descriptor(mem_ctx);
296 :
297 322 : *r->out.sdbuf = sd;
298 :
299 322 : return NT_STATUS_OK;
300 : }
301 :
302 :
303 : /*
304 : samr_Shutdown
305 :
306 : we refuse this operation completely. If a admin wants to shutdown samr
307 : in Samba then they should use the samba admin tools to disable the samr pipe
308 : */
309 0 : static NTSTATUS dcesrv_samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
310 : struct samr_Shutdown *r)
311 : {
312 0 : return NT_STATUS_ACCESS_DENIED;
313 : }
314 :
315 :
316 : /*
317 : samr_LookupDomain
318 :
319 : this maps from a domain name to a SID
320 : */
321 564 : static NTSTATUS dcesrv_samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
322 : struct samr_LookupDomain *r)
323 : {
324 0 : struct samr_connect_state *c_state;
325 0 : struct dcesrv_handle *h;
326 0 : struct dom_sid *sid;
327 564 : const char * const dom_attrs[] = { "objectSid", NULL};
328 0 : struct ldb_message **dom_msgs;
329 0 : int ret;
330 :
331 564 : *r->out.sid = NULL;
332 :
333 564 : DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
334 :
335 564 : c_state = h->data;
336 :
337 564 : if (r->in.domain_name->string == NULL) {
338 44 : return NT_STATUS_INVALID_PARAMETER;
339 : }
340 :
341 520 : if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
342 22 : ret = gendb_search(c_state->sam_ctx,
343 : mem_ctx, NULL, &dom_msgs, dom_attrs,
344 : "(objectClass=builtinDomain)");
345 498 : } else if (strcasecmp_m(r->in.domain_name->string, lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx)) == 0) {
346 454 : ret = gendb_search_dn(c_state->sam_ctx,
347 : mem_ctx, ldb_get_default_basedn(c_state->sam_ctx),
348 : &dom_msgs, dom_attrs);
349 : } else {
350 44 : return NT_STATUS_NO_SUCH_DOMAIN;
351 : }
352 476 : if (ret != 1) {
353 0 : return NT_STATUS_NO_SUCH_DOMAIN;
354 : }
355 :
356 476 : sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
357 : "objectSid");
358 :
359 476 : if (sid == NULL) {
360 0 : return NT_STATUS_NO_SUCH_DOMAIN;
361 : }
362 :
363 476 : *r->out.sid = sid;
364 :
365 476 : return NT_STATUS_OK;
366 : }
367 :
368 :
369 : /*
370 : samr_EnumDomains
371 :
372 : list the domains in the SAM
373 : */
374 158 : static NTSTATUS dcesrv_samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
375 : struct samr_EnumDomains *r)
376 : {
377 0 : struct dcesrv_handle *h;
378 0 : struct samr_SamArray *array;
379 0 : uint32_t i, start_i;
380 :
381 158 : *r->out.resume_handle = 0;
382 158 : *r->out.sam = NULL;
383 158 : *r->out.num_entries = 0;
384 :
385 158 : DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
386 :
387 158 : *r->out.resume_handle = 2;
388 :
389 158 : start_i = *r->in.resume_handle;
390 :
391 158 : if (start_i >= 2) {
392 : /* search past end of list is not an error for this call */
393 22 : return NT_STATUS_OK;
394 : }
395 :
396 136 : array = talloc(mem_ctx, struct samr_SamArray);
397 136 : if (array == NULL) {
398 0 : return NT_STATUS_NO_MEMORY;
399 : }
400 :
401 136 : array->count = 0;
402 136 : array->entries = NULL;
403 :
404 136 : array->entries = talloc_array(mem_ctx, struct samr_SamEntry, 2 - start_i);
405 136 : if (array->entries == NULL) {
406 0 : return NT_STATUS_NO_MEMORY;
407 : }
408 :
409 408 : for (i=0;i<2-start_i;i++) {
410 272 : array->entries[i].idx = start_i + i;
411 272 : if (i == 0) {
412 136 : array->entries[i].name.string = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
413 : } else {
414 136 : array->entries[i].name.string = "BUILTIN";
415 : }
416 : }
417 :
418 136 : *r->out.sam = array;
419 136 : *r->out.num_entries = i;
420 136 : array->count = *r->out.num_entries;
421 :
422 136 : return NT_STATUS_OK;
423 : }
424 :
425 :
426 : /*
427 : samr_OpenDomain
428 : */
429 2393 : static NTSTATUS dcesrv_samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
430 : struct samr_OpenDomain *r)
431 : {
432 172 : struct dcesrv_handle *h_conn, *h_domain;
433 172 : struct samr_connect_state *c_state;
434 172 : struct samr_domain_state *d_state;
435 2393 : const char * const dom_attrs[] = { "cn", NULL};
436 172 : struct ldb_message **dom_msgs;
437 172 : int ret;
438 172 : unsigned int i;
439 :
440 2393 : ZERO_STRUCTP(r->out.domain_handle);
441 :
442 2393 : DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
443 :
444 2387 : c_state = h_conn->data;
445 :
446 2387 : if (r->in.sid == NULL) {
447 0 : return NT_STATUS_INVALID_PARAMETER;
448 : }
449 :
450 2387 : d_state = talloc(mem_ctx, struct samr_domain_state);
451 2387 : if (!d_state) {
452 0 : return NT_STATUS_NO_MEMORY;
453 : }
454 :
455 2387 : d_state->domain_sid = talloc_steal(d_state, r->in.sid);
456 :
457 2387 : if (dom_sid_equal(d_state->domain_sid, &global_sid_Builtin)) {
458 560 : d_state->builtin = true;
459 560 : d_state->domain_name = "BUILTIN";
460 : } else {
461 1827 : d_state->builtin = false;
462 1827 : d_state->domain_name = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
463 : }
464 :
465 2387 : ret = gendb_search(c_state->sam_ctx,
466 : mem_ctx, ldb_get_default_basedn(c_state->sam_ctx), &dom_msgs, dom_attrs,
467 : "(objectSid=%s)",
468 2387 : ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
469 :
470 2387 : if (ret == 0) {
471 0 : talloc_free(d_state);
472 0 : return NT_STATUS_NO_SUCH_DOMAIN;
473 2387 : } else if (ret > 1) {
474 0 : talloc_free(d_state);
475 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
476 2387 : } else if (ret == -1) {
477 0 : talloc_free(d_state);
478 0 : DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
479 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
480 : }
481 :
482 2387 : d_state->domain_dn = talloc_steal(d_state, dom_msgs[0]->dn);
483 2387 : d_state->role = lpcfg_server_role(dce_call->conn->dce_ctx->lp_ctx);
484 2387 : d_state->connect_state = talloc_reference(d_state, c_state);
485 2387 : d_state->sam_ctx = c_state->sam_ctx;
486 2387 : d_state->access_mask = r->in.access_mask;
487 2387 : d_state->domain_users_cached = NULL;
488 :
489 2387 : d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
490 :
491 9548 : for (i = 0; i < SAMR_LAST_CACHE; i++) {
492 7161 : initialize_guid_cache(&d_state->guid_caches[i]);
493 : }
494 :
495 2387 : h_domain = dcesrv_handle_create(dce_call, SAMR_HANDLE_DOMAIN);
496 2387 : if (!h_domain) {
497 0 : talloc_free(d_state);
498 0 : return NT_STATUS_NO_MEMORY;
499 : }
500 :
501 2387 : h_domain->data = talloc_steal(h_domain, d_state);
502 :
503 2387 : *r->out.domain_handle = h_domain->wire_handle;
504 :
505 2387 : return NT_STATUS_OK;
506 : }
507 :
508 : /*
509 : return DomInfo1
510 : */
511 59 : static NTSTATUS dcesrv_samr_info_DomInfo1(struct samr_domain_state *state,
512 : TALLOC_CTX *mem_ctx,
513 : struct ldb_message **dom_msgs,
514 : struct samr_DomInfo1 *info)
515 : {
516 59 : info->min_password_length =
517 59 : ldb_msg_find_attr_as_uint(dom_msgs[0], "minPwdLength", 0);
518 59 : info->password_history_length =
519 59 : ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdHistoryLength", 0);
520 59 : info->password_properties =
521 59 : ldb_msg_find_attr_as_uint(dom_msgs[0], "pwdProperties", 0);
522 59 : info->max_password_age =
523 59 : ldb_msg_find_attr_as_int64(dom_msgs[0], "maxPwdAge", 0);
524 59 : info->min_password_age =
525 59 : ldb_msg_find_attr_as_int64(dom_msgs[0], "minPwdAge", 0);
526 :
527 59 : return NT_STATUS_OK;
528 : }
529 :
530 : /*
531 : return DomInfo2
532 : */
533 94 : static NTSTATUS dcesrv_samr_info_DomGeneralInformation(struct samr_domain_state *state,
534 : TALLOC_CTX *mem_ctx,
535 : struct ldb_message **dom_msgs,
536 : struct samr_DomGeneralInformation *info)
537 : {
538 94 : size_t count = 0;
539 94 : const enum ldb_scope scope = LDB_SCOPE_SUBTREE;
540 94 : int ret = 0;
541 :
542 : /* MS-SAMR 2.2.4.1 - ReplicaSourceNodeName: "domainReplica" attribute */
543 94 : info->primary.string = ldb_msg_find_attr_as_string(dom_msgs[0],
544 : "domainReplica",
545 : "");
546 :
547 94 : info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
548 : 0x8000000000000000LL);
549 :
550 94 : info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0],
551 : "oEMInformation",
552 : "");
553 94 : info->domain_name.string = state->domain_name;
554 :
555 94 : info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
556 : 0);
557 94 : switch (state->role) {
558 50 : case ROLE_ACTIVE_DIRECTORY_DC:
559 : /* This pulls the NetBIOS name from the
560 : cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
561 : string */
562 50 : if (samdb_is_pdc(state->sam_ctx)) {
563 38 : info->role = SAMR_ROLE_DOMAIN_PDC;
564 : } else {
565 12 : info->role = SAMR_ROLE_DOMAIN_BDC;
566 : }
567 94 : break;
568 0 : case ROLE_DOMAIN_PDC:
569 : case ROLE_DOMAIN_BDC:
570 : case ROLE_IPA_DC:
571 : case ROLE_AUTO:
572 0 : return NT_STATUS_INTERNAL_ERROR;
573 44 : case ROLE_DOMAIN_MEMBER:
574 44 : info->role = SAMR_ROLE_DOMAIN_MEMBER;
575 44 : break;
576 0 : case ROLE_STANDALONE:
577 0 : info->role = SAMR_ROLE_STANDALONE;
578 0 : break;
579 : }
580 :
581 : /*
582 : * Users are not meant to be in BUILTIN
583 : * so to speed up the query we do not filter on domain_sid
584 : */
585 94 : ret = dsdb_domain_count(
586 94 : state->sam_ctx,
587 : &count,
588 : state->domain_dn,
589 : NULL,
590 : scope,
591 : "(objectClass=user)");
592 94 : if (ret != LDB_SUCCESS || count > UINT32_MAX) {
593 0 : goto error;
594 : }
595 94 : info->num_users = count;
596 :
597 : /*
598 : * Groups are not meant to be in BUILTIN
599 : * so to speed up the query we do not filter on domain_sid
600 : */
601 94 : ret = dsdb_domain_count(
602 94 : state->sam_ctx,
603 : &count,
604 : state->domain_dn,
605 : NULL,
606 : scope,
607 : "(&(objectClass=group)(|(groupType=%d)(groupType=%d)))",
608 : GTYPE_SECURITY_UNIVERSAL_GROUP,
609 : GTYPE_SECURITY_GLOBAL_GROUP);
610 94 : if (ret != LDB_SUCCESS || count > UINT32_MAX) {
611 0 : goto error;
612 : }
613 94 : info->num_groups = count;
614 :
615 94 : ret = dsdb_domain_count(
616 94 : state->sam_ctx,
617 : &count,
618 : state->domain_dn,
619 : state->domain_sid,
620 : scope,
621 : "(&(objectClass=group)(|(groupType=%d)(groupType=%d)))",
622 : GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
623 : GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
624 94 : if (ret != LDB_SUCCESS || count > UINT32_MAX) {
625 0 : goto error;
626 : }
627 94 : info->num_aliases = count;
628 :
629 94 : return NT_STATUS_OK;
630 :
631 0 : error:
632 0 : if (count > UINT32_MAX) {
633 0 : return NT_STATUS_INTEGER_OVERFLOW;
634 : }
635 0 : return dsdb_ldb_err_to_ntstatus(ret);
636 :
637 : }
638 :
639 : /*
640 : return DomInfo3
641 : */
642 22 : static NTSTATUS dcesrv_samr_info_DomInfo3(struct samr_domain_state *state,
643 : TALLOC_CTX *mem_ctx,
644 : struct ldb_message **dom_msgs,
645 : struct samr_DomInfo3 *info)
646 : {
647 22 : info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
648 : 0x8000000000000000LL);
649 :
650 22 : return NT_STATUS_OK;
651 : }
652 :
653 : /*
654 : return DomInfo4
655 : */
656 18 : static NTSTATUS dcesrv_samr_info_DomOEMInformation(struct samr_domain_state *state,
657 : TALLOC_CTX *mem_ctx,
658 : struct ldb_message **dom_msgs,
659 : struct samr_DomOEMInformation *info)
660 : {
661 18 : info->oem_information.string = ldb_msg_find_attr_as_string(dom_msgs[0],
662 : "oEMInformation",
663 : "");
664 :
665 18 : return NT_STATUS_OK;
666 : }
667 :
668 : /*
669 : return DomInfo5
670 : */
671 19 : static NTSTATUS dcesrv_samr_info_DomInfo5(struct samr_domain_state *state,
672 : TALLOC_CTX *mem_ctx,
673 : struct ldb_message **dom_msgs,
674 : struct samr_DomInfo5 *info)
675 : {
676 19 : info->domain_name.string = state->domain_name;
677 :
678 19 : return NT_STATUS_OK;
679 : }
680 :
681 : /*
682 : return DomInfo6
683 : */
684 19 : static NTSTATUS dcesrv_samr_info_DomInfo6(struct samr_domain_state *state,
685 : TALLOC_CTX *mem_ctx,
686 : struct ldb_message **dom_msgs,
687 : struct samr_DomInfo6 *info)
688 : {
689 : /* MS-SAMR 2.2.4.1 - ReplicaSourceNodeName: "domainReplica" attribute */
690 19 : info->primary.string = ldb_msg_find_attr_as_string(dom_msgs[0],
691 : "domainReplica",
692 : "");
693 :
694 19 : return NT_STATUS_OK;
695 : }
696 :
697 : /*
698 : return DomInfo7
699 : */
700 19 : static NTSTATUS dcesrv_samr_info_DomInfo7(struct samr_domain_state *state,
701 : TALLOC_CTX *mem_ctx,
702 : struct ldb_message **dom_msgs,
703 : struct samr_DomInfo7 *info)
704 : {
705 :
706 19 : switch (state->role) {
707 7 : case ROLE_ACTIVE_DIRECTORY_DC:
708 : /* This pulls the NetBIOS name from the
709 : cn=NTDS Settings,cn=<NETBIOS name of PDC>,....
710 : string */
711 7 : if (samdb_is_pdc(state->sam_ctx)) {
712 7 : info->role = SAMR_ROLE_DOMAIN_PDC;
713 : } else {
714 0 : info->role = SAMR_ROLE_DOMAIN_BDC;
715 : }
716 19 : break;
717 0 : case ROLE_DOMAIN_PDC:
718 : case ROLE_DOMAIN_BDC:
719 : case ROLE_IPA_DC:
720 : case ROLE_AUTO:
721 0 : return NT_STATUS_INTERNAL_ERROR;
722 12 : case ROLE_DOMAIN_MEMBER:
723 12 : info->role = SAMR_ROLE_DOMAIN_MEMBER;
724 12 : break;
725 0 : case ROLE_STANDALONE:
726 0 : info->role = SAMR_ROLE_STANDALONE;
727 0 : break;
728 : }
729 :
730 19 : return NT_STATUS_OK;
731 : }
732 :
733 : /*
734 : return DomInfo8
735 : */
736 21 : static NTSTATUS dcesrv_samr_info_DomInfo8(struct samr_domain_state *state,
737 : TALLOC_CTX *mem_ctx,
738 : struct ldb_message **dom_msgs,
739 : struct samr_DomInfo8 *info)
740 : {
741 21 : info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
742 21 : time(NULL));
743 :
744 21 : info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
745 : 0x0LL);
746 :
747 21 : return NT_STATUS_OK;
748 : }
749 :
750 : /*
751 : return DomInfo9
752 : */
753 18 : static NTSTATUS dcesrv_samr_info_DomInfo9(struct samr_domain_state *state,
754 : TALLOC_CTX *mem_ctx,
755 : struct ldb_message **dom_msgs,
756 : struct samr_DomInfo9 *info)
757 : {
758 18 : info->domain_server_state = DOMAIN_SERVER_ENABLED;
759 :
760 18 : return NT_STATUS_OK;
761 : }
762 :
763 : /*
764 : return DomInfo11
765 : */
766 18 : static NTSTATUS dcesrv_samr_info_DomGeneralInformation2(struct samr_domain_state *state,
767 : TALLOC_CTX *mem_ctx,
768 : struct ldb_message **dom_msgs,
769 : struct samr_DomGeneralInformation2 *info)
770 : {
771 0 : NTSTATUS status;
772 18 : status = dcesrv_samr_info_DomGeneralInformation(state, mem_ctx, dom_msgs, &info->general);
773 18 : if (!NT_STATUS_IS_OK(status)) {
774 0 : return status;
775 : }
776 :
777 18 : info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
778 : -18000000000LL);
779 18 : info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
780 : -18000000000LL);
781 18 : info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
782 :
783 18 : return NT_STATUS_OK;
784 : }
785 :
786 : /*
787 : return DomInfo12
788 : */
789 35 : static NTSTATUS dcesrv_samr_info_DomInfo12(struct samr_domain_state *state,
790 : TALLOC_CTX *mem_ctx,
791 : struct ldb_message **dom_msgs,
792 : struct samr_DomInfo12 *info)
793 : {
794 35 : info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
795 : -18000000000LL);
796 35 : info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
797 : -18000000000LL);
798 35 : info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
799 :
800 35 : return NT_STATUS_OK;
801 : }
802 :
803 : /*
804 : return DomInfo13
805 : */
806 18 : static NTSTATUS dcesrv_samr_info_DomInfo13(struct samr_domain_state *state,
807 : TALLOC_CTX *mem_ctx,
808 : struct ldb_message **dom_msgs,
809 : struct samr_DomInfo13 *info)
810 : {
811 18 : info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
812 18 : time(NULL));
813 :
814 18 : info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
815 : 0x0LL);
816 :
817 18 : info->modified_count_at_last_promotion = 0;
818 :
819 18 : return NT_STATUS_OK;
820 : }
821 :
822 : /*
823 : samr_QueryDomainInfo
824 : */
825 342 : static NTSTATUS dcesrv_samr_QueryDomainInfo(struct dcesrv_call_state *dce_call,
826 : TALLOC_CTX *mem_ctx,
827 : struct samr_QueryDomainInfo *r)
828 : {
829 0 : struct dcesrv_handle *h;
830 0 : struct samr_domain_state *d_state;
831 0 : union samr_DomainInfo *info;
832 :
833 0 : struct ldb_message **dom_msgs;
834 342 : const char * const *attrs = NULL;
835 :
836 342 : *r->out.info = NULL;
837 :
838 342 : DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
839 :
840 342 : d_state = h->data;
841 :
842 342 : switch (r->in.level) {
843 59 : case 1:
844 : {
845 : static const char * const attrs2[] = { "minPwdLength",
846 : "pwdHistoryLength",
847 : "pwdProperties",
848 : "maxPwdAge",
849 : "minPwdAge",
850 : NULL };
851 59 : attrs = attrs2;
852 59 : break;
853 : }
854 76 : case 2:
855 : {
856 0 : static const char * const attrs2[] = {"forceLogoff",
857 : "oEMInformation",
858 : "modifiedCount",
859 : "domainReplica",
860 : NULL};
861 76 : attrs = attrs2;
862 76 : break;
863 : }
864 22 : case 3:
865 : {
866 0 : static const char * const attrs2[] = {"forceLogoff",
867 : NULL};
868 22 : attrs = attrs2;
869 22 : break;
870 : }
871 18 : case 4:
872 : {
873 0 : static const char * const attrs2[] = {"oEMInformation",
874 : NULL};
875 18 : attrs = attrs2;
876 18 : break;
877 : }
878 19 : case 5:
879 : {
880 19 : attrs = NULL;
881 19 : break;
882 : }
883 19 : case 6:
884 : {
885 0 : static const char * const attrs2[] = { "domainReplica",
886 : NULL };
887 19 : attrs = attrs2;
888 19 : break;
889 : }
890 19 : case 7:
891 : {
892 19 : attrs = NULL;
893 19 : break;
894 : }
895 21 : case 8:
896 : {
897 0 : static const char * const attrs2[] = { "modifiedCount",
898 : "creationTime",
899 : NULL };
900 21 : attrs = attrs2;
901 21 : break;
902 : }
903 18 : case 9:
904 : {
905 18 : attrs = NULL;
906 18 : break;
907 : }
908 18 : case 11:
909 : {
910 0 : static const char * const attrs2[] = { "oEMInformation",
911 : "forceLogoff",
912 : "modifiedCount",
913 : "lockoutDuration",
914 : "lockOutObservationWindow",
915 : "lockoutThreshold",
916 : NULL};
917 18 : attrs = attrs2;
918 18 : break;
919 : }
920 35 : case 12:
921 : {
922 0 : static const char * const attrs2[] = { "lockoutDuration",
923 : "lockOutObservationWindow",
924 : "lockoutThreshold",
925 : NULL};
926 35 : attrs = attrs2;
927 35 : break;
928 : }
929 18 : case 13:
930 : {
931 0 : static const char * const attrs2[] = { "modifiedCount",
932 : "creationTime",
933 : NULL };
934 18 : attrs = attrs2;
935 18 : break;
936 : }
937 0 : default:
938 : {
939 0 : return NT_STATUS_INVALID_INFO_CLASS;
940 : }
941 : }
942 :
943 : /* some levels don't need a search */
944 342 : if (attrs) {
945 0 : int ret;
946 286 : ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
947 : d_state->domain_dn, &dom_msgs, attrs);
948 286 : if (ret == 0) {
949 0 : return NT_STATUS_NO_SUCH_DOMAIN;
950 : }
951 286 : if (ret != 1) {
952 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
953 : }
954 : }
955 :
956 : /* allocate the info structure */
957 342 : info = talloc_zero(mem_ctx, union samr_DomainInfo);
958 342 : if (info == NULL) {
959 0 : return NT_STATUS_NO_MEMORY;
960 : }
961 :
962 342 : *r->out.info = info;
963 :
964 342 : switch (r->in.level) {
965 59 : case 1:
966 59 : return dcesrv_samr_info_DomInfo1(d_state, mem_ctx, dom_msgs,
967 : &info->info1);
968 76 : case 2:
969 76 : return dcesrv_samr_info_DomGeneralInformation(d_state, mem_ctx, dom_msgs,
970 : &info->general);
971 22 : case 3:
972 22 : return dcesrv_samr_info_DomInfo3(d_state, mem_ctx, dom_msgs,
973 : &info->info3);
974 18 : case 4:
975 18 : return dcesrv_samr_info_DomOEMInformation(d_state, mem_ctx, dom_msgs,
976 : &info->oem);
977 19 : case 5:
978 19 : return dcesrv_samr_info_DomInfo5(d_state, mem_ctx, dom_msgs,
979 : &info->info5);
980 19 : case 6:
981 19 : return dcesrv_samr_info_DomInfo6(d_state, mem_ctx, dom_msgs,
982 : &info->info6);
983 19 : case 7:
984 19 : return dcesrv_samr_info_DomInfo7(d_state, mem_ctx, dom_msgs,
985 : &info->info7);
986 21 : case 8:
987 21 : return dcesrv_samr_info_DomInfo8(d_state, mem_ctx, dom_msgs,
988 : &info->info8);
989 18 : case 9:
990 18 : return dcesrv_samr_info_DomInfo9(d_state, mem_ctx, dom_msgs,
991 : &info->info9);
992 18 : case 11:
993 18 : return dcesrv_samr_info_DomGeneralInformation2(d_state, mem_ctx, dom_msgs,
994 : &info->general2);
995 35 : case 12:
996 35 : return dcesrv_samr_info_DomInfo12(d_state, mem_ctx, dom_msgs,
997 : &info->info12);
998 18 : case 13:
999 18 : return dcesrv_samr_info_DomInfo13(d_state, mem_ctx, dom_msgs,
1000 : &info->info13);
1001 0 : default:
1002 0 : return NT_STATUS_INVALID_INFO_CLASS;
1003 : }
1004 : }
1005 :
1006 :
1007 : /*
1008 : samr_SetDomainInfo
1009 : */
1010 222 : static NTSTATUS dcesrv_samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1011 : struct samr_SetDomainInfo *r)
1012 : {
1013 0 : struct dcesrv_handle *h;
1014 0 : struct samr_domain_state *d_state;
1015 0 : struct ldb_message *msg;
1016 0 : int ret;
1017 0 : struct ldb_context *sam_ctx;
1018 :
1019 222 : DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1020 :
1021 222 : d_state = h->data;
1022 222 : sam_ctx = d_state->sam_ctx;
1023 :
1024 222 : msg = ldb_msg_new(mem_ctx);
1025 222 : if (msg == NULL) {
1026 0 : return NT_STATUS_NO_MEMORY;
1027 : }
1028 :
1029 222 : msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
1030 222 : if (!msg->dn) {
1031 0 : return NT_STATUS_NO_MEMORY;
1032 : }
1033 :
1034 222 : switch (r->in.level) {
1035 85 : case 1:
1036 85 : SET_UINT (msg, info1.min_password_length, "minPwdLength");
1037 85 : SET_UINT (msg, info1.password_history_length, "pwdHistoryLength");
1038 85 : SET_UINT (msg, info1.password_properties, "pwdProperties");
1039 85 : SET_INT64 (msg, info1.max_password_age, "maxPwdAge");
1040 85 : SET_INT64 (msg, info1.min_password_age, "minPwdAge");
1041 85 : break;
1042 7 : case 3:
1043 7 : SET_UINT64 (msg, info3.force_logoff_time, "forceLogoff");
1044 7 : break;
1045 12 : case 4:
1046 12 : SET_STRING(msg, oem.oem_information, "oEMInformation");
1047 12 : break;
1048 :
1049 18 : case 6:
1050 : case 7:
1051 : case 9:
1052 : /* No op, we don't know where to set these */
1053 18 : return NT_STATUS_OK;
1054 :
1055 70 : case 12:
1056 : /*
1057 : * It is not possible to set lockout_duration < lockout_window.
1058 : * (The test is the other way around since the negative numbers
1059 : * are stored...)
1060 : *
1061 : * TODO:
1062 : * This check should be moved to the backend, i.e. to some
1063 : * ldb module under dsdb/samdb/ldb_modules/ .
1064 : *
1065 : * This constraint is documented here for the samr rpc service:
1066 : * MS-SAMR 3.1.1.6 Attribute Constraints for Originating Updates
1067 : * http://msdn.microsoft.com/en-us/library/cc245667%28PROT.10%29.aspx
1068 : *
1069 : * And here for the ldap backend:
1070 : * MS-ADTS 3.1.1.5.3.2 Constraints
1071 : * http://msdn.microsoft.com/en-us/library/cc223462(PROT.10).aspx
1072 : */
1073 70 : if (r->in.info->info12.lockout_duration >
1074 70 : r->in.info->info12.lockout_window)
1075 : {
1076 12 : return NT_STATUS_INVALID_PARAMETER;
1077 : }
1078 58 : SET_INT64 (msg, info12.lockout_duration, "lockoutDuration");
1079 58 : SET_INT64 (msg, info12.lockout_window, "lockOutObservationWindow");
1080 58 : SET_INT64 (msg, info12.lockout_threshold, "lockoutThreshold");
1081 58 : break;
1082 :
1083 30 : default:
1084 : /* many info classes are not valid for SetDomainInfo */
1085 30 : return NT_STATUS_INVALID_INFO_CLASS;
1086 : }
1087 :
1088 : /* modify the samdb record */
1089 162 : ret = ldb_modify(sam_ctx, msg);
1090 162 : if (ret != LDB_SUCCESS) {
1091 0 : DEBUG(1,("Failed to modify record %s: %s\n",
1092 : ldb_dn_get_linearized(d_state->domain_dn),
1093 : ldb_errstring(sam_ctx)));
1094 0 : return dsdb_ldb_err_to_ntstatus(ret);
1095 : }
1096 :
1097 162 : return NT_STATUS_OK;
1098 : }
1099 :
1100 : /*
1101 : samr_CreateDomainGroup
1102 : */
1103 982 : static NTSTATUS dcesrv_samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1104 : struct samr_CreateDomainGroup *r)
1105 : {
1106 0 : NTSTATUS status;
1107 0 : struct samr_domain_state *d_state;
1108 0 : struct samr_account_state *a_state;
1109 0 : struct dcesrv_handle *h;
1110 0 : const char *groupname;
1111 0 : struct dom_sid *group_sid;
1112 0 : struct ldb_dn *group_dn;
1113 0 : struct dcesrv_handle *g_handle;
1114 :
1115 982 : ZERO_STRUCTP(r->out.group_handle);
1116 982 : *r->out.rid = 0;
1117 :
1118 982 : DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1119 :
1120 982 : d_state = h->data;
1121 :
1122 982 : if (d_state->builtin) {
1123 453 : DEBUG(5, ("Cannot create a domain group in the BUILTIN domain\n"));
1124 453 : return NT_STATUS_ACCESS_DENIED;
1125 : }
1126 :
1127 529 : groupname = r->in.name->string;
1128 :
1129 529 : if (groupname == NULL) {
1130 0 : return NT_STATUS_INVALID_PARAMETER;
1131 : }
1132 :
1133 529 : status = dsdb_add_domain_group(d_state->sam_ctx, mem_ctx, groupname, &group_sid, &group_dn);
1134 529 : if (!NT_STATUS_IS_OK(status)) {
1135 1 : return status;
1136 : }
1137 :
1138 528 : a_state = talloc(mem_ctx, struct samr_account_state);
1139 528 : if (!a_state) {
1140 0 : return NT_STATUS_NO_MEMORY;
1141 : }
1142 528 : a_state->sam_ctx = d_state->sam_ctx;
1143 528 : a_state->access_mask = r->in.access_mask;
1144 528 : a_state->domain_state = talloc_reference(a_state, d_state);
1145 528 : a_state->account_dn = talloc_steal(a_state, group_dn);
1146 :
1147 528 : a_state->account_name = talloc_steal(a_state, groupname);
1148 :
1149 : /* create the policy handle */
1150 528 : g_handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_GROUP);
1151 528 : if (!g_handle) {
1152 0 : return NT_STATUS_NO_MEMORY;
1153 : }
1154 :
1155 528 : g_handle->data = talloc_steal(g_handle, a_state);
1156 :
1157 528 : *r->out.group_handle = g_handle->wire_handle;
1158 528 : *r->out.rid = group_sid->sub_auths[group_sid->num_auths-1];
1159 :
1160 528 : return NT_STATUS_OK;
1161 : }
1162 :
1163 :
1164 : /*
1165 : comparison function for sorting SamEntry array
1166 : */
1167 31498 : static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1168 : {
1169 31498 : return e1->idx - e2->idx;
1170 : }
1171 :
1172 4335 : static int compare_msgRid(struct ldb_message **m1, struct ldb_message **m2) {
1173 4335 : struct dom_sid *sid1 = NULL;
1174 4335 : struct dom_sid *sid2 = NULL;
1175 0 : uint32_t rid1;
1176 0 : uint32_t rid2;
1177 4335 : int res = 0;
1178 0 : NTSTATUS status;
1179 4335 : TALLOC_CTX *frame = talloc_stackframe();
1180 :
1181 4335 : sid1 = samdb_result_dom_sid(frame, *m1, "objectSid");
1182 4335 : sid2 = samdb_result_dom_sid(frame, *m2, "objectSid");
1183 :
1184 : /*
1185 : * If entries don't have a SID we want to sort them to the end of
1186 : * the list.
1187 : */
1188 4335 : if (sid1 == NULL && sid2 == NULL) {
1189 0 : res = 0;
1190 0 : goto exit;
1191 4335 : } else if (sid2 == NULL) {
1192 0 : res = 1;
1193 0 : goto exit;
1194 4335 : } else if (sid1 == NULL) {
1195 0 : res = -1;
1196 0 : goto exit;
1197 : }
1198 :
1199 : /*
1200 : * Get and compare the rids, if we fail to extract a rid treat it as a
1201 : * missing SID and sort to the end of the list
1202 : */
1203 4335 : status = dom_sid_split_rid(NULL, sid1, NULL, &rid1);
1204 4335 : if (!NT_STATUS_IS_OK(status)) {
1205 0 : res = 1;
1206 0 : goto exit;
1207 : }
1208 :
1209 4335 : status = dom_sid_split_rid(NULL, sid2, NULL, &rid2);
1210 4335 : if (!NT_STATUS_IS_OK(status)) {
1211 0 : res = -1;
1212 0 : goto exit;
1213 : }
1214 :
1215 4335 : if (rid1 == rid2) {
1216 0 : res = 0;
1217 : }
1218 4335 : else if (rid1 > rid2) {
1219 2301 : res = 1;
1220 : }
1221 : else {
1222 2034 : res = -1;
1223 : }
1224 4335 : exit:
1225 4335 : TALLOC_FREE(frame);
1226 4335 : return res;
1227 : }
1228 :
1229 : /*
1230 : samr_EnumDomainGroups
1231 : */
1232 150 : static NTSTATUS dcesrv_samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1233 : struct samr_EnumDomainGroups *r)
1234 : {
1235 0 : struct dcesrv_handle *h;
1236 0 : struct samr_domain_state *d_state;
1237 0 : struct ldb_message **res;
1238 0 : uint32_t i;
1239 0 : uint32_t count;
1240 0 : uint32_t results;
1241 0 : uint32_t max_entries;
1242 0 : uint32_t remaining_entries;
1243 0 : uint32_t resume_handle;
1244 0 : struct samr_SamEntry *entries;
1245 150 : const char * const attrs[] = { "objectSid", "sAMAccountName", NULL };
1246 150 : const char * const cache_attrs[] = { "objectSid", "objectGUID", NULL };
1247 0 : struct samr_SamArray *sam;
1248 150 : struct samr_guid_cache *cache = NULL;
1249 :
1250 150 : *r->out.resume_handle = 0;
1251 150 : *r->out.sam = NULL;
1252 150 : *r->out.num_entries = 0;
1253 :
1254 150 : DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1255 :
1256 150 : d_state = h->data;
1257 150 : cache = &d_state->guid_caches[SAMR_ENUM_DOMAIN_GROUPS_CACHE];
1258 :
1259 : /*
1260 : * If the resume_handle is zero, query the database and cache the
1261 : * matching GUID's
1262 : */
1263 150 : if (*r->in.resume_handle == 0) {
1264 0 : NTSTATUS status;
1265 0 : int ldb_cnt;
1266 47 : clear_guid_cache(cache);
1267 : /*
1268 : * search for all domain groups in this domain.
1269 : */
1270 47 : ldb_cnt = samdb_search_domain(
1271 47 : d_state->sam_ctx,
1272 : mem_ctx,
1273 : d_state->domain_dn,
1274 : &res,
1275 : cache_attrs,
1276 47 : d_state->domain_sid,
1277 : "(&(|(groupType=%d)(groupType=%d))(objectClass=group))",
1278 : GTYPE_SECURITY_UNIVERSAL_GROUP,
1279 : GTYPE_SECURITY_GLOBAL_GROUP);
1280 47 : if (ldb_cnt < 0) {
1281 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
1282 : }
1283 : /*
1284 : * Sort the results into RID order, while the spec states there
1285 : * is no order, Windows appears to sort the results by RID and
1286 : * so it is possible that there are clients that depend on
1287 : * this ordering
1288 : */
1289 47 : TYPESAFE_QSORT(res, ldb_cnt, compare_msgRid);
1290 :
1291 : /*
1292 : * cache the sorted GUID's
1293 : */
1294 47 : status = load_guid_cache(cache, d_state, ldb_cnt, res);
1295 47 : TALLOC_FREE(res);
1296 47 : if (!NT_STATUS_IS_OK(status)) {
1297 0 : return status;
1298 : }
1299 47 : cache->handle = 0;
1300 : }
1301 :
1302 :
1303 : /*
1304 : * If the resume handle is out of range we return an empty response
1305 : * and invalidate the cache.
1306 : *
1307 : * From the specification:
1308 : * Servers SHOULD validate that EnumerationContext is an expected
1309 : * value for the server's implementation. Windows does NOT validate
1310 : * the input, though the result of malformed information merely results
1311 : * in inconsistent output to the client.
1312 : */
1313 150 : if (*r->in.resume_handle >= cache->size) {
1314 10 : clear_guid_cache(cache);
1315 10 : sam = talloc(mem_ctx, struct samr_SamArray);
1316 10 : if (!sam) {
1317 0 : return NT_STATUS_NO_MEMORY;
1318 : }
1319 10 : sam->entries = NULL;
1320 10 : sam->count = 0;
1321 :
1322 10 : *r->out.sam = sam;
1323 10 : *r->out.resume_handle = 0;
1324 10 : return NT_STATUS_OK;
1325 : }
1326 :
1327 :
1328 : /*
1329 : * Calculate the number of entries to return limit by max_size.
1330 : * Note that we use the w2k3 element size value of 54
1331 : */
1332 140 : max_entries = 1 + (r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER);
1333 140 : remaining_entries = cache->size - *r->in.resume_handle;
1334 140 : results = MIN(remaining_entries, max_entries);
1335 :
1336 : /*
1337 : * Process the list of result GUID's.
1338 : * Read the details of each object and populate the Entries
1339 : * for the current level.
1340 : */
1341 140 : count = 0;
1342 140 : resume_handle = *r->in.resume_handle;
1343 140 : entries = talloc_array(mem_ctx, struct samr_SamEntry, results);
1344 140 : if (entries == NULL) {
1345 0 : clear_guid_cache(cache);
1346 0 : return NT_STATUS_NO_MEMORY;
1347 : }
1348 1102 : for (i = 0; i < results; i++) {
1349 0 : struct dom_sid *objectsid;
1350 0 : uint32_t rid;
1351 0 : struct ldb_result *rec;
1352 962 : const uint32_t idx = *r->in.resume_handle + i;
1353 0 : int ret;
1354 0 : NTSTATUS status;
1355 962 : const char *name = NULL;
1356 962 : resume_handle++;
1357 : /*
1358 : * Read an object from disk using the GUID as the key
1359 : *
1360 : * If the object can not be read, or it does not have a SID
1361 : * it is ignored.
1362 : *
1363 : * As a consequence of this, if all the remaining GUID's
1364 : * have been deleted an empty result will be returned.
1365 : * i.e. even if the previous call returned a non zero
1366 : * resume_handle it is possible for no results to be returned.
1367 : *
1368 : */
1369 962 : ret = dsdb_search_by_dn_guid(d_state->sam_ctx,
1370 : mem_ctx,
1371 : &rec,
1372 962 : &cache->entries[idx],
1373 : attrs,
1374 : 0);
1375 962 : if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1376 0 : struct GUID_txt_buf guid_buf;
1377 1 : DBG_WARNING(
1378 : "GUID [%s] not found\n",
1379 : GUID_buf_string(&cache->entries[idx], &guid_buf));
1380 1 : continue;
1381 961 : } else if (ret != LDB_SUCCESS) {
1382 0 : clear_guid_cache(cache);
1383 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
1384 : }
1385 :
1386 961 : objectsid = samdb_result_dom_sid(mem_ctx,
1387 961 : rec->msgs[0],
1388 : "objectSID");
1389 961 : if (objectsid == NULL) {
1390 0 : struct GUID_txt_buf guid_buf;
1391 0 : DBG_WARNING(
1392 : "objectSID for GUID [%s] not found\n",
1393 : GUID_buf_string(&cache->entries[idx], &guid_buf));
1394 0 : continue;
1395 : }
1396 961 : status = dom_sid_split_rid(NULL,
1397 : objectsid,
1398 : NULL,
1399 : &rid);
1400 961 : if (!NT_STATUS_IS_OK(status)) {
1401 0 : struct dom_sid_buf sid_buf;
1402 0 : struct GUID_txt_buf guid_buf;
1403 0 : DBG_WARNING(
1404 : "objectSID [%s] for GUID [%s] invalid\n",
1405 : dom_sid_str_buf(objectsid, &sid_buf),
1406 : GUID_buf_string(&cache->entries[idx], &guid_buf));
1407 0 : continue;
1408 : }
1409 :
1410 961 : entries[count].idx = rid;
1411 961 : name = ldb_msg_find_attr_as_string(
1412 961 : rec->msgs[0], "sAMAccountName", "");
1413 961 : entries[count].name.string = talloc_strdup(entries, name);
1414 961 : count++;
1415 : }
1416 :
1417 140 : sam = talloc(mem_ctx, struct samr_SamArray);
1418 140 : if (!sam) {
1419 0 : clear_guid_cache(cache);
1420 0 : return NT_STATUS_NO_MEMORY;
1421 : }
1422 :
1423 140 : sam->entries = entries;
1424 140 : sam->count = count;
1425 :
1426 140 : *r->out.sam = sam;
1427 140 : *r->out.resume_handle = resume_handle;
1428 140 : *r->out.num_entries = count;
1429 :
1430 : /*
1431 : * Signal no more results by returning zero resume handle,
1432 : * the cache is also cleared at this point
1433 : */
1434 140 : if (*r->out.resume_handle >= cache->size) {
1435 36 : *r->out.resume_handle = 0;
1436 36 : clear_guid_cache(cache);
1437 36 : return NT_STATUS_OK;
1438 : }
1439 : /*
1440 : * There are more results to be returned.
1441 : */
1442 104 : return STATUS_MORE_ENTRIES;
1443 : }
1444 :
1445 :
1446 : /*
1447 : samr_CreateUser2
1448 :
1449 : This call uses transactions to ensure we don't get a new conflicting
1450 : user while we are processing this, and to ensure the user either
1451 : completely exists, or does not.
1452 : */
1453 1765 : static NTSTATUS dcesrv_samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1454 : struct samr_CreateUser2 *r)
1455 : {
1456 72 : NTSTATUS status;
1457 72 : struct samr_domain_state *d_state;
1458 72 : struct samr_account_state *a_state;
1459 72 : struct dcesrv_handle *h;
1460 72 : struct ldb_dn *dn;
1461 72 : struct dom_sid *sid;
1462 72 : struct dcesrv_handle *u_handle;
1463 72 : const char *account_name;
1464 :
1465 1765 : ZERO_STRUCTP(r->out.user_handle);
1466 1765 : *r->out.access_granted = 0;
1467 1765 : *r->out.rid = 0;
1468 :
1469 1765 : DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1470 :
1471 1765 : d_state = h->data;
1472 :
1473 1765 : if (d_state->builtin) {
1474 603 : DEBUG(5, ("Cannot create a user in the BUILTIN domain\n"));
1475 603 : return NT_STATUS_ACCESS_DENIED;
1476 1162 : } else if (r->in.acct_flags == ACB_DOMTRUST) {
1477 : /* Domain trust accounts must be created by the LSA calls */
1478 10 : return NT_STATUS_ACCESS_DENIED;
1479 : }
1480 1152 : account_name = r->in.account_name->string;
1481 :
1482 1152 : if (account_name == NULL) {
1483 0 : return NT_STATUS_INVALID_PARAMETER;
1484 : }
1485 :
1486 1152 : status = dsdb_add_user(d_state->sam_ctx, mem_ctx, account_name, r->in.acct_flags, NULL,
1487 : &sid, &dn);
1488 1152 : if (!NT_STATUS_IS_OK(status)) {
1489 113 : return status;
1490 : }
1491 1039 : a_state = talloc(mem_ctx, struct samr_account_state);
1492 1039 : if (!a_state) {
1493 0 : return NT_STATUS_NO_MEMORY;
1494 : }
1495 1039 : a_state->sam_ctx = d_state->sam_ctx;
1496 1039 : a_state->access_mask = r->in.access_mask;
1497 1039 : a_state->domain_state = talloc_reference(a_state, d_state);
1498 1039 : a_state->account_dn = talloc_steal(a_state, dn);
1499 :
1500 1039 : a_state->account_name = talloc_steal(a_state, account_name);
1501 1039 : if (!a_state->account_name) {
1502 0 : return NT_STATUS_NO_MEMORY;
1503 : }
1504 :
1505 : /* create the policy handle */
1506 1039 : u_handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_USER);
1507 1039 : if (!u_handle) {
1508 0 : return NT_STATUS_NO_MEMORY;
1509 : }
1510 :
1511 1039 : u_handle->data = talloc_steal(u_handle, a_state);
1512 :
1513 1039 : *r->out.user_handle = u_handle->wire_handle;
1514 1039 : *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1515 :
1516 1039 : *r->out.rid = sid->sub_auths[sid->num_auths-1];
1517 :
1518 1039 : return NT_STATUS_OK;
1519 : }
1520 :
1521 :
1522 : /*
1523 : samr_CreateUser
1524 : */
1525 939 : static NTSTATUS dcesrv_samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1526 : struct samr_CreateUser *r)
1527 : {
1528 0 : struct samr_CreateUser2 r2;
1529 939 : uint32_t access_granted = 0;
1530 :
1531 :
1532 : /* a simple wrapper around samr_CreateUser2 works nicely */
1533 :
1534 939 : r2 = (struct samr_CreateUser2) {
1535 939 : .in.domain_handle = r->in.domain_handle,
1536 939 : .in.account_name = r->in.account_name,
1537 : .in.acct_flags = ACB_NORMAL,
1538 939 : .in.access_mask = r->in.access_mask,
1539 939 : .out.user_handle = r->out.user_handle,
1540 : .out.access_granted = &access_granted,
1541 939 : .out.rid = r->out.rid
1542 : };
1543 :
1544 939 : return dcesrv_samr_CreateUser2(dce_call, mem_ctx, &r2);
1545 : }
1546 :
1547 : struct enum_dom_users_ctx {
1548 : struct samr_SamEntry *entries;
1549 : uint32_t num_entries;
1550 : uint32_t acct_flags;
1551 : struct dom_sid *domain_sid;
1552 : };
1553 :
1554 : static int user_iterate_callback(struct ldb_request *req,
1555 : struct ldb_reply *ares);
1556 :
1557 : /*
1558 : * Iterate users and add all those that match a domain SID and pass an acct
1559 : * flags check to an array of SamEntry objects.
1560 : */
1561 4177 : static int user_iterate_callback(struct ldb_request *req,
1562 : struct ldb_reply *ares)
1563 : {
1564 0 : struct enum_dom_users_ctx *ac =\
1565 4177 : talloc_get_type(req->context, struct enum_dom_users_ctx);
1566 4177 : int ret = LDB_ERR_OPERATIONS_ERROR;
1567 :
1568 4177 : if (!ares) {
1569 0 : return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
1570 : }
1571 4177 : if (ares->error != LDB_SUCCESS) {
1572 0 : return ldb_request_done(req, ares->error);
1573 : }
1574 :
1575 4177 : switch (ares->type) {
1576 3898 : case LDB_REPLY_ENTRY:
1577 : {
1578 3898 : struct ldb_message *msg = ares->message;
1579 0 : const struct ldb_val *val;
1580 0 : struct samr_SamEntry *ent;
1581 0 : struct dom_sid objectsid;
1582 0 : uint32_t rid;
1583 3898 : size_t entries_array_len = 0;
1584 0 : NTSTATUS status;
1585 0 : ssize_t sid_size;
1586 :
1587 3898 : if (ac->acct_flags && ((samdb_result_acct_flags(msg, NULL) &
1588 3255 : ac->acct_flags) == 0)) {
1589 233 : ret = LDB_SUCCESS;
1590 233 : break;
1591 : }
1592 :
1593 3665 : val = ldb_msg_find_ldb_val(msg, "objectSID");
1594 3665 : if (val == NULL) {
1595 0 : DBG_WARNING("objectSID for DN %s not found\n",
1596 : ldb_dn_get_linearized(msg->dn));
1597 0 : ret = ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
1598 0 : break;
1599 : }
1600 :
1601 3665 : sid_size = sid_parse(val->data, val->length, &objectsid);
1602 3665 : if (sid_size == -1) {
1603 0 : struct dom_sid_buf sid_buf;
1604 0 : DBG_WARNING("objectsid [%s] for DN [%s] invalid\n",
1605 : dom_sid_str_buf(&objectsid, &sid_buf),
1606 : ldb_dn_get_linearized(msg->dn));
1607 0 : ret = ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
1608 0 : break;
1609 : }
1610 :
1611 3665 : if (!dom_sid_in_domain(ac->domain_sid, &objectsid)) {
1612 : /* Ignore if user isn't in the domain */
1613 0 : ret = LDB_SUCCESS;
1614 0 : break;
1615 : }
1616 :
1617 3665 : status = dom_sid_split_rid(ares, &objectsid, NULL, &rid);
1618 3665 : if (!NT_STATUS_IS_OK(status)) {
1619 0 : struct dom_sid_buf sid_buf;
1620 0 : DBG_WARNING("Couldn't split RID from "
1621 : "SID [%s] of DN [%s]\n",
1622 : dom_sid_str_buf(&objectsid, &sid_buf),
1623 : ldb_dn_get_linearized(msg->dn));
1624 0 : ret = ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
1625 0 : break;
1626 : }
1627 :
1628 3665 : entries_array_len = talloc_array_length(ac->entries);
1629 3665 : if (ac->num_entries >= entries_array_len) {
1630 11 : if (entries_array_len * 2 < entries_array_len) {
1631 0 : ret = ldb_request_done(req,
1632 : LDB_ERR_OPERATIONS_ERROR);
1633 0 : break;
1634 : }
1635 11 : ac->entries = talloc_realloc(ac,
1636 : ac->entries,
1637 : struct samr_SamEntry,
1638 : entries_array_len * 2);
1639 11 : if (ac->entries == NULL) {
1640 0 : ret = ldb_request_done(req,
1641 : LDB_ERR_OPERATIONS_ERROR);
1642 0 : break;
1643 : }
1644 : }
1645 :
1646 3665 : ent = &(ac->entries[ac->num_entries++]);
1647 3665 : val = ldb_msg_find_ldb_val(msg, "samaccountname");
1648 3665 : if (val == NULL) {
1649 0 : DBG_WARNING("samaccountname attribute not found\n");
1650 0 : ret = ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
1651 0 : break;
1652 : }
1653 3665 : ent->name.string = talloc_steal(ac->entries,
1654 : (char *)val->data);
1655 3665 : ent->idx = rid;
1656 3665 : ret = LDB_SUCCESS;
1657 3665 : break;
1658 : }
1659 98 : case LDB_REPLY_DONE:
1660 : {
1661 98 : if (ac->num_entries != 0 &&
1662 65 : ac->num_entries != talloc_array_length(ac->entries)) {
1663 65 : ac->entries = talloc_realloc(ac,
1664 : ac->entries,
1665 : struct samr_SamEntry,
1666 : ac->num_entries);
1667 65 : if (ac->entries == NULL) {
1668 0 : ret = ldb_request_done(req,
1669 : LDB_ERR_OPERATIONS_ERROR);
1670 0 : break;
1671 : }
1672 : }
1673 98 : ret = ldb_request_done(req, LDB_SUCCESS);
1674 98 : break;
1675 : }
1676 181 : case LDB_REPLY_REFERRAL:
1677 : {
1678 181 : ret = LDB_SUCCESS;
1679 181 : break;
1680 : }
1681 0 : default:
1682 : /* Doesn't happen */
1683 0 : ret = LDB_ERR_OPERATIONS_ERROR;
1684 : }
1685 4177 : TALLOC_FREE(ares);
1686 :
1687 4177 : return ret;
1688 : }
1689 :
1690 : /*
1691 : * samr_EnumDomainUsers
1692 : * The previous implementation did an initial search and stored a list of
1693 : * matching GUIDs on the connection handle's domain state, then did direct
1694 : * GUID lookups for each record in a page indexed by resume_handle. That
1695 : * approach was memory efficient, requiring only 16 bytes per record, but
1696 : * was too slow for winbind which needs this RPC call for getpwent.
1697 : *
1698 : * Now we use an iterate pattern to populate a cached list of the rids and
1699 : * names for each record. This improves runtime performance but requires
1700 : * about 200 bytes per record which will mean for a 100k database we use
1701 : * about 2MB, which is fine. The speedup achieved by this new approach is
1702 : * around 50%.
1703 : */
1704 148 : static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call,
1705 : TALLOC_CTX *mem_ctx,
1706 : struct samr_EnumDomainUsers *r)
1707 : {
1708 0 : struct dcesrv_handle *h;
1709 0 : struct samr_domain_state *d_state;
1710 0 : uint32_t results;
1711 0 : uint32_t max_entries;
1712 0 : uint32_t num_entries;
1713 0 : uint32_t remaining_entries;
1714 0 : struct samr_SamEntry *entries;
1715 148 : const char * const attrs[] = { "objectSid", "sAMAccountName",
1716 : "userAccountControl", NULL };
1717 0 : struct samr_SamArray *sam;
1718 0 : struct ldb_request *req;
1719 :
1720 148 : *r->out.resume_handle = 0;
1721 148 : *r->out.sam = NULL;
1722 148 : *r->out.num_entries = 0;
1723 :
1724 148 : DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1725 :
1726 148 : d_state = h->data;
1727 148 : entries = d_state->domain_users_cached;
1728 :
1729 : /*
1730 : * If the resume_handle is zero, query the database and cache the
1731 : * matching entries.
1732 : */
1733 148 : if (*r->in.resume_handle == 0) {
1734 0 : int ret;
1735 0 : struct enum_dom_users_ctx *ac;
1736 98 : if (entries != NULL) {
1737 38 : talloc_free(entries);
1738 38 : d_state->domain_users_cached = NULL;
1739 : }
1740 :
1741 98 : ac = talloc(mem_ctx, struct enum_dom_users_ctx);
1742 98 : ac->num_entries = 0;
1743 98 : ac->domain_sid = d_state->domain_sid;
1744 98 : ac->entries = talloc_array(ac,
1745 : struct samr_SamEntry,
1746 : 100);
1747 98 : if (ac->entries == NULL) {
1748 0 : talloc_free(ac);
1749 0 : return NT_STATUS_NO_MEMORY;
1750 : }
1751 98 : ac->acct_flags = r->in.acct_flags;
1752 :
1753 98 : ret = ldb_build_search_req(&req,
1754 98 : d_state->sam_ctx,
1755 : mem_ctx,
1756 : d_state->domain_dn,
1757 : LDB_SCOPE_SUBTREE,
1758 : "(objectClass=user)",
1759 : attrs,
1760 : NULL,
1761 : ac,
1762 : user_iterate_callback,
1763 : NULL);
1764 98 : if (ret != LDB_SUCCESS) {
1765 0 : talloc_free(ac);
1766 0 : return dsdb_ldb_err_to_ntstatus(ret);
1767 : }
1768 :
1769 98 : ret = ldb_request(d_state->sam_ctx, req);
1770 98 : if (ret != LDB_SUCCESS) {
1771 0 : talloc_free(ac);
1772 0 : return dsdb_ldb_err_to_ntstatus(ret);
1773 : }
1774 :
1775 98 : ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1776 98 : if (ret != LDB_SUCCESS) {
1777 0 : return dsdb_ldb_err_to_ntstatus(ret);
1778 : }
1779 :
1780 98 : if (ac->num_entries == 0) {
1781 33 : DBG_WARNING("No users in domain %s\n",
1782 : ldb_dn_get_linearized(d_state->domain_dn));
1783 33 : talloc_free(ac);
1784 :
1785 : /*
1786 : * test_EnumDomainUsers_all() expects that r.out.sam
1787 : * should be non-NULL, even if we have no entries.
1788 : */
1789 33 : sam = talloc_zero(mem_ctx, struct samr_SamArray);
1790 33 : if (sam == NULL) {
1791 0 : return NT_STATUS_NO_MEMORY;
1792 : }
1793 33 : *r->out.sam = sam;
1794 :
1795 33 : return NT_STATUS_OK;
1796 : }
1797 :
1798 65 : entries = talloc_steal(d_state, ac->entries);
1799 65 : d_state->domain_users_cached = entries;
1800 65 : num_entries = ac->num_entries;
1801 65 : talloc_free(ac);
1802 :
1803 : /*
1804 : * Sort the entries into RID order, while the spec states there
1805 : * is no order, Windows appears to sort the results by RID and
1806 : * so it is possible that there are clients that depend on
1807 : * this ordering
1808 : */
1809 65 : TYPESAFE_QSORT(entries, num_entries, compare_SamEntry);
1810 : } else {
1811 50 : num_entries = talloc_array_length(entries);
1812 : }
1813 :
1814 : /*
1815 : * If the resume handle is out of range we return an empty response
1816 : * and invalidate the cache.
1817 : *
1818 : * From the specification:
1819 : * Servers SHOULD validate that EnumerationContext is an expected
1820 : * value for the server's implementation. Windows does NOT validate
1821 : * the input, though the result of malformed information merely results
1822 : * in inconsistent output to the client.
1823 : */
1824 115 : if (*r->in.resume_handle >= num_entries) {
1825 1 : talloc_free(entries);
1826 1 : d_state->domain_users_cached = NULL;
1827 1 : sam = talloc(mem_ctx, struct samr_SamArray);
1828 1 : if (!sam) {
1829 0 : return NT_STATUS_NO_MEMORY;
1830 : }
1831 1 : sam->entries = NULL;
1832 1 : sam->count = 0;
1833 :
1834 1 : *r->out.sam = sam;
1835 1 : *r->out.resume_handle = 0;
1836 1 : return NT_STATUS_OK;
1837 : }
1838 :
1839 : /*
1840 : * Calculate the number of entries to return limit by max_size.
1841 : * Note that we use the w2k3 element size value of 54
1842 : */
1843 114 : max_entries = 1 + (r->in.max_size / SAMR_ENUM_USERS_MULTIPLIER);
1844 114 : remaining_entries = num_entries - *r->in.resume_handle;
1845 114 : results = MIN(remaining_entries, max_entries);
1846 :
1847 114 : sam = talloc(mem_ctx, struct samr_SamArray);
1848 114 : if (!sam) {
1849 0 : d_state->domain_users_cached = NULL;
1850 0 : return NT_STATUS_NO_MEMORY;
1851 : }
1852 :
1853 114 : sam->entries = entries + *r->in.resume_handle;
1854 114 : sam->count = results;
1855 :
1856 114 : *r->out.sam = sam;
1857 114 : *r->out.resume_handle = *r->in.resume_handle + results;
1858 114 : *r->out.num_entries = results;
1859 :
1860 : /*
1861 : * Signal no more results by returning zero resume handle,
1862 : * the cache is also cleared at this point
1863 : */
1864 114 : if (*r->out.resume_handle >= num_entries) {
1865 64 : *r->out.resume_handle = 0;
1866 64 : return NT_STATUS_OK;
1867 : }
1868 : /*
1869 : * There are more results to be returned.
1870 : */
1871 50 : return STATUS_MORE_ENTRIES;
1872 : }
1873 :
1874 :
1875 : /*
1876 : samr_CreateDomAlias
1877 : */
1878 906 : static NTSTATUS dcesrv_samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1879 : struct samr_CreateDomAlias *r)
1880 : {
1881 0 : struct samr_domain_state *d_state;
1882 0 : struct samr_account_state *a_state;
1883 0 : struct dcesrv_handle *h;
1884 0 : const char *alias_name;
1885 0 : struct dom_sid *sid;
1886 0 : struct dcesrv_handle *a_handle;
1887 0 : struct ldb_dn *dn;
1888 0 : NTSTATUS status;
1889 :
1890 906 : ZERO_STRUCTP(r->out.alias_handle);
1891 906 : *r->out.rid = 0;
1892 :
1893 906 : DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1894 :
1895 906 : d_state = h->data;
1896 :
1897 906 : if (d_state->builtin) {
1898 453 : DEBUG(5, ("Cannot create a domain alias in the BUILTIN domain\n"));
1899 453 : return NT_STATUS_ACCESS_DENIED;
1900 : }
1901 :
1902 453 : alias_name = r->in.alias_name->string;
1903 :
1904 453 : if (alias_name == NULL) {
1905 0 : return NT_STATUS_INVALID_PARAMETER;
1906 : }
1907 :
1908 453 : status = dsdb_add_domain_alias(d_state->sam_ctx, mem_ctx, alias_name, &sid, &dn);
1909 453 : if (!NT_STATUS_IS_OK(status)) {
1910 0 : return status;
1911 : }
1912 :
1913 453 : a_state = talloc(mem_ctx, struct samr_account_state);
1914 453 : if (!a_state) {
1915 0 : return NT_STATUS_NO_MEMORY;
1916 : }
1917 :
1918 453 : a_state->sam_ctx = d_state->sam_ctx;
1919 453 : a_state->access_mask = r->in.access_mask;
1920 453 : a_state->domain_state = talloc_reference(a_state, d_state);
1921 453 : a_state->account_dn = talloc_steal(a_state, dn);
1922 :
1923 453 : a_state->account_name = talloc_steal(a_state, alias_name);
1924 :
1925 : /* create the policy handle */
1926 453 : a_handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_ALIAS);
1927 453 : if (a_handle == NULL)
1928 0 : return NT_STATUS_NO_MEMORY;
1929 :
1930 453 : a_handle->data = talloc_steal(a_handle, a_state);
1931 :
1932 453 : *r->out.alias_handle = a_handle->wire_handle;
1933 :
1934 453 : *r->out.rid = sid->sub_auths[sid->num_auths-1];
1935 :
1936 453 : return NT_STATUS_OK;
1937 : }
1938 :
1939 :
1940 : /*
1941 : samr_EnumDomainAliases
1942 : */
1943 49 : static NTSTATUS dcesrv_samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1944 : struct samr_EnumDomainAliases *r)
1945 : {
1946 0 : struct dcesrv_handle *h;
1947 0 : struct samr_domain_state *d_state;
1948 0 : struct ldb_message **res;
1949 0 : int i, ldb_cnt;
1950 0 : uint32_t first, count;
1951 0 : struct samr_SamEntry *entries;
1952 49 : const char * const attrs[] = { "objectSid", "sAMAccountName", NULL };
1953 0 : struct samr_SamArray *sam;
1954 :
1955 49 : *r->out.resume_handle = 0;
1956 49 : *r->out.sam = NULL;
1957 49 : *r->out.num_entries = 0;
1958 :
1959 49 : DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1960 :
1961 49 : d_state = h->data;
1962 :
1963 : /* search for all domain aliases in this domain. This could possibly be
1964 : cached and resumed based on resume_key */
1965 49 : ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
1966 : &res, attrs,
1967 49 : d_state->domain_sid,
1968 : "(&(|(grouptype=%d)(grouptype=%d)))"
1969 : "(objectclass=group))",
1970 : GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1971 : GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1972 49 : if (ldb_cnt < 0) {
1973 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
1974 : }
1975 :
1976 : /* convert to SamEntry format */
1977 49 : entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1978 49 : if (!entries) {
1979 0 : return NT_STATUS_NO_MEMORY;
1980 : }
1981 :
1982 49 : count = 0;
1983 :
1984 1003 : for (i=0;i<ldb_cnt;i++) {
1985 0 : struct dom_sid *alias_sid;
1986 :
1987 954 : alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1988 : "objectSid");
1989 :
1990 954 : if (alias_sid == NULL) {
1991 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
1992 : }
1993 :
1994 954 : entries[count].idx =
1995 954 : alias_sid->sub_auths[alias_sid->num_auths-1];
1996 1908 : entries[count].name.string =
1997 954 : ldb_msg_find_attr_as_string(res[i], "sAMAccountName", "");
1998 954 : count += 1;
1999 : }
2000 :
2001 : /* sort the results by rid */
2002 49 : TYPESAFE_QSORT(entries, count, compare_SamEntry);
2003 :
2004 : /* find the first entry to return */
2005 49 : for (first=0;
2006 59 : first<count && entries[first].idx <= *r->in.resume_handle;
2007 10 : first++) ;
2008 :
2009 : /* return the rest, limit by max_size. Note that we
2010 : use the w2k3 element size value of 54 */
2011 49 : *r->out.num_entries = count - first;
2012 49 : *r->out.num_entries = MIN(*r->out.num_entries,
2013 : 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
2014 :
2015 49 : sam = talloc(mem_ctx, struct samr_SamArray);
2016 49 : if (!sam) {
2017 0 : return NT_STATUS_NO_MEMORY;
2018 : }
2019 :
2020 49 : sam->entries = entries+first;
2021 49 : sam->count = *r->out.num_entries;
2022 :
2023 49 : *r->out.sam = sam;
2024 :
2025 49 : if (first == count) {
2026 0 : return NT_STATUS_OK;
2027 : }
2028 :
2029 49 : if (*r->out.num_entries < count - first) {
2030 5 : *r->out.resume_handle =
2031 5 : entries[first+*r->out.num_entries-1].idx;
2032 5 : return STATUS_MORE_ENTRIES;
2033 : }
2034 :
2035 44 : return NT_STATUS_OK;
2036 : }
2037 :
2038 :
2039 : /*
2040 : samr_GetAliasMembership
2041 : */
2042 257 : static NTSTATUS dcesrv_samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2043 : struct samr_GetAliasMembership *r)
2044 : {
2045 0 : struct dcesrv_handle *h;
2046 0 : struct samr_domain_state *d_state;
2047 0 : char *filter;
2048 257 : const char * const attrs[] = { "objectSid", NULL };
2049 0 : struct ldb_message **res;
2050 0 : uint32_t i;
2051 257 : int count = 0;
2052 :
2053 257 : DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2054 :
2055 257 : d_state = h->data;
2056 :
2057 257 : filter = talloc_asprintf(mem_ctx,
2058 : "(&(|(grouptype=%d)(grouptype=%d))"
2059 : "(objectclass=group)(|",
2060 : GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2061 : GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2062 257 : if (filter == NULL) {
2063 0 : return NT_STATUS_NO_MEMORY;
2064 : }
2065 :
2066 1057 : for (i=0; i<r->in.sids->num_sids; i++) {
2067 0 : struct dom_sid_buf buf;
2068 :
2069 800 : filter = talloc_asprintf_append(
2070 : filter,
2071 : "(member=<SID=%s>)",
2072 800 : dom_sid_str_buf(r->in.sids->sids[i].sid, &buf));
2073 :
2074 800 : if (filter == NULL) {
2075 0 : return NT_STATUS_NO_MEMORY;
2076 : }
2077 : }
2078 :
2079 : /* Find out if we had at least one valid member SID passed - otherwise
2080 : * just skip the search. */
2081 257 : if (strstr(filter, "member") != NULL) {
2082 235 : count = samdb_search_domain(d_state->sam_ctx, mem_ctx, NULL,
2083 235 : &res, attrs, d_state->domain_sid,
2084 : "%s))", filter);
2085 235 : if (count < 0) {
2086 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
2087 : }
2088 : }
2089 :
2090 257 : r->out.rids->count = 0;
2091 257 : r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
2092 257 : if (r->out.rids->ids == NULL)
2093 0 : return NT_STATUS_NO_MEMORY;
2094 :
2095 421 : for (i=0; i<count; i++) {
2096 0 : struct dom_sid *alias_sid;
2097 :
2098 164 : alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
2099 164 : if (alias_sid == NULL) {
2100 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
2101 : }
2102 :
2103 164 : r->out.rids->ids[r->out.rids->count] =
2104 164 : alias_sid->sub_auths[alias_sid->num_auths-1];
2105 164 : r->out.rids->count += 1;
2106 : }
2107 :
2108 257 : return NT_STATUS_OK;
2109 : }
2110 :
2111 :
2112 : /*
2113 : samr_LookupNames
2114 : */
2115 5095 : static NTSTATUS dcesrv_samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2116 : struct samr_LookupNames *r)
2117 : {
2118 17 : struct dcesrv_handle *h;
2119 17 : struct samr_domain_state *d_state;
2120 17 : uint32_t i, num_mapped;
2121 5095 : NTSTATUS status = NT_STATUS_OK;
2122 5095 : const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
2123 17 : int count;
2124 :
2125 5095 : ZERO_STRUCTP(r->out.rids);
2126 5095 : ZERO_STRUCTP(r->out.types);
2127 :
2128 5095 : DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2129 :
2130 5095 : d_state = h->data;
2131 :
2132 5095 : if (r->in.num_names == 0) {
2133 325 : return NT_STATUS_OK;
2134 : }
2135 :
2136 4770 : r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
2137 4770 : r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
2138 4770 : if (!r->out.rids->ids || !r->out.types->ids) {
2139 0 : return NT_STATUS_NO_MEMORY;
2140 : }
2141 4770 : r->out.rids->count = r->in.num_names;
2142 4770 : r->out.types->count = r->in.num_names;
2143 :
2144 4770 : num_mapped = 0;
2145 :
2146 10220 : for (i=0;i<r->in.num_names;i++) {
2147 17 : struct ldb_message **res;
2148 17 : struct dom_sid *sid;
2149 17 : uint32_t atype, rtype;
2150 :
2151 5450 : r->out.rids->ids[i] = 0;
2152 5450 : r->out.types->ids[i] = SID_NAME_UNKNOWN;
2153 :
2154 5450 : count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
2155 : "sAMAccountName=%s",
2156 5450 : ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
2157 5450 : if (count != 1) {
2158 3967 : status = STATUS_SOME_UNMAPPED;
2159 3967 : continue;
2160 : }
2161 :
2162 1483 : sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
2163 1483 : if (sid == NULL) {
2164 0 : status = STATUS_SOME_UNMAPPED;
2165 0 : continue;
2166 : }
2167 :
2168 1483 : atype = ldb_msg_find_attr_as_uint(res[0], "sAMAccountType", 0);
2169 1483 : if (atype == 0) {
2170 0 : status = STATUS_SOME_UNMAPPED;
2171 0 : continue;
2172 : }
2173 :
2174 1483 : rtype = ds_atype_map(atype);
2175 :
2176 1483 : if (rtype == SID_NAME_UNKNOWN) {
2177 0 : status = STATUS_SOME_UNMAPPED;
2178 0 : continue;
2179 : }
2180 :
2181 1483 : r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
2182 1483 : r->out.types->ids[i] = rtype;
2183 1483 : num_mapped++;
2184 : }
2185 :
2186 4770 : if (num_mapped == 0) {
2187 3323 : return NT_STATUS_NONE_MAPPED;
2188 : }
2189 1447 : return status;
2190 : }
2191 :
2192 :
2193 : /*
2194 : samr_LookupRids
2195 : */
2196 259 : static NTSTATUS dcesrv_samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2197 : struct samr_LookupRids *r)
2198 : {
2199 0 : NTSTATUS status;
2200 0 : struct dcesrv_handle *h;
2201 0 : struct samr_domain_state *d_state;
2202 0 : const char **names;
2203 0 : struct lsa_String *lsa_names;
2204 0 : enum lsa_SidType *ids;
2205 :
2206 259 : ZERO_STRUCTP(r->out.names);
2207 259 : ZERO_STRUCTP(r->out.types);
2208 :
2209 259 : DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2210 :
2211 259 : d_state = h->data;
2212 :
2213 259 : if (r->in.num_rids == 0)
2214 7 : return NT_STATUS_OK;
2215 :
2216 252 : lsa_names = talloc_zero_array(mem_ctx, struct lsa_String, r->in.num_rids);
2217 252 : names = talloc_zero_array(mem_ctx, const char *, r->in.num_rids);
2218 252 : ids = talloc_zero_array(mem_ctx, enum lsa_SidType, r->in.num_rids);
2219 :
2220 252 : if ((lsa_names == NULL) || (names == NULL) || (ids == NULL))
2221 0 : return NT_STATUS_NO_MEMORY;
2222 :
2223 252 : r->out.names->names = lsa_names;
2224 252 : r->out.names->count = r->in.num_rids;
2225 :
2226 252 : r->out.types->ids = (uint32_t *) ids;
2227 252 : r->out.types->count = r->in.num_rids;
2228 :
2229 252 : status = dsdb_lookup_rids(d_state->sam_ctx, mem_ctx, d_state->domain_sid,
2230 : r->in.num_rids, r->in.rids, names, ids);
2231 252 : if (NT_STATUS_IS_OK(status) || NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED) || NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
2232 : uint32_t i;
2233 3121 : for (i = 0; i < r->in.num_rids; i++) {
2234 2869 : lsa_names[i].string = names[i];
2235 : }
2236 : }
2237 252 : return status;
2238 : }
2239 :
2240 :
2241 : /*
2242 : samr_OpenGroup
2243 : */
2244 253 : static NTSTATUS dcesrv_samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2245 : struct samr_OpenGroup *r)
2246 : {
2247 0 : struct samr_domain_state *d_state;
2248 0 : struct samr_account_state *a_state;
2249 0 : struct dcesrv_handle *h;
2250 0 : const char *groupname;
2251 0 : struct dom_sid *sid;
2252 0 : struct ldb_message **msgs;
2253 0 : struct dcesrv_handle *g_handle;
2254 253 : const char * const attrs[2] = { "sAMAccountName", NULL };
2255 0 : int ret;
2256 :
2257 253 : ZERO_STRUCTP(r->out.group_handle);
2258 :
2259 253 : DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2260 :
2261 250 : d_state = h->data;
2262 :
2263 : /* form the group SID */
2264 250 : sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2265 250 : if (!sid) {
2266 0 : return NT_STATUS_NO_MEMORY;
2267 : }
2268 :
2269 : /* search for the group record */
2270 250 : if (d_state->builtin) {
2271 0 : ret = gendb_search(d_state->sam_ctx,
2272 : mem_ctx, d_state->domain_dn, &msgs, attrs,
2273 : "(&(objectSid=%s)(objectClass=group)"
2274 : "(groupType=%d))",
2275 : ldap_encode_ndr_dom_sid(mem_ctx, sid),
2276 : GTYPE_SECURITY_BUILTIN_LOCAL_GROUP);
2277 : } else {
2278 250 : ret = gendb_search(d_state->sam_ctx,
2279 : mem_ctx, d_state->domain_dn, &msgs, attrs,
2280 : "(&(objectSid=%s)(objectClass=group)"
2281 : "(|(groupType=%d)(groupType=%d)))",
2282 : ldap_encode_ndr_dom_sid(mem_ctx, sid),
2283 : GTYPE_SECURITY_UNIVERSAL_GROUP,
2284 : GTYPE_SECURITY_GLOBAL_GROUP);
2285 : }
2286 250 : if (ret == 0) {
2287 0 : return NT_STATUS_NO_SUCH_GROUP;
2288 : }
2289 250 : if (ret != 1) {
2290 0 : DEBUG(0,("Found %d records matching sid %s\n",
2291 : ret, dom_sid_string(mem_ctx, sid)));
2292 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
2293 : }
2294 :
2295 250 : groupname = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2296 250 : if (groupname == NULL) {
2297 0 : DEBUG(0,("sAMAccountName field missing for sid %s\n",
2298 : dom_sid_string(mem_ctx, sid)));
2299 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
2300 : }
2301 :
2302 250 : a_state = talloc(mem_ctx, struct samr_account_state);
2303 250 : if (!a_state) {
2304 0 : return NT_STATUS_NO_MEMORY;
2305 : }
2306 250 : a_state->sam_ctx = d_state->sam_ctx;
2307 250 : a_state->access_mask = r->in.access_mask;
2308 250 : a_state->domain_state = talloc_reference(a_state, d_state);
2309 250 : a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2310 250 : a_state->account_sid = talloc_steal(a_state, sid);
2311 250 : a_state->account_name = talloc_strdup(a_state, groupname);
2312 250 : if (!a_state->account_name) {
2313 0 : return NT_STATUS_NO_MEMORY;
2314 : }
2315 :
2316 : /* create the policy handle */
2317 250 : g_handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_GROUP);
2318 250 : if (!g_handle) {
2319 0 : return NT_STATUS_NO_MEMORY;
2320 : }
2321 :
2322 250 : g_handle->data = talloc_steal(g_handle, a_state);
2323 :
2324 250 : *r->out.group_handle = g_handle->wire_handle;
2325 :
2326 250 : return NT_STATUS_OK;
2327 : }
2328 :
2329 : /*
2330 : samr_QueryGroupInfo
2331 : */
2332 225 : static NTSTATUS dcesrv_samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2333 : struct samr_QueryGroupInfo *r)
2334 : {
2335 0 : struct dcesrv_handle *h;
2336 0 : struct samr_account_state *a_state;
2337 0 : struct ldb_message *msg, **res;
2338 225 : const char * const attrs[4] = { "sAMAccountName", "description",
2339 : "numMembers", NULL };
2340 0 : int ret;
2341 0 : union samr_GroupInfo *info;
2342 :
2343 225 : *r->out.info = NULL;
2344 :
2345 225 : DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2346 :
2347 225 : a_state = h->data;
2348 :
2349 : /* pull all the group attributes */
2350 225 : ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2351 : a_state->account_dn, &res, attrs);
2352 225 : if (ret == 0) {
2353 0 : return NT_STATUS_NO_SUCH_GROUP;
2354 : }
2355 225 : if (ret != 1) {
2356 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
2357 : }
2358 225 : msg = res[0];
2359 :
2360 : /* allocate the info structure */
2361 225 : info = talloc_zero(mem_ctx, union samr_GroupInfo);
2362 225 : if (info == NULL) {
2363 0 : return NT_STATUS_NO_MEMORY;
2364 : }
2365 :
2366 : /* Fill in the level */
2367 225 : switch (r->in.level) {
2368 44 : case GROUPINFOALL:
2369 44 : QUERY_STRING(msg, all.name, "sAMAccountName");
2370 44 : info->all.attributes = SE_GROUP_DEFAULT_FLAGS; /* Do like w2k3 */
2371 44 : QUERY_UINT (msg, all.num_members, "numMembers")
2372 44 : QUERY_STRING(msg, all.description, "description");
2373 44 : break;
2374 43 : case GROUPINFONAME:
2375 43 : QUERY_STRING(msg, name, "sAMAccountName");
2376 43 : break;
2377 45 : case GROUPINFOATTRIBUTES:
2378 45 : info->attributes.attributes = SE_GROUP_DEFAULT_FLAGS; /* Do like w2k3 */
2379 45 : break;
2380 43 : case GROUPINFODESCRIPTION:
2381 43 : QUERY_STRING(msg, description, "description");
2382 43 : break;
2383 50 : case GROUPINFOALL2:
2384 50 : QUERY_STRING(msg, all2.name, "sAMAccountName");
2385 50 : info->all.attributes = SE_GROUP_DEFAULT_FLAGS; /* Do like w2k3 */
2386 50 : QUERY_UINT (msg, all2.num_members, "numMembers")
2387 50 : QUERY_STRING(msg, all2.description, "description");
2388 50 : break;
2389 0 : default:
2390 0 : talloc_free(info);
2391 0 : return NT_STATUS_INVALID_INFO_CLASS;
2392 : }
2393 :
2394 225 : *r->out.info = info;
2395 :
2396 225 : return NT_STATUS_OK;
2397 : }
2398 :
2399 :
2400 : /*
2401 : samr_SetGroupInfo
2402 : */
2403 13 : static NTSTATUS dcesrv_samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2404 : struct samr_SetGroupInfo *r)
2405 : {
2406 0 : struct dcesrv_handle *h;
2407 0 : struct samr_account_state *g_state;
2408 0 : struct ldb_message *msg;
2409 0 : int ret;
2410 :
2411 13 : DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2412 :
2413 13 : g_state = h->data;
2414 :
2415 13 : msg = ldb_msg_new(mem_ctx);
2416 13 : if (msg == NULL) {
2417 0 : return NT_STATUS_NO_MEMORY;
2418 : }
2419 :
2420 13 : msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
2421 13 : if (!msg->dn) {
2422 0 : return NT_STATUS_NO_MEMORY;
2423 : }
2424 :
2425 13 : switch (r->in.level) {
2426 3 : case GROUPINFODESCRIPTION:
2427 3 : SET_STRING(msg, description, "description");
2428 3 : break;
2429 4 : case GROUPINFONAME:
2430 : /* On W2k3 this does not change the name, it changes the
2431 : * sAMAccountName attribute */
2432 4 : SET_STRING(msg, name, "sAMAccountName");
2433 4 : break;
2434 3 : case GROUPINFOATTRIBUTES:
2435 : /* This does not do anything obviously visible in W2k3 LDAP */
2436 3 : return NT_STATUS_OK;
2437 3 : default:
2438 3 : return NT_STATUS_INVALID_INFO_CLASS;
2439 : }
2440 :
2441 : /* modify the samdb record */
2442 7 : ret = ldb_modify(g_state->sam_ctx, msg);
2443 7 : if (ret != LDB_SUCCESS) {
2444 0 : return dsdb_ldb_err_to_ntstatus(ret);
2445 : }
2446 :
2447 7 : return NT_STATUS_OK;
2448 : }
2449 :
2450 :
2451 : /*
2452 : samr_AddGroupMember
2453 : */
2454 81 : static NTSTATUS dcesrv_samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2455 : struct samr_AddGroupMember *r)
2456 : {
2457 0 : struct dcesrv_handle *h;
2458 0 : struct samr_account_state *a_state;
2459 0 : struct samr_domain_state *d_state;
2460 0 : struct ldb_message *mod;
2461 0 : struct dom_sid *membersid;
2462 0 : const char *memberdn;
2463 0 : struct ldb_result *res;
2464 81 : const char * const attrs[] = { NULL };
2465 0 : int ret;
2466 :
2467 81 : DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2468 :
2469 81 : a_state = h->data;
2470 81 : d_state = a_state->domain_state;
2471 :
2472 81 : membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2473 81 : if (membersid == NULL) {
2474 0 : return NT_STATUS_NO_MEMORY;
2475 : }
2476 :
2477 : /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
2478 81 : ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2479 : d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2480 : "(objectSid=%s)",
2481 : ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2482 :
2483 81 : if (ret != LDB_SUCCESS) {
2484 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
2485 : }
2486 :
2487 81 : if (res->count == 0) {
2488 0 : return NT_STATUS_NO_SUCH_USER;
2489 : }
2490 :
2491 81 : if (res->count > 1) {
2492 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
2493 : }
2494 :
2495 81 : memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2496 :
2497 81 : if (memberdn == NULL)
2498 0 : return NT_STATUS_NO_MEMORY;
2499 :
2500 81 : mod = ldb_msg_new(mem_ctx);
2501 81 : if (mod == NULL) {
2502 0 : return NT_STATUS_NO_MEMORY;
2503 : }
2504 :
2505 81 : mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2506 :
2507 81 : ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2508 : memberdn);
2509 81 : if (ret != LDB_SUCCESS) {
2510 0 : return dsdb_ldb_err_to_ntstatus(ret);
2511 : }
2512 :
2513 81 : ret = ldb_modify(a_state->sam_ctx, mod);
2514 81 : switch (ret) {
2515 78 : case LDB_SUCCESS:
2516 78 : return NT_STATUS_OK;
2517 3 : case LDB_ERR_ENTRY_ALREADY_EXISTS:
2518 3 : return NT_STATUS_MEMBER_IN_GROUP;
2519 0 : case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2520 0 : return NT_STATUS_ACCESS_DENIED;
2521 0 : default:
2522 0 : return dsdb_ldb_err_to_ntstatus(ret);
2523 : }
2524 : }
2525 :
2526 :
2527 : /*
2528 : samr_DeleteDomainGroup
2529 : */
2530 528 : static NTSTATUS dcesrv_samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2531 : struct samr_DeleteDomainGroup *r)
2532 : {
2533 0 : struct dcesrv_handle *h;
2534 0 : struct samr_account_state *a_state;
2535 0 : int ret;
2536 :
2537 528 : *r->out.group_handle = *r->in.group_handle;
2538 :
2539 528 : DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2540 :
2541 528 : a_state = h->data;
2542 :
2543 528 : ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2544 528 : if (ret != LDB_SUCCESS) {
2545 0 : return dsdb_ldb_err_to_ntstatus(ret);
2546 : }
2547 :
2548 528 : talloc_free(h);
2549 528 : ZERO_STRUCTP(r->out.group_handle);
2550 :
2551 528 : return NT_STATUS_OK;
2552 : }
2553 :
2554 :
2555 : /*
2556 : samr_DeleteGroupMember
2557 : */
2558 77 : static NTSTATUS dcesrv_samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2559 : struct samr_DeleteGroupMember *r)
2560 : {
2561 0 : struct dcesrv_handle *h;
2562 0 : struct samr_account_state *a_state;
2563 0 : struct samr_domain_state *d_state;
2564 0 : struct ldb_message *mod;
2565 0 : struct dom_sid *membersid;
2566 0 : const char *memberdn;
2567 0 : struct ldb_result *res;
2568 77 : const char * const attrs[] = { NULL };
2569 0 : int ret;
2570 :
2571 77 : DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2572 :
2573 77 : a_state = h->data;
2574 77 : d_state = a_state->domain_state;
2575 :
2576 77 : membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2577 77 : if (membersid == NULL) {
2578 0 : return NT_STATUS_NO_MEMORY;
2579 : }
2580 :
2581 : /* according to MS-SAMR 3.1.5.8.2 all type of accounts are accepted */
2582 77 : ret = ldb_search(d_state->sam_ctx, mem_ctx, &res,
2583 : d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2584 : "(objectSid=%s)",
2585 : ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2586 :
2587 77 : if (ret != LDB_SUCCESS) {
2588 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
2589 : }
2590 :
2591 77 : if (res->count == 0) {
2592 0 : return NT_STATUS_NO_SUCH_USER;
2593 : }
2594 :
2595 77 : if (res->count > 1) {
2596 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
2597 : }
2598 :
2599 77 : memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2600 :
2601 77 : if (memberdn == NULL)
2602 0 : return NT_STATUS_NO_MEMORY;
2603 :
2604 77 : mod = ldb_msg_new(mem_ctx);
2605 77 : if (mod == NULL) {
2606 0 : return NT_STATUS_NO_MEMORY;
2607 : }
2608 :
2609 77 : mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2610 :
2611 77 : ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2612 : memberdn);
2613 77 : if (ret != LDB_SUCCESS) {
2614 0 : return NT_STATUS_NO_MEMORY;
2615 : }
2616 :
2617 77 : ret = ldb_modify(a_state->sam_ctx, mod);
2618 77 : switch (ret) {
2619 74 : case LDB_SUCCESS:
2620 74 : return NT_STATUS_OK;
2621 3 : case LDB_ERR_UNWILLING_TO_PERFORM:
2622 : case LDB_ERR_NO_SUCH_ATTRIBUTE:
2623 3 : return NT_STATUS_MEMBER_NOT_IN_GROUP;
2624 0 : case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2625 0 : return NT_STATUS_ACCESS_DENIED;
2626 0 : default:
2627 0 : return dsdb_ldb_err_to_ntstatus(ret);
2628 : }
2629 : }
2630 :
2631 :
2632 : /*
2633 : samr_QueryGroupMember
2634 : */
2635 164 : static NTSTATUS dcesrv_samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2636 : struct samr_QueryGroupMember *r)
2637 : {
2638 0 : struct dcesrv_handle *h;
2639 0 : struct samr_account_state *a_state;
2640 0 : struct samr_domain_state *d_state;
2641 0 : struct samr_RidAttrArray *array;
2642 0 : unsigned int i, num_members;
2643 0 : struct dom_sid *members;
2644 0 : NTSTATUS status;
2645 :
2646 164 : DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2647 :
2648 164 : a_state = h->data;
2649 164 : d_state = a_state->domain_state;
2650 :
2651 164 : status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
2652 : a_state->account_dn, &members,
2653 : &num_members);
2654 164 : if (!NT_STATUS_IS_OK(status)) {
2655 0 : return status;
2656 : }
2657 :
2658 164 : array = talloc_zero(mem_ctx, struct samr_RidAttrArray);
2659 164 : if (array == NULL) {
2660 0 : return NT_STATUS_NO_MEMORY;
2661 : }
2662 :
2663 164 : if (num_members == 0) {
2664 55 : *r->out.rids = array;
2665 :
2666 55 : return NT_STATUS_OK;
2667 : }
2668 :
2669 109 : array->rids = talloc_array(array, uint32_t, num_members);
2670 109 : if (array->rids == NULL) {
2671 0 : return NT_STATUS_NO_MEMORY;
2672 : }
2673 :
2674 109 : array->attributes = talloc_array(array, uint32_t, num_members);
2675 109 : if (array->attributes == NULL) {
2676 0 : return NT_STATUS_NO_MEMORY;
2677 : }
2678 :
2679 109 : array->count = 0;
2680 218 : for (i=0; i<num_members; i++) {
2681 109 : if (!dom_sid_in_domain(d_state->domain_sid, &members[i])) {
2682 0 : continue;
2683 : }
2684 :
2685 109 : status = dom_sid_split_rid(NULL, &members[i], NULL,
2686 109 : &array->rids[array->count]);
2687 109 : if (!NT_STATUS_IS_OK(status)) {
2688 0 : return status;
2689 : }
2690 :
2691 109 : array->attributes[array->count] = SE_GROUP_DEFAULT_FLAGS;
2692 109 : array->count++;
2693 : }
2694 :
2695 109 : *r->out.rids = array;
2696 :
2697 109 : return NT_STATUS_OK;
2698 : }
2699 :
2700 :
2701 : /*
2702 : samr_SetMemberAttributesOfGroup
2703 : */
2704 0 : static NTSTATUS dcesrv_samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2705 : struct samr_SetMemberAttributesOfGroup *r)
2706 : {
2707 0 : DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2708 : }
2709 :
2710 :
2711 : /*
2712 : samr_OpenAlias
2713 : */
2714 79 : static NTSTATUS dcesrv_samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2715 : struct samr_OpenAlias *r)
2716 : {
2717 0 : struct samr_domain_state *d_state;
2718 0 : struct samr_account_state *a_state;
2719 0 : struct dcesrv_handle *h;
2720 0 : const char *alias_name;
2721 0 : struct dom_sid *sid;
2722 0 : struct ldb_message **msgs;
2723 0 : struct dcesrv_handle *g_handle;
2724 79 : const char * const attrs[2] = { "sAMAccountName", NULL };
2725 0 : int ret;
2726 :
2727 79 : ZERO_STRUCTP(r->out.alias_handle);
2728 :
2729 79 : DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2730 :
2731 79 : d_state = h->data;
2732 :
2733 : /* form the alias SID */
2734 79 : sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2735 79 : if (sid == NULL)
2736 0 : return NT_STATUS_NO_MEMORY;
2737 :
2738 : /* search for the group record */
2739 79 : ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL, &msgs, attrs,
2740 : "(&(objectSid=%s)(objectclass=group)"
2741 : "(|(grouptype=%d)(grouptype=%d)))",
2742 : ldap_encode_ndr_dom_sid(mem_ctx, sid),
2743 : GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2744 : GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2745 79 : if (ret == 0) {
2746 0 : return NT_STATUS_NO_SUCH_ALIAS;
2747 : }
2748 79 : if (ret != 1) {
2749 0 : DEBUG(0,("Found %d records matching sid %s\n",
2750 : ret, dom_sid_string(mem_ctx, sid)));
2751 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
2752 : }
2753 :
2754 79 : alias_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
2755 79 : if (alias_name == NULL) {
2756 0 : DEBUG(0,("sAMAccountName field missing for sid %s\n",
2757 : dom_sid_string(mem_ctx, sid)));
2758 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
2759 : }
2760 :
2761 79 : a_state = talloc(mem_ctx, struct samr_account_state);
2762 79 : if (!a_state) {
2763 0 : return NT_STATUS_NO_MEMORY;
2764 : }
2765 79 : a_state->sam_ctx = d_state->sam_ctx;
2766 79 : a_state->access_mask = r->in.access_mask;
2767 79 : a_state->domain_state = talloc_reference(a_state, d_state);
2768 79 : a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2769 79 : a_state->account_sid = talloc_steal(a_state, sid);
2770 79 : a_state->account_name = talloc_strdup(a_state, alias_name);
2771 79 : if (!a_state->account_name) {
2772 0 : return NT_STATUS_NO_MEMORY;
2773 : }
2774 :
2775 : /* create the policy handle */
2776 79 : g_handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_ALIAS);
2777 79 : if (!g_handle) {
2778 0 : return NT_STATUS_NO_MEMORY;
2779 : }
2780 :
2781 79 : g_handle->data = talloc_steal(g_handle, a_state);
2782 :
2783 79 : *r->out.alias_handle = g_handle->wire_handle;
2784 :
2785 79 : return NT_STATUS_OK;
2786 : }
2787 :
2788 :
2789 : /*
2790 : samr_QueryAliasInfo
2791 : */
2792 252 : static NTSTATUS dcesrv_samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2793 : struct samr_QueryAliasInfo *r)
2794 : {
2795 0 : struct dcesrv_handle *h;
2796 0 : struct samr_account_state *a_state;
2797 0 : struct ldb_message *msg, **res;
2798 252 : const char * const attrs[4] = { "sAMAccountName", "description",
2799 : "numMembers", NULL };
2800 0 : int ret;
2801 0 : union samr_AliasInfo *info;
2802 :
2803 252 : *r->out.info = NULL;
2804 :
2805 252 : DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2806 :
2807 252 : a_state = h->data;
2808 :
2809 : /* pull all the alias attributes */
2810 252 : ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2811 : a_state->account_dn, &res, attrs);
2812 252 : if (ret == 0) {
2813 0 : return NT_STATUS_NO_SUCH_ALIAS;
2814 : }
2815 252 : if (ret != 1) {
2816 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
2817 : }
2818 252 : msg = res[0];
2819 :
2820 : /* allocate the info structure */
2821 252 : info = talloc_zero(mem_ctx, union samr_AliasInfo);
2822 252 : if (info == NULL) {
2823 0 : return NT_STATUS_NO_MEMORY;
2824 : }
2825 :
2826 252 : switch(r->in.level) {
2827 82 : case ALIASINFOALL:
2828 82 : QUERY_STRING(msg, all.name, "sAMAccountName");
2829 82 : QUERY_UINT (msg, all.num_members, "numMembers");
2830 82 : QUERY_STRING(msg, all.description, "description");
2831 82 : break;
2832 85 : case ALIASINFONAME:
2833 85 : QUERY_STRING(msg, name, "sAMAccountName");
2834 85 : break;
2835 85 : case ALIASINFODESCRIPTION:
2836 85 : QUERY_STRING(msg, description, "description");
2837 85 : break;
2838 0 : default:
2839 0 : talloc_free(info);
2840 0 : return NT_STATUS_INVALID_INFO_CLASS;
2841 : }
2842 :
2843 252 : *r->out.info = info;
2844 :
2845 252 : return NT_STATUS_OK;
2846 : }
2847 :
2848 :
2849 : /*
2850 : samr_SetAliasInfo
2851 : */
2852 6 : static NTSTATUS dcesrv_samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2853 : struct samr_SetAliasInfo *r)
2854 : {
2855 0 : struct dcesrv_handle *h;
2856 0 : struct samr_account_state *a_state;
2857 0 : struct ldb_message *msg;
2858 0 : int ret;
2859 :
2860 6 : DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2861 :
2862 6 : a_state = h->data;
2863 :
2864 6 : msg = ldb_msg_new(mem_ctx);
2865 6 : if (msg == NULL) {
2866 0 : return NT_STATUS_NO_MEMORY;
2867 : }
2868 :
2869 6 : msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2870 6 : if (!msg->dn) {
2871 0 : return NT_STATUS_NO_MEMORY;
2872 : }
2873 :
2874 6 : switch (r->in.level) {
2875 3 : case ALIASINFODESCRIPTION:
2876 3 : SET_STRING(msg, description, "description");
2877 3 : break;
2878 3 : case ALIASINFONAME:
2879 : /* On W2k3 this does not change the name, it changes the
2880 : * sAMAccountName attribute */
2881 3 : SET_STRING(msg, name, "sAMAccountName");
2882 3 : break;
2883 0 : default:
2884 0 : return NT_STATUS_INVALID_INFO_CLASS;
2885 : }
2886 :
2887 : /* modify the samdb record */
2888 6 : ret = ldb_modify(a_state->sam_ctx, msg);
2889 6 : if (ret != LDB_SUCCESS) {
2890 0 : return dsdb_ldb_err_to_ntstatus(ret);
2891 : }
2892 :
2893 6 : return NT_STATUS_OK;
2894 : }
2895 :
2896 :
2897 : /*
2898 : samr_DeleteDomAlias
2899 : */
2900 453 : static NTSTATUS dcesrv_samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2901 : struct samr_DeleteDomAlias *r)
2902 : {
2903 0 : struct dcesrv_handle *h;
2904 0 : struct samr_account_state *a_state;
2905 0 : int ret;
2906 :
2907 453 : *r->out.alias_handle = *r->in.alias_handle;
2908 :
2909 453 : DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2910 :
2911 453 : a_state = h->data;
2912 :
2913 453 : ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
2914 453 : if (ret != LDB_SUCCESS) {
2915 0 : return dsdb_ldb_err_to_ntstatus(ret);
2916 : }
2917 :
2918 453 : talloc_free(h);
2919 453 : ZERO_STRUCTP(r->out.alias_handle);
2920 :
2921 453 : return NT_STATUS_OK;
2922 : }
2923 :
2924 :
2925 : /*
2926 : samr_AddAliasMember
2927 : */
2928 3 : static NTSTATUS dcesrv_samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2929 : struct samr_AddAliasMember *r)
2930 : {
2931 0 : struct dcesrv_handle *h;
2932 0 : struct samr_account_state *a_state;
2933 0 : struct samr_domain_state *d_state;
2934 0 : struct ldb_message *mod;
2935 0 : struct ldb_message **msgs;
2936 3 : const char * const attrs[] = { NULL };
2937 3 : struct ldb_dn *memberdn = NULL;
2938 0 : int ret;
2939 0 : NTSTATUS status;
2940 :
2941 3 : DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2942 :
2943 3 : a_state = h->data;
2944 3 : d_state = a_state->domain_state;
2945 :
2946 3 : ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2947 : &msgs, attrs, "(objectsid=%s)",
2948 3 : ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2949 :
2950 3 : if (ret == 1) {
2951 3 : memberdn = msgs[0]->dn;
2952 0 : } else if (ret == 0) {
2953 0 : status = samdb_create_foreign_security_principal(
2954 0 : d_state->sam_ctx, mem_ctx, r->in.sid, &memberdn);
2955 0 : if (!NT_STATUS_IS_OK(status)) {
2956 0 : return status;
2957 : }
2958 : } else {
2959 0 : DEBUG(0,("Found %d records matching sid %s\n",
2960 : ret, dom_sid_string(mem_ctx, r->in.sid)));
2961 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
2962 : }
2963 :
2964 3 : if (memberdn == NULL) {
2965 0 : DEBUG(0, ("Could not find memberdn\n"));
2966 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
2967 : }
2968 :
2969 3 : mod = ldb_msg_new(mem_ctx);
2970 3 : if (mod == NULL) {
2971 0 : return NT_STATUS_NO_MEMORY;
2972 : }
2973 :
2974 3 : mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2975 :
2976 3 : ret = samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2977 3 : ldb_dn_alloc_linearized(mem_ctx, memberdn));
2978 3 : if (ret != LDB_SUCCESS) {
2979 0 : return dsdb_ldb_err_to_ntstatus(ret);
2980 : }
2981 :
2982 3 : ret = ldb_modify(a_state->sam_ctx, mod);
2983 3 : switch (ret) {
2984 3 : case LDB_SUCCESS:
2985 3 : return NT_STATUS_OK;
2986 0 : case LDB_ERR_ENTRY_ALREADY_EXISTS:
2987 0 : return NT_STATUS_MEMBER_IN_GROUP;
2988 0 : case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2989 0 : return NT_STATUS_ACCESS_DENIED;
2990 0 : default:
2991 0 : return dsdb_ldb_err_to_ntstatus(ret);
2992 : }
2993 : }
2994 :
2995 :
2996 : /*
2997 : samr_DeleteAliasMember
2998 : */
2999 3 : static NTSTATUS dcesrv_samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3000 : struct samr_DeleteAliasMember *r)
3001 : {
3002 0 : struct dcesrv_handle *h;
3003 0 : struct samr_account_state *a_state;
3004 0 : struct samr_domain_state *d_state;
3005 0 : struct ldb_message *mod;
3006 0 : const char *memberdn;
3007 0 : int ret;
3008 :
3009 3 : DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
3010 :
3011 3 : a_state = h->data;
3012 3 : d_state = a_state->domain_state;
3013 :
3014 3 : memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3015 : "distinguishedName", "(objectSid=%s)",
3016 3 : ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3017 3 : if (memberdn == NULL) {
3018 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3019 : }
3020 :
3021 3 : mod = ldb_msg_new(mem_ctx);
3022 3 : if (mod == NULL) {
3023 0 : return NT_STATUS_NO_MEMORY;
3024 : }
3025 :
3026 3 : mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
3027 :
3028 3 : ret = samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
3029 : memberdn);
3030 3 : if (ret != LDB_SUCCESS) {
3031 0 : return dsdb_ldb_err_to_ntstatus(ret);
3032 : }
3033 :
3034 3 : ret = ldb_modify(a_state->sam_ctx, mod);
3035 3 : switch (ret) {
3036 3 : case LDB_SUCCESS:
3037 3 : return NT_STATUS_OK;
3038 0 : case LDB_ERR_UNWILLING_TO_PERFORM:
3039 0 : return NT_STATUS_MEMBER_NOT_IN_GROUP;
3040 0 : case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
3041 0 : return NT_STATUS_ACCESS_DENIED;
3042 0 : default:
3043 0 : return dsdb_ldb_err_to_ntstatus(ret);
3044 : }
3045 : }
3046 :
3047 :
3048 : /*
3049 : samr_GetMembersInAlias
3050 : */
3051 79 : static NTSTATUS dcesrv_samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3052 : struct samr_GetMembersInAlias *r)
3053 : {
3054 0 : struct dcesrv_handle *h;
3055 0 : struct samr_account_state *a_state;
3056 0 : struct samr_domain_state *d_state;
3057 0 : struct lsa_SidPtr *array;
3058 0 : unsigned int i, num_members;
3059 0 : struct dom_sid *members;
3060 0 : NTSTATUS status;
3061 :
3062 79 : DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
3063 :
3064 79 : a_state = h->data;
3065 79 : d_state = a_state->domain_state;
3066 :
3067 79 : status = dsdb_enum_group_mem(d_state->sam_ctx, mem_ctx,
3068 : a_state->account_dn, &members,
3069 : &num_members);
3070 79 : if (!NT_STATUS_IS_OK(status)) {
3071 0 : return status;
3072 : }
3073 :
3074 79 : if (num_members == 0) {
3075 55 : r->out.sids->sids = NULL;
3076 :
3077 55 : return NT_STATUS_OK;
3078 : }
3079 :
3080 24 : array = talloc_array(mem_ctx, struct lsa_SidPtr, num_members);
3081 24 : if (array == NULL) {
3082 0 : return NT_STATUS_NO_MEMORY;
3083 : }
3084 :
3085 84 : for (i=0; i<num_members; i++) {
3086 60 : array[i].sid = &members[i];
3087 : }
3088 :
3089 24 : r->out.sids->num_sids = num_members;
3090 24 : r->out.sids->sids = array;
3091 :
3092 24 : return NT_STATUS_OK;
3093 : }
3094 :
3095 : /*
3096 : samr_OpenUser
3097 : */
3098 1901 : static NTSTATUS dcesrv_samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3099 : struct samr_OpenUser *r)
3100 : {
3101 0 : struct samr_domain_state *d_state;
3102 0 : struct samr_account_state *a_state;
3103 0 : struct dcesrv_handle *h;
3104 0 : const char *account_name;
3105 0 : struct dom_sid *sid;
3106 0 : struct ldb_message **msgs;
3107 0 : struct dcesrv_handle *u_handle;
3108 1901 : const char * const attrs[2] = { "sAMAccountName", NULL };
3109 0 : int ret;
3110 :
3111 1901 : ZERO_STRUCTP(r->out.user_handle);
3112 :
3113 1901 : DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3114 :
3115 1898 : d_state = h->data;
3116 :
3117 : /* form the users SID */
3118 1898 : sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
3119 1898 : if (!sid) {
3120 0 : return NT_STATUS_NO_MEMORY;
3121 : }
3122 :
3123 : /* search for the user record */
3124 1898 : ret = gendb_search(d_state->sam_ctx,
3125 : mem_ctx, d_state->domain_dn, &msgs, attrs,
3126 : "(&(objectSid=%s)(objectclass=user))",
3127 : ldap_encode_ndr_dom_sid(mem_ctx, sid));
3128 1898 : if (ret == 0) {
3129 21 : return NT_STATUS_NO_SUCH_USER;
3130 : }
3131 1877 : if (ret != 1) {
3132 0 : DEBUG(0,("Found %d records matching sid %s\n", ret,
3133 : dom_sid_string(mem_ctx, sid)));
3134 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
3135 : }
3136 :
3137 1877 : account_name = ldb_msg_find_attr_as_string(msgs[0], "sAMAccountName", NULL);
3138 1877 : if (account_name == NULL) {
3139 0 : DEBUG(0,("sAMAccountName field missing for sid %s\n",
3140 : dom_sid_string(mem_ctx, sid)));
3141 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
3142 : }
3143 :
3144 1877 : a_state = talloc(mem_ctx, struct samr_account_state);
3145 1877 : if (!a_state) {
3146 0 : return NT_STATUS_NO_MEMORY;
3147 : }
3148 1877 : a_state->sam_ctx = d_state->sam_ctx;
3149 1877 : a_state->access_mask = r->in.access_mask;
3150 1877 : a_state->domain_state = talloc_reference(a_state, d_state);
3151 1877 : a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
3152 1877 : a_state->account_sid = talloc_steal(a_state, sid);
3153 1877 : a_state->account_name = talloc_strdup(a_state, account_name);
3154 1877 : if (!a_state->account_name) {
3155 0 : return NT_STATUS_NO_MEMORY;
3156 : }
3157 :
3158 : /* create the policy handle */
3159 1877 : u_handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_USER);
3160 1877 : if (!u_handle) {
3161 0 : return NT_STATUS_NO_MEMORY;
3162 : }
3163 :
3164 1877 : u_handle->data = talloc_steal(u_handle, a_state);
3165 :
3166 1877 : *r->out.user_handle = u_handle->wire_handle;
3167 :
3168 1877 : return NT_STATUS_OK;
3169 :
3170 : }
3171 :
3172 :
3173 : /*
3174 : samr_DeleteUser
3175 : */
3176 1027 : static NTSTATUS dcesrv_samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3177 : struct samr_DeleteUser *r)
3178 : {
3179 72 : struct dcesrv_handle *h;
3180 72 : struct samr_account_state *a_state;
3181 72 : int ret;
3182 :
3183 1027 : *r->out.user_handle = *r->in.user_handle;
3184 :
3185 1027 : DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3186 :
3187 1027 : a_state = h->data;
3188 :
3189 1027 : ret = ldb_delete(a_state->sam_ctx, a_state->account_dn);
3190 1027 : if (ret != LDB_SUCCESS) {
3191 0 : DEBUG(1, ("Failed to delete user: %s: %s\n",
3192 : ldb_dn_get_linearized(a_state->account_dn),
3193 : ldb_errstring(a_state->sam_ctx)));
3194 0 : return dsdb_ldb_err_to_ntstatus(ret);
3195 : }
3196 :
3197 1027 : talloc_free(h);
3198 1027 : ZERO_STRUCTP(r->out.user_handle);
3199 :
3200 1027 : return NT_STATUS_OK;
3201 : }
3202 :
3203 :
3204 : /*
3205 : samr_QueryUserInfo
3206 : */
3207 11203 : static NTSTATUS dcesrv_samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3208 : struct samr_QueryUserInfo *r)
3209 : {
3210 72 : struct dcesrv_handle *h;
3211 72 : struct samr_account_state *a_state;
3212 72 : struct ldb_message *msg, **res;
3213 72 : int ret;
3214 72 : struct ldb_context *sam_ctx;
3215 :
3216 11203 : const char * const *attrs = NULL;
3217 72 : union samr_UserInfo *info;
3218 :
3219 72 : NTSTATUS status;
3220 :
3221 11203 : *r->out.info = NULL;
3222 :
3223 11203 : DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3224 :
3225 11203 : a_state = h->data;
3226 11203 : sam_ctx = a_state->sam_ctx;
3227 :
3228 : /* fill in the reply */
3229 11203 : switch (r->in.level) {
3230 227 : case 1:
3231 : {
3232 : static const char * const attrs2[] = {"sAMAccountName",
3233 : "displayName",
3234 : "primaryGroupID",
3235 : "description",
3236 : "comment",
3237 : NULL};
3238 227 : attrs = attrs2;
3239 227 : break;
3240 : }
3241 260 : case 2:
3242 : {
3243 0 : static const char * const attrs2[] = {"comment",
3244 : "countryCode",
3245 : "codePage",
3246 : NULL};
3247 260 : attrs = attrs2;
3248 260 : break;
3249 : }
3250 1496 : case 3:
3251 : {
3252 0 : static const char * const attrs2[] = {"sAMAccountName",
3253 : "displayName",
3254 : "objectSid",
3255 : "primaryGroupID",
3256 : "homeDirectory",
3257 : "homeDrive",
3258 : "scriptPath",
3259 : "profilePath",
3260 : "userWorkstations",
3261 : "lastLogon",
3262 : "lastLogoff",
3263 : "pwdLastSet",
3264 : "msDS-UserPasswordExpiryTimeComputed",
3265 : "logonHours",
3266 : "badPwdCount",
3267 : "badPasswordTime",
3268 : "logonCount",
3269 : "userAccountControl",
3270 : "msDS-User-Account-Control-Computed",
3271 : NULL};
3272 1496 : attrs = attrs2;
3273 1496 : break;
3274 : }
3275 174 : case 4:
3276 : {
3277 0 : static const char * const attrs2[] = {"logonHours",
3278 : NULL};
3279 174 : attrs = attrs2;
3280 174 : break;
3281 : }
3282 1732 : case 5:
3283 : {
3284 0 : static const char * const attrs2[] = {"sAMAccountName",
3285 : "displayName",
3286 : "objectSid",
3287 : "primaryGroupID",
3288 : "homeDirectory",
3289 : "homeDrive",
3290 : "scriptPath",
3291 : "profilePath",
3292 : "description",
3293 : "userWorkstations",
3294 : "lastLogon",
3295 : "lastLogoff",
3296 : "logonHours",
3297 : "badPwdCount",
3298 : "badPasswordTime",
3299 : "logonCount",
3300 : "pwdLastSet",
3301 : "msDS-ResultantPSO",
3302 : "msDS-UserPasswordExpiryTimeComputed",
3303 : "accountExpires",
3304 : "userAccountControl",
3305 : "msDS-User-Account-Control-Computed",
3306 : NULL};
3307 1732 : attrs = attrs2;
3308 1732 : break;
3309 : }
3310 426 : case 6:
3311 : {
3312 0 : static const char * const attrs2[] = {"sAMAccountName",
3313 : "displayName",
3314 : NULL};
3315 426 : attrs = attrs2;
3316 426 : break;
3317 : }
3318 258 : case 7:
3319 : {
3320 0 : static const char * const attrs2[] = {"sAMAccountName",
3321 : NULL};
3322 258 : attrs = attrs2;
3323 258 : break;
3324 : }
3325 174 : case 8:
3326 : {
3327 0 : static const char * const attrs2[] = {"displayName",
3328 : NULL};
3329 174 : attrs = attrs2;
3330 174 : break;
3331 : }
3332 102 : case 9:
3333 : {
3334 0 : static const char * const attrs2[] = {"primaryGroupID",
3335 : NULL};
3336 102 : attrs = attrs2;
3337 102 : break;
3338 : }
3339 278 : case 10:
3340 : {
3341 0 : static const char * const attrs2[] = {"homeDirectory",
3342 : "homeDrive",
3343 : NULL};
3344 278 : attrs = attrs2;
3345 278 : break;
3346 : }
3347 174 : case 11:
3348 : {
3349 0 : static const char * const attrs2[] = {"scriptPath",
3350 : NULL};
3351 174 : attrs = attrs2;
3352 174 : break;
3353 : }
3354 186 : case 12:
3355 : {
3356 0 : static const char * const attrs2[] = {"profilePath",
3357 : NULL};
3358 186 : attrs = attrs2;
3359 186 : break;
3360 : }
3361 174 : case 13:
3362 : {
3363 0 : static const char * const attrs2[] = {"description",
3364 : NULL};
3365 174 : attrs = attrs2;
3366 174 : break;
3367 : }
3368 186 : case 14:
3369 : {
3370 0 : static const char * const attrs2[] = {"userWorkstations",
3371 : NULL};
3372 186 : attrs = attrs2;
3373 186 : break;
3374 : }
3375 2049 : case 16:
3376 : {
3377 72 : static const char * const attrs2[] = {"userAccountControl",
3378 : "msDS-User-Account-Control-Computed",
3379 : "pwdLastSet",
3380 : "msDS-UserPasswordExpiryTimeComputed",
3381 : NULL};
3382 2049 : attrs = attrs2;
3383 2049 : break;
3384 : }
3385 162 : case 17:
3386 : {
3387 0 : static const char * const attrs2[] = {"accountExpires",
3388 : NULL};
3389 162 : attrs = attrs2;
3390 162 : break;
3391 : }
3392 0 : case 18:
3393 : {
3394 0 : return NT_STATUS_NOT_SUPPORTED;
3395 : }
3396 174 : case 20:
3397 : {
3398 0 : static const char * const attrs2[] = {"userParameters",
3399 : NULL};
3400 174 : attrs = attrs2;
3401 174 : break;
3402 : }
3403 2971 : case 21:
3404 : {
3405 0 : static const char * const attrs2[] = {"lastLogon",
3406 : "lastLogoff",
3407 : "pwdLastSet",
3408 : "msDS-ResultantPSO",
3409 : "msDS-UserPasswordExpiryTimeComputed",
3410 : "accountExpires",
3411 : "sAMAccountName",
3412 : "displayName",
3413 : "homeDirectory",
3414 : "homeDrive",
3415 : "scriptPath",
3416 : "profilePath",
3417 : "description",
3418 : "userWorkstations",
3419 : "comment",
3420 : "userParameters",
3421 : "objectSid",
3422 : "primaryGroupID",
3423 : "userAccountControl",
3424 : "msDS-User-Account-Control-Computed",
3425 : "logonHours",
3426 : "badPwdCount",
3427 : "badPasswordTime",
3428 : "logonCount",
3429 : "countryCode",
3430 : "codePage",
3431 : NULL};
3432 2971 : attrs = attrs2;
3433 2971 : break;
3434 : }
3435 0 : case 23:
3436 : case 24:
3437 : case 25:
3438 : case 26:
3439 : {
3440 0 : return NT_STATUS_NOT_SUPPORTED;
3441 : }
3442 0 : default:
3443 : {
3444 0 : return NT_STATUS_INVALID_INFO_CLASS;
3445 : }
3446 : }
3447 :
3448 : /* pull all the user attributes */
3449 11203 : ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3450 : a_state->account_dn, &res, attrs);
3451 11203 : if (ret == 0) {
3452 0 : return NT_STATUS_NO_SUCH_USER;
3453 : }
3454 11203 : if (ret != 1) {
3455 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
3456 : }
3457 11203 : msg = res[0];
3458 :
3459 : /* allocate the info structure */
3460 11203 : info = talloc_zero(mem_ctx, union samr_UserInfo);
3461 11203 : if (info == NULL) {
3462 0 : return NT_STATUS_NO_MEMORY;
3463 : }
3464 :
3465 : /* fill in the reply */
3466 11203 : switch (r->in.level) {
3467 227 : case 1:
3468 227 : QUERY_STRING(msg, info1.account_name, "sAMAccountName");
3469 227 : QUERY_STRING(msg, info1.full_name, "displayName");
3470 227 : QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
3471 227 : QUERY_STRING(msg, info1.description, "description");
3472 227 : QUERY_STRING(msg, info1.comment, "comment");
3473 227 : break;
3474 :
3475 260 : case 2:
3476 260 : QUERY_STRING(msg, info2.comment, "comment");
3477 260 : QUERY_UINT (msg, info2.country_code, "countryCode");
3478 260 : QUERY_UINT (msg, info2.code_page, "codePage");
3479 260 : break;
3480 :
3481 1496 : case 3:
3482 1496 : QUERY_STRING(msg, info3.account_name, "sAMAccountName");
3483 1496 : QUERY_STRING(msg, info3.full_name, "displayName");
3484 1496 : QUERY_RID (msg, info3.rid, "objectSid");
3485 1496 : QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
3486 1496 : QUERY_STRING(msg, info3.home_directory, "homeDirectory");
3487 1496 : QUERY_STRING(msg, info3.home_drive, "homeDrive");
3488 1496 : QUERY_STRING(msg, info3.logon_script, "scriptPath");
3489 1496 : QUERY_STRING(msg, info3.profile_path, "profilePath");
3490 1496 : QUERY_STRING(msg, info3.workstations, "userWorkstations");
3491 1496 : QUERY_UINT64(msg, info3.last_logon, "lastLogon");
3492 1496 : QUERY_UINT64(msg, info3.last_logoff, "lastLogoff");
3493 1496 : QUERY_UINT64(msg, info3.last_password_change, "pwdLastSet");
3494 1496 : QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3495 1496 : QUERY_UINT64(msg, info3.force_password_change, "msDS-UserPasswordExpiryTimeComputed");
3496 1496 : QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
3497 : /* level 3 gives the raw badPwdCount value */
3498 1496 : QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
3499 1496 : QUERY_UINT (msg, info3.logon_count, "logonCount");
3500 1496 : QUERY_AFLAGS(msg, info3.acct_flags, "msDS-User-Account-Control-Computed");
3501 1496 : break;
3502 :
3503 174 : case 4:
3504 174 : QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
3505 174 : break;
3506 :
3507 1732 : case 5:
3508 1732 : QUERY_STRING(msg, info5.account_name, "sAMAccountName");
3509 1732 : QUERY_STRING(msg, info5.full_name, "displayName");
3510 1732 : QUERY_RID (msg, info5.rid, "objectSid");
3511 1732 : QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
3512 1732 : QUERY_STRING(msg, info5.home_directory, "homeDirectory");
3513 1732 : QUERY_STRING(msg, info5.home_drive, "homeDrive");
3514 1732 : QUERY_STRING(msg, info5.logon_script, "scriptPath");
3515 1732 : QUERY_STRING(msg, info5.profile_path, "profilePath");
3516 1732 : QUERY_STRING(msg, info5.description, "description");
3517 1732 : QUERY_STRING(msg, info5.workstations, "userWorkstations");
3518 1732 : QUERY_UINT64(msg, info5.last_logon, "lastLogon");
3519 1732 : QUERY_UINT64(msg, info5.last_logoff, "lastLogoff");
3520 1732 : QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
3521 1732 : QUERY_BPWDCT(msg, info5.bad_password_count, "badPwdCount");
3522 1732 : QUERY_UINT (msg, info5.logon_count, "logonCount");
3523 1732 : QUERY_UINT64(msg, info5.last_password_change, "pwdLastSet");
3524 1732 : QUERY_UINT64(msg, info5.acct_expiry, "accountExpires");
3525 1732 : QUERY_AFLAGS(msg, info5.acct_flags, "msDS-User-Account-Control-Computed");
3526 1732 : break;
3527 :
3528 426 : case 6:
3529 426 : QUERY_STRING(msg, info6.account_name, "sAMAccountName");
3530 426 : QUERY_STRING(msg, info6.full_name, "displayName");
3531 426 : break;
3532 :
3533 258 : case 7:
3534 258 : QUERY_STRING(msg, info7.account_name, "sAMAccountName");
3535 258 : break;
3536 :
3537 174 : case 8:
3538 174 : QUERY_STRING(msg, info8.full_name, "displayName");
3539 174 : break;
3540 :
3541 102 : case 9:
3542 102 : QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
3543 102 : break;
3544 :
3545 278 : case 10:
3546 278 : QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3547 278 : QUERY_STRING(msg, info10.home_drive, "homeDrive");
3548 278 : break;
3549 :
3550 174 : case 11:
3551 174 : QUERY_STRING(msg, info11.logon_script, "scriptPath");
3552 174 : break;
3553 :
3554 186 : case 12:
3555 186 : QUERY_STRING(msg, info12.profile_path, "profilePath");
3556 186 : break;
3557 :
3558 174 : case 13:
3559 174 : QUERY_STRING(msg, info13.description, "description");
3560 174 : break;
3561 :
3562 186 : case 14:
3563 186 : QUERY_STRING(msg, info14.workstations, "userWorkstations");
3564 186 : break;
3565 :
3566 2049 : case 16:
3567 2049 : QUERY_AFLAGS(msg, info16.acct_flags, "msDS-User-Account-Control-Computed");
3568 2049 : break;
3569 :
3570 162 : case 17:
3571 162 : QUERY_UINT64(msg, info17.acct_expiry, "accountExpires");
3572 162 : break;
3573 :
3574 174 : case 20:
3575 174 : status = samdb_result_parameters(mem_ctx, msg, "userParameters", &info->info20.parameters);
3576 174 : if (!NT_STATUS_IS_OK(status)) {
3577 0 : talloc_free(info);
3578 0 : return status;
3579 : }
3580 174 : break;
3581 :
3582 2971 : case 21:
3583 2971 : QUERY_UINT64(msg, info21.last_logon, "lastLogon");
3584 2971 : QUERY_UINT64(msg, info21.last_logoff, "lastLogoff");
3585 2971 : QUERY_UINT64(msg, info21.last_password_change, "pwdLastSet");
3586 2971 : QUERY_UINT64(msg, info21.acct_expiry, "accountExpires");
3587 2971 : QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3588 2971 : QUERY_UINT64(msg, info21.force_password_change, "msDS-UserPasswordExpiryTimeComputed");
3589 2971 : QUERY_STRING(msg, info21.account_name, "sAMAccountName");
3590 2971 : QUERY_STRING(msg, info21.full_name, "displayName");
3591 2971 : QUERY_STRING(msg, info21.home_directory, "homeDirectory");
3592 2971 : QUERY_STRING(msg, info21.home_drive, "homeDrive");
3593 2971 : QUERY_STRING(msg, info21.logon_script, "scriptPath");
3594 2971 : QUERY_STRING(msg, info21.profile_path, "profilePath");
3595 2971 : QUERY_STRING(msg, info21.description, "description");
3596 2971 : QUERY_STRING(msg, info21.workstations, "userWorkstations");
3597 2971 : QUERY_STRING(msg, info21.comment, "comment");
3598 2971 : status = samdb_result_parameters(mem_ctx, msg, "userParameters", &info->info21.parameters);
3599 2971 : if (!NT_STATUS_IS_OK(status)) {
3600 0 : talloc_free(info);
3601 0 : return status;
3602 : }
3603 :
3604 2971 : QUERY_RID (msg, info21.rid, "objectSid");
3605 2971 : QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
3606 2971 : QUERY_AFLAGS(msg, info21.acct_flags, "msDS-User-Account-Control-Computed");
3607 2971 : info->info21.fields_present = 0x08FFFFFF;
3608 2971 : QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
3609 2971 : QUERY_BPWDCT(msg, info21.bad_password_count, "badPwdCount");
3610 2971 : QUERY_UINT (msg, info21.logon_count, "logonCount");
3611 2971 : if ((info->info21.acct_flags & ACB_PW_EXPIRED) != 0) {
3612 735 : info->info21.password_expired = PASS_MUST_CHANGE_AT_NEXT_LOGON;
3613 : } else {
3614 2236 : info->info21.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON;
3615 : }
3616 2971 : QUERY_UINT (msg, info21.country_code, "countryCode");
3617 2971 : QUERY_UINT (msg, info21.code_page, "codePage");
3618 2971 : break;
3619 :
3620 :
3621 0 : default:
3622 0 : talloc_free(info);
3623 0 : return NT_STATUS_INVALID_INFO_CLASS;
3624 : }
3625 :
3626 11203 : *r->out.info = info;
3627 :
3628 11203 : return NT_STATUS_OK;
3629 : }
3630 :
3631 :
3632 : /*
3633 : samr_SetUserInfo
3634 : */
3635 4223 : static NTSTATUS dcesrv_samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3636 : struct samr_SetUserInfo *r)
3637 : {
3638 144 : struct dcesrv_handle *h;
3639 144 : struct samr_account_state *a_state;
3640 144 : struct ldb_message *msg;
3641 144 : int ret;
3642 4223 : NTSTATUS status = NT_STATUS_OK;
3643 144 : struct ldb_context *sam_ctx;
3644 4223 : DATA_BLOB session_key = data_blob_null;
3645 :
3646 4223 : DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3647 :
3648 4223 : a_state = h->data;
3649 4223 : sam_ctx = a_state->sam_ctx;
3650 :
3651 4223 : msg = ldb_msg_new(mem_ctx);
3652 4223 : if (msg == NULL) {
3653 0 : return NT_STATUS_NO_MEMORY;
3654 : }
3655 :
3656 4223 : msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3657 4223 : if (!msg->dn) {
3658 0 : return NT_STATUS_NO_MEMORY;
3659 : }
3660 :
3661 4223 : ret = ldb_transaction_start(sam_ctx);
3662 4223 : if (ret != LDB_SUCCESS) {
3663 0 : DBG_ERR("Failed to start a transaction: %s\n",
3664 : ldb_errstring(sam_ctx));
3665 0 : return NT_STATUS_LOCK_NOT_GRANTED;
3666 : }
3667 :
3668 4223 : switch (r->in.level) {
3669 122 : case 2:
3670 122 : SET_STRING(msg, info2.comment, "comment");
3671 122 : SET_UINT (msg, info2.country_code, "countryCode");
3672 122 : SET_UINT (msg, info2.code_page, "codePage");
3673 122 : break;
3674 :
3675 72 : case 4:
3676 72 : SET_LHOURS(msg, info4.logon_hours, "logonHours");
3677 72 : break;
3678 :
3679 288 : case 6:
3680 288 : SET_STRING(msg, info6.account_name, "samAccountName");
3681 288 : SET_STRING(msg, info6.full_name, "displayName");
3682 288 : break;
3683 :
3684 150 : case 7:
3685 150 : SET_STRING(msg, info7.account_name, "samAccountName");
3686 150 : break;
3687 :
3688 51 : case 8:
3689 51 : SET_STRING(msg, info8.full_name, "displayName");
3690 51 : break;
3691 :
3692 0 : case 9:
3693 0 : SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3694 0 : break;
3695 :
3696 150 : case 10:
3697 150 : SET_STRING(msg, info10.home_directory, "homeDirectory");
3698 150 : SET_STRING(msg, info10.home_drive, "homeDrive");
3699 150 : break;
3700 :
3701 79 : case 11:
3702 79 : SET_STRING(msg, info11.logon_script, "scriptPath");
3703 79 : break;
3704 :
3705 82 : case 12:
3706 82 : SET_STRING(msg, info12.profile_path, "profilePath");
3707 82 : break;
3708 :
3709 81 : case 13:
3710 81 : SET_STRING(msg, info13.description, "description");
3711 81 : break;
3712 :
3713 72 : case 14:
3714 72 : SET_STRING(msg, info14.workstations, "userWorkstations");
3715 72 : break;
3716 :
3717 302 : case 16:
3718 302 : SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3719 302 : break;
3720 :
3721 56 : case 17:
3722 56 : SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3723 56 : break;
3724 :
3725 158 : case 18:
3726 114 : status = samr_set_password_buffers(dce_call,
3727 : sam_ctx,
3728 : a_state->account_dn,
3729 158 : a_state->domain_state->domain_dn,
3730 : mem_ctx,
3731 158 : r->in.info->info18.lm_pwd_active ? r->in.info->info18.lm_pwd.hash : NULL,
3732 158 : r->in.info->info18.nt_pwd_active ? r->in.info->info18.nt_pwd.hash : NULL);
3733 158 : if (!NT_STATUS_IS_OK(status)) {
3734 229 : goto done;
3735 : }
3736 :
3737 158 : if (r->in.info->info18.password_expired > 0) {
3738 0 : struct ldb_message_element *set_el;
3739 16 : if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3740 0 : status = NT_STATUS_NO_MEMORY;
3741 0 : goto done;
3742 : }
3743 16 : set_el = ldb_msg_find_element(msg, "pwdLastSet");
3744 16 : set_el->flags = LDB_FLAG_MOD_REPLACE;
3745 : }
3746 158 : break;
3747 :
3748 48 : case 20:
3749 48 : SET_PARAMETERS(msg, info20.parameters, "userParameters");
3750 48 : break;
3751 :
3752 1491 : case 21:
3753 1491 : if (r->in.info->info21.fields_present == 0) {
3754 8 : status = NT_STATUS_INVALID_PARAMETER;
3755 8 : goto done;
3756 : }
3757 :
3758 : #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3759 1483 : IFSET(SAMR_FIELD_LAST_LOGON)
3760 0 : SET_UINT64(msg, info21.last_logon, "lastLogon");
3761 1483 : IFSET(SAMR_FIELD_LAST_LOGOFF)
3762 0 : SET_UINT64(msg, info21.last_logoff, "lastLogoff");
3763 1483 : IFSET(SAMR_FIELD_ACCT_EXPIRY)
3764 74 : SET_UINT64(msg, info21.acct_expiry, "accountExpires");
3765 1483 : IFSET(SAMR_FIELD_ACCOUNT_NAME)
3766 25 : SET_STRING(msg, info21.account_name, "samAccountName");
3767 1483 : IFSET(SAMR_FIELD_FULL_NAME)
3768 563 : SET_STRING(msg, info21.full_name, "displayName");
3769 1483 : IFSET(SAMR_FIELD_HOME_DIRECTORY)
3770 50 : SET_STRING(msg, info21.home_directory, "homeDirectory");
3771 1483 : IFSET(SAMR_FIELD_HOME_DRIVE)
3772 50 : SET_STRING(msg, info21.home_drive, "homeDrive");
3773 1483 : IFSET(SAMR_FIELD_LOGON_SCRIPT)
3774 26 : SET_STRING(msg, info21.logon_script, "scriptPath");
3775 1483 : IFSET(SAMR_FIELD_PROFILE_PATH)
3776 26 : SET_STRING(msg, info21.profile_path, "profilePath");
3777 1483 : IFSET(SAMR_FIELD_DESCRIPTION)
3778 540 : SET_STRING(msg, info21.description, "description");
3779 1483 : IFSET(SAMR_FIELD_WORKSTATIONS)
3780 100 : SET_STRING(msg, info21.workstations, "userWorkstations");
3781 1483 : IFSET(SAMR_FIELD_COMMENT)
3782 571 : SET_STRING(msg, info21.comment, "comment");
3783 1483 : IFSET(SAMR_FIELD_PARAMETERS)
3784 96 : SET_PARAMETERS(msg, info21.parameters, "userParameters");
3785 1483 : IFSET(SAMR_FIELD_PRIMARY_GID)
3786 2 : SET_UINT(msg, info21.primary_gid, "primaryGroupID");
3787 1483 : IFSET(SAMR_FIELD_ACCT_FLAGS)
3788 43 : SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3789 1483 : IFSET(SAMR_FIELD_LOGON_HOURS)
3790 27 : SET_LHOURS(msg, info21.logon_hours, "logonHours");
3791 1483 : IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3792 0 : SET_UINT (msg, info21.bad_password_count, "badPwdCount");
3793 1483 : IFSET(SAMR_FIELD_NUM_LOGONS)
3794 0 : SET_UINT (msg, info21.logon_count, "logonCount");
3795 1483 : IFSET(SAMR_FIELD_COUNTRY_CODE)
3796 48 : SET_UINT (msg, info21.country_code, "countryCode");
3797 1483 : IFSET(SAMR_FIELD_CODE_PAGE)
3798 48 : SET_UINT (msg, info21.code_page, "codePage");
3799 :
3800 : /* password change fields */
3801 1483 : IFSET(SAMR_FIELD_LAST_PWD_CHANGE) {
3802 40 : status = NT_STATUS_ACCESS_DENIED;
3803 40 : goto done;
3804 : }
3805 :
3806 1443 : IFSET((SAMR_FIELD_LM_PASSWORD_PRESENT
3807 : | SAMR_FIELD_NT_PASSWORD_PRESENT)) {
3808 188 : uint8_t *lm_pwd_hash = NULL, *nt_pwd_hash = NULL;
3809 :
3810 188 : if (r->in.info->info21.lm_password_set) {
3811 100 : if ((r->in.info->info21.lm_owf_password.length != 16)
3812 88 : || (r->in.info->info21.lm_owf_password.size != 16)) {
3813 12 : status = NT_STATUS_INVALID_PARAMETER;
3814 12 : goto done;
3815 : }
3816 :
3817 88 : lm_pwd_hash = (uint8_t *) r->in.info->info21.lm_owf_password.array;
3818 : }
3819 176 : if (r->in.info->info21.nt_password_set) {
3820 176 : if ((r->in.info->info21.nt_owf_password.length != 16)
3821 152 : || (r->in.info->info21.nt_owf_password.size != 16)) {
3822 24 : status = NT_STATUS_INVALID_PARAMETER;
3823 24 : goto done;
3824 : }
3825 :
3826 152 : nt_pwd_hash = (uint8_t *) r->in.info->info21.nt_owf_password.array;
3827 : }
3828 152 : status = samr_set_password_buffers(dce_call,
3829 : sam_ctx,
3830 : a_state->account_dn,
3831 152 : a_state->domain_state->domain_dn,
3832 : mem_ctx,
3833 : lm_pwd_hash,
3834 : nt_pwd_hash);
3835 152 : if (!NT_STATUS_IS_OK(status)) {
3836 0 : goto done;
3837 : }
3838 : }
3839 :
3840 :
3841 1407 : IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3842 98 : const char *t = "0";
3843 0 : struct ldb_message_element *set_el;
3844 98 : if (r->in.info->info21.password_expired
3845 : == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3846 50 : t = "-1";
3847 : }
3848 98 : if (ldb_msg_add_string(msg, "pwdLastSet", t) != LDB_SUCCESS) {
3849 0 : status = NT_STATUS_NO_MEMORY;
3850 0 : goto done;
3851 : }
3852 98 : set_el = ldb_msg_find_element(msg, "pwdLastSet");
3853 98 : set_el->flags = LDB_FLAG_MOD_REPLACE;
3854 : }
3855 : #undef IFSET
3856 1335 : break;
3857 :
3858 74 : case 23:
3859 74 : if (r->in.info->info23.info.fields_present == 0) {
3860 0 : status = NT_STATUS_INVALID_PARAMETER;
3861 0 : goto done;
3862 : }
3863 :
3864 : #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3865 74 : IFSET(SAMR_FIELD_LAST_LOGON)
3866 0 : SET_UINT64(msg, info23.info.last_logon, "lastLogon");
3867 74 : IFSET(SAMR_FIELD_LAST_LOGOFF)
3868 0 : SET_UINT64(msg, info23.info.last_logoff, "lastLogoff");
3869 74 : IFSET(SAMR_FIELD_ACCT_EXPIRY)
3870 0 : SET_UINT64(msg, info23.info.acct_expiry, "accountExpires");
3871 74 : IFSET(SAMR_FIELD_ACCOUNT_NAME)
3872 0 : SET_STRING(msg, info23.info.account_name, "samAccountName");
3873 74 : IFSET(SAMR_FIELD_FULL_NAME)
3874 0 : SET_STRING(msg, info23.info.full_name, "displayName");
3875 74 : IFSET(SAMR_FIELD_HOME_DIRECTORY)
3876 0 : SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3877 74 : IFSET(SAMR_FIELD_HOME_DRIVE)
3878 0 : SET_STRING(msg, info23.info.home_drive, "homeDrive");
3879 74 : IFSET(SAMR_FIELD_LOGON_SCRIPT)
3880 0 : SET_STRING(msg, info23.info.logon_script, "scriptPath");
3881 74 : IFSET(SAMR_FIELD_PROFILE_PATH)
3882 0 : SET_STRING(msg, info23.info.profile_path, "profilePath");
3883 74 : IFSET(SAMR_FIELD_DESCRIPTION)
3884 0 : SET_STRING(msg, info23.info.description, "description");
3885 74 : IFSET(SAMR_FIELD_WORKSTATIONS)
3886 0 : SET_STRING(msg, info23.info.workstations, "userWorkstations");
3887 74 : IFSET(SAMR_FIELD_COMMENT)
3888 0 : SET_STRING(msg, info23.info.comment, "comment");
3889 74 : IFSET(SAMR_FIELD_PARAMETERS)
3890 0 : SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3891 74 : IFSET(SAMR_FIELD_PRIMARY_GID)
3892 0 : SET_UINT(msg, info23.info.primary_gid, "primaryGroupID");
3893 74 : IFSET(SAMR_FIELD_ACCT_FLAGS)
3894 0 : SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3895 74 : IFSET(SAMR_FIELD_LOGON_HOURS)
3896 0 : SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3897 74 : IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3898 0 : SET_UINT (msg, info23.info.bad_password_count, "badPwdCount");
3899 74 : IFSET(SAMR_FIELD_NUM_LOGONS)
3900 0 : SET_UINT (msg, info23.info.logon_count, "logonCount");
3901 :
3902 74 : IFSET(SAMR_FIELD_COUNTRY_CODE)
3903 0 : SET_UINT (msg, info23.info.country_code, "countryCode");
3904 74 : IFSET(SAMR_FIELD_CODE_PAGE)
3905 0 : SET_UINT (msg, info23.info.code_page, "codePage");
3906 :
3907 : /* password change fields */
3908 74 : IFSET(SAMR_FIELD_LAST_PWD_CHANGE) {
3909 0 : status = NT_STATUS_ACCESS_DENIED;
3910 0 : goto done;
3911 : }
3912 :
3913 74 : IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3914 50 : status = samr_set_password(dce_call,
3915 : sam_ctx,
3916 : a_state->account_dn,
3917 50 : a_state->domain_state->domain_dn,
3918 : mem_ctx,
3919 50 : &r->in.info->info23.password);
3920 24 : } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3921 24 : status = samr_set_password(dce_call,
3922 : sam_ctx,
3923 : a_state->account_dn,
3924 24 : a_state->domain_state->domain_dn,
3925 : mem_ctx,
3926 24 : &r->in.info->info23.password);
3927 : }
3928 74 : if (!NT_STATUS_IS_OK(status)) {
3929 36 : goto done;
3930 : }
3931 :
3932 38 : IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3933 2 : const char *t = "0";
3934 0 : struct ldb_message_element *set_el;
3935 2 : if (r->in.info->info23.info.password_expired
3936 : == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3937 2 : t = "-1";
3938 : }
3939 2 : if (ldb_msg_add_string(msg, "pwdLastSet", t) != LDB_SUCCESS) {
3940 0 : status = NT_STATUS_NO_MEMORY;
3941 0 : goto done;
3942 : }
3943 2 : set_el = ldb_msg_find_element(msg, "pwdLastSet");
3944 2 : set_el->flags = LDB_FLAG_MOD_REPLACE;
3945 : }
3946 : #undef IFSET
3947 38 : break;
3948 :
3949 : /* the set password levels are handled separately */
3950 173 : case 24:
3951 173 : status = samr_set_password(dce_call,
3952 : sam_ctx,
3953 : a_state->account_dn,
3954 173 : a_state->domain_state->domain_dn,
3955 : mem_ctx,
3956 173 : &r->in.info->info24.password);
3957 173 : if (!NT_STATUS_IS_OK(status)) {
3958 0 : goto done;
3959 : }
3960 :
3961 173 : if (r->in.info->info24.password_expired > 0) {
3962 0 : struct ldb_message_element *set_el;
3963 4 : if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3964 0 : status = NT_STATUS_NO_MEMORY;
3965 0 : goto done;
3966 : }
3967 4 : set_el = ldb_msg_find_element(msg, "pwdLastSet");
3968 4 : set_el->flags = LDB_FLAG_MOD_REPLACE;
3969 : }
3970 173 : break;
3971 :
3972 593 : case 25:
3973 593 : if (r->in.info->info25.info.fields_present == 0) {
3974 0 : status = NT_STATUS_INVALID_PARAMETER;
3975 0 : goto done;
3976 : }
3977 :
3978 : #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3979 593 : IFSET(SAMR_FIELD_LAST_LOGON)
3980 0 : SET_UINT64(msg, info25.info.last_logon, "lastLogon");
3981 593 : IFSET(SAMR_FIELD_LAST_LOGOFF)
3982 0 : SET_UINT64(msg, info25.info.last_logoff, "lastLogoff");
3983 593 : IFSET(SAMR_FIELD_ACCT_EXPIRY)
3984 0 : SET_UINT64(msg, info25.info.acct_expiry, "accountExpires");
3985 593 : IFSET(SAMR_FIELD_ACCOUNT_NAME)
3986 4 : SET_STRING(msg, info25.info.account_name, "samAccountName");
3987 593 : IFSET(SAMR_FIELD_FULL_NAME)
3988 509 : SET_STRING(msg, info25.info.full_name, "displayName");
3989 593 : IFSET(SAMR_FIELD_HOME_DIRECTORY)
3990 0 : SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3991 593 : IFSET(SAMR_FIELD_HOME_DRIVE)
3992 0 : SET_STRING(msg, info25.info.home_drive, "homeDrive");
3993 593 : IFSET(SAMR_FIELD_LOGON_SCRIPT)
3994 0 : SET_STRING(msg, info25.info.logon_script, "scriptPath");
3995 593 : IFSET(SAMR_FIELD_PROFILE_PATH)
3996 0 : SET_STRING(msg, info25.info.profile_path, "profilePath");
3997 593 : IFSET(SAMR_FIELD_DESCRIPTION)
3998 2 : SET_STRING(msg, info25.info.description, "description");
3999 593 : IFSET(SAMR_FIELD_WORKSTATIONS)
4000 0 : SET_STRING(msg, info25.info.workstations, "userWorkstations");
4001 593 : IFSET(SAMR_FIELD_COMMENT)
4002 0 : SET_STRING(msg, info25.info.comment, "comment");
4003 593 : IFSET(SAMR_FIELD_PARAMETERS)
4004 0 : SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
4005 593 : IFSET(SAMR_FIELD_PRIMARY_GID)
4006 0 : SET_UINT(msg, info25.info.primary_gid, "primaryGroupID");
4007 593 : IFSET(SAMR_FIELD_ACCT_FLAGS)
4008 513 : SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
4009 593 : IFSET(SAMR_FIELD_LOGON_HOURS)
4010 0 : SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
4011 593 : IFSET(SAMR_FIELD_BAD_PWD_COUNT)
4012 0 : SET_UINT (msg, info25.info.bad_password_count, "badPwdCount");
4013 593 : IFSET(SAMR_FIELD_NUM_LOGONS)
4014 0 : SET_UINT (msg, info25.info.logon_count, "logonCount");
4015 593 : IFSET(SAMR_FIELD_COUNTRY_CODE)
4016 0 : SET_UINT (msg, info25.info.country_code, "countryCode");
4017 593 : IFSET(SAMR_FIELD_CODE_PAGE)
4018 0 : SET_UINT (msg, info25.info.code_page, "codePage");
4019 :
4020 : /* password change fields */
4021 593 : IFSET(SAMR_FIELD_LAST_PWD_CHANGE) {
4022 0 : status = NT_STATUS_ACCESS_DENIED;
4023 0 : goto done;
4024 : }
4025 :
4026 593 : IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
4027 569 : status = samr_set_password_ex(dce_call,
4028 : sam_ctx,
4029 : a_state->account_dn,
4030 569 : a_state->domain_state->domain_dn,
4031 : mem_ctx,
4032 497 : &r->in.info->info25.password);
4033 24 : } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
4034 24 : status = samr_set_password_ex(dce_call,
4035 : sam_ctx,
4036 : a_state->account_dn,
4037 24 : a_state->domain_state->domain_dn,
4038 : mem_ctx,
4039 24 : &r->in.info->info25.password);
4040 : }
4041 593 : if (!NT_STATUS_IS_OK(status)) {
4042 36 : goto done;
4043 : }
4044 :
4045 557 : IFSET(SAMR_FIELD_EXPIRED_FLAG) {
4046 0 : const char *t = "0";
4047 0 : struct ldb_message_element *set_el;
4048 0 : if (r->in.info->info25.info.password_expired
4049 : == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
4050 0 : t = "-1";
4051 : }
4052 0 : if (ldb_msg_add_string(msg, "pwdLastSet", t) != LDB_SUCCESS) {
4053 0 : status = NT_STATUS_NO_MEMORY;
4054 0 : goto done;
4055 : }
4056 0 : set_el = ldb_msg_find_element(msg, "pwdLastSet");
4057 0 : set_el->flags = LDB_FLAG_MOD_REPLACE;
4058 : }
4059 : #undef IFSET
4060 485 : break;
4061 :
4062 : /* the set password levels are handled separately */
4063 85 : case 26:
4064 85 : status = samr_set_password_ex(dce_call,
4065 : sam_ctx,
4066 : a_state->account_dn,
4067 85 : a_state->domain_state->domain_dn,
4068 : mem_ctx,
4069 85 : &r->in.info->info26.password);
4070 85 : if (!NT_STATUS_IS_OK(status)) {
4071 25 : goto done;
4072 : }
4073 :
4074 60 : if (r->in.info->info26.password_expired > 0) {
4075 16 : const char *t = "0";
4076 0 : struct ldb_message_element *set_el;
4077 16 : if (r->in.info->info26.password_expired
4078 : == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
4079 0 : t = "-1";
4080 : }
4081 16 : if (ldb_msg_add_string(msg, "pwdLastSet", t) != LDB_SUCCESS) {
4082 0 : status = NT_STATUS_NO_MEMORY;
4083 0 : goto done;
4084 : }
4085 16 : set_el = ldb_msg_find_element(msg, "pwdLastSet");
4086 16 : set_el->flags = LDB_FLAG_MOD_REPLACE;
4087 : }
4088 60 : break;
4089 :
4090 24 : case 31:
4091 24 : status = dcesrv_transport_session_key(dce_call, &session_key);
4092 24 : if (!NT_STATUS_IS_OK(status)) {
4093 0 : DBG_NOTICE("samr: failed to get session key: %s\n",
4094 : nt_errstr(status));
4095 0 : goto done;
4096 : }
4097 :
4098 24 : status = samr_set_password_aes(dce_call,
4099 : mem_ctx,
4100 : &session_key,
4101 : sam_ctx,
4102 : a_state->account_dn,
4103 24 : a_state->domain_state->domain_dn,
4104 24 : &r->in.info->info31.password,
4105 : DSDB_PASSWORD_RESET);
4106 24 : if (!NT_STATUS_IS_OK(status)) {
4107 12 : goto done;
4108 : }
4109 :
4110 12 : if (r->in.info->info31.password_expired > 0) {
4111 0 : const char *t = "0";
4112 0 : struct ldb_message_element *set_el = NULL;
4113 :
4114 0 : if (r->in.info->info31.password_expired ==
4115 : PASS_DONT_CHANGE_AT_NEXT_LOGON) {
4116 0 : t = "-1";
4117 : }
4118 :
4119 0 : ret = ldb_msg_add_string(msg, "pwdLastSet", t);
4120 0 : if (ret != LDB_SUCCESS) {
4121 0 : status = NT_STATUS_NO_MEMORY;
4122 0 : goto done;
4123 : }
4124 0 : set_el = ldb_msg_find_element(msg, "pwdLastSet");
4125 0 : set_el->flags = LDB_FLAG_MOD_REPLACE;
4126 : }
4127 :
4128 12 : break;
4129 72 : case 32:
4130 72 : status = dcesrv_transport_session_key(dce_call, &session_key);
4131 72 : if (!NT_STATUS_IS_OK(status)) {
4132 0 : DBG_NOTICE("samr: failed to get session key: %s\n",
4133 : nt_errstr(status));
4134 0 : goto done;
4135 : }
4136 :
4137 72 : if (r->in.info->info32.info.fields_present == 0) {
4138 0 : status = NT_STATUS_INVALID_PARAMETER;
4139 0 : goto done;
4140 : }
4141 :
4142 : #define IFSET(bit) if (bit & r->in.info->info32.info.fields_present)
4143 72 : IFSET(SAMR_FIELD_LAST_LOGON)
4144 : {
4145 0 : SET_UINT64(msg, info32.info.last_logon, "lastLogon");
4146 : }
4147 72 : IFSET(SAMR_FIELD_LAST_LOGOFF)
4148 : {
4149 0 : SET_UINT64(msg, info32.info.last_logoff, "lastLogoff");
4150 : }
4151 72 : IFSET(SAMR_FIELD_ACCT_EXPIRY)
4152 : {
4153 0 : SET_UINT64(msg,
4154 : info32.info.acct_expiry,
4155 : "accountExpires");
4156 : }
4157 72 : IFSET(SAMR_FIELD_ACCOUNT_NAME)
4158 : {
4159 0 : SET_STRING(msg,
4160 : info32.info.account_name,
4161 : "samAccountName");
4162 : }
4163 72 : IFSET(SAMR_FIELD_FULL_NAME)
4164 : {
4165 0 : SET_STRING(msg, info32.info.full_name, "displayName");
4166 : }
4167 72 : IFSET(SAMR_FIELD_HOME_DIRECTORY)
4168 : {
4169 0 : SET_STRING(msg,
4170 : info32.info.home_directory,
4171 : "homeDirectory");
4172 : }
4173 72 : IFSET(SAMR_FIELD_HOME_DRIVE)
4174 : {
4175 0 : SET_STRING(msg, info32.info.home_drive, "homeDrive");
4176 : }
4177 72 : IFSET(SAMR_FIELD_LOGON_SCRIPT)
4178 : {
4179 0 : SET_STRING(msg, info32.info.logon_script, "scriptPath");
4180 : }
4181 72 : IFSET(SAMR_FIELD_PROFILE_PATH)
4182 : {
4183 0 : SET_STRING(msg,
4184 : info32.info.profile_path,
4185 : "profilePath");
4186 : }
4187 72 : IFSET(SAMR_FIELD_DESCRIPTION)
4188 : {
4189 0 : SET_STRING(msg, info32.info.description, "description");
4190 : }
4191 72 : IFSET(SAMR_FIELD_WORKSTATIONS)
4192 : {
4193 0 : SET_STRING(msg,
4194 : info32.info.workstations,
4195 : "userWorkstations");
4196 : }
4197 72 : IFSET(SAMR_FIELD_COMMENT)
4198 : {
4199 0 : SET_STRING(msg, info32.info.comment, "comment");
4200 : }
4201 72 : IFSET(SAMR_FIELD_PARAMETERS)
4202 : {
4203 0 : SET_PARAMETERS(msg,
4204 : info32.info.parameters,
4205 : "userParameters");
4206 : }
4207 72 : IFSET(SAMR_FIELD_PRIMARY_GID)
4208 : {
4209 0 : SET_UINT(msg,
4210 : info32.info.primary_gid,
4211 : "primaryGroupID");
4212 : }
4213 72 : IFSET(SAMR_FIELD_ACCT_FLAGS)
4214 : {
4215 0 : SET_AFLAGS(msg,
4216 : info32.info.acct_flags,
4217 : "userAccountControl");
4218 : }
4219 72 : IFSET(SAMR_FIELD_LOGON_HOURS)
4220 : {
4221 0 : SET_LHOURS(msg, info32.info.logon_hours, "logonHours");
4222 : }
4223 72 : IFSET(SAMR_FIELD_BAD_PWD_COUNT)
4224 : {
4225 0 : SET_UINT(msg,
4226 : info32.info.bad_password_count,
4227 : "badPwdCount");
4228 : }
4229 72 : IFSET(SAMR_FIELD_NUM_LOGONS)
4230 : {
4231 0 : SET_UINT(msg, info32.info.logon_count, "logonCount");
4232 : }
4233 72 : IFSET(SAMR_FIELD_COUNTRY_CODE)
4234 : {
4235 0 : SET_UINT(msg, info32.info.country_code, "countryCode");
4236 : }
4237 72 : IFSET(SAMR_FIELD_CODE_PAGE)
4238 : {
4239 0 : SET_UINT(msg, info32.info.code_page, "codePage");
4240 : }
4241 :
4242 : /* password change fields */
4243 72 : IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
4244 : {
4245 0 : status = NT_STATUS_ACCESS_DENIED;
4246 0 : goto done;
4247 : }
4248 :
4249 72 : IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT)
4250 : {
4251 48 : status = samr_set_password_aes(
4252 : dce_call,
4253 : mem_ctx,
4254 : &session_key,
4255 48 : a_state->sam_ctx,
4256 : a_state->account_dn,
4257 48 : a_state->domain_state->domain_dn,
4258 48 : &r->in.info->info32.password,
4259 : DSDB_PASSWORD_RESET);
4260 : }
4261 24 : else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT)
4262 : {
4263 24 : status = samr_set_password_aes(
4264 : dce_call,
4265 : mem_ctx,
4266 : &session_key,
4267 24 : a_state->sam_ctx,
4268 : a_state->account_dn,
4269 24 : a_state->domain_state->domain_dn,
4270 24 : &r->in.info->info32.password,
4271 : DSDB_PASSWORD_RESET);
4272 : }
4273 72 : if (!NT_STATUS_IS_OK(status)) {
4274 36 : goto done;
4275 : }
4276 :
4277 36 : IFSET(SAMR_FIELD_EXPIRED_FLAG)
4278 : {
4279 0 : const char *t = "0";
4280 0 : struct ldb_message_element *set_el;
4281 0 : if (r->in.info->info32.info.password_expired ==
4282 : PASS_DONT_CHANGE_AT_NEXT_LOGON) {
4283 0 : t = "-1";
4284 : }
4285 0 : if (ldb_msg_add_string(msg, "pwdLastSet", t) !=
4286 : LDB_SUCCESS) {
4287 0 : status = NT_STATUS_NO_MEMORY;
4288 0 : goto done;
4289 : }
4290 0 : set_el = ldb_msg_find_element(msg, "pwdLastSet");
4291 0 : set_el->flags = LDB_FLAG_MOD_REPLACE;
4292 : }
4293 : #undef IFSET
4294 :
4295 36 : break;
4296 0 : default:
4297 : /* many info classes are not valid for SetUserInfo */
4298 0 : status = NT_STATUS_INVALID_INFO_CLASS;
4299 0 : goto done;
4300 : }
4301 :
4302 3994 : if (!NT_STATUS_IS_OK(status)) {
4303 0 : goto done;
4304 : }
4305 :
4306 : /* modify the samdb record */
4307 3994 : if (msg->num_elements > 0) {
4308 3351 : ret = ldb_modify(sam_ctx, msg);
4309 3351 : if (ret != LDB_SUCCESS) {
4310 0 : DEBUG(1,("Failed to modify record %s: %s\n",
4311 : ldb_dn_get_linearized(a_state->account_dn),
4312 : ldb_errstring(sam_ctx)));
4313 :
4314 0 : status = dsdb_ldb_err_to_ntstatus(ret);
4315 0 : goto done;
4316 : }
4317 : }
4318 :
4319 3994 : ret = ldb_transaction_commit(sam_ctx);
4320 3994 : if (ret != LDB_SUCCESS) {
4321 0 : DBG_ERR("Failed to commit transaction modifying account record "
4322 : "%s: %s\n",
4323 : ldb_dn_get_linearized(msg->dn),
4324 : ldb_errstring(sam_ctx));
4325 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
4326 : }
4327 :
4328 3850 : status = NT_STATUS_OK;
4329 4223 : done:
4330 4223 : if (!NT_STATUS_IS_OK(status)) {
4331 229 : ldb_transaction_cancel(sam_ctx);
4332 : }
4333 :
4334 4223 : return status;
4335 : }
4336 :
4337 :
4338 : /*
4339 : samr_GetGroupsForUser
4340 : */
4341 210 : static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4342 : struct samr_GetGroupsForUser *r)
4343 : {
4344 0 : struct dcesrv_handle *h;
4345 0 : struct samr_account_state *a_state;
4346 0 : struct samr_domain_state *d_state;
4347 0 : struct ldb_result *res, *res_memberof;
4348 210 : const char * const attrs[] = { "primaryGroupID",
4349 : "memberOf",
4350 : NULL };
4351 210 : const char * const group_attrs[] = { "objectSid",
4352 : NULL };
4353 :
4354 0 : struct samr_RidWithAttributeArray *array;
4355 0 : struct ldb_message_element *memberof_el;
4356 210 : int i, ret, count = 0;
4357 0 : uint32_t primary_group_id;
4358 0 : char *filter;
4359 :
4360 210 : DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
4361 :
4362 210 : a_state = h->data;
4363 210 : d_state = a_state->domain_state;
4364 :
4365 210 : ret = dsdb_search_dn(a_state->sam_ctx, mem_ctx,
4366 : &res,
4367 : a_state->account_dn,
4368 : attrs, DSDB_SEARCH_SHOW_EXTENDED_DN);
4369 :
4370 210 : if (ret == LDB_ERR_NO_SUCH_OBJECT) {
4371 0 : return NT_STATUS_NO_SUCH_USER;
4372 210 : } else if (ret != LDB_SUCCESS) {
4373 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
4374 210 : } else if (res->count != 1) {
4375 0 : return NT_STATUS_NO_SUCH_USER;
4376 : }
4377 :
4378 210 : primary_group_id = ldb_msg_find_attr_as_uint(res->msgs[0], "primaryGroupID",
4379 : 0);
4380 :
4381 210 : filter = talloc_asprintf(mem_ctx,
4382 : "(&(|(grouptype=%d)(grouptype=%d))"
4383 : "(objectclass=group)(|",
4384 : GTYPE_SECURITY_UNIVERSAL_GROUP,
4385 : GTYPE_SECURITY_GLOBAL_GROUP);
4386 210 : if (filter == NULL) {
4387 0 : return NT_STATUS_NO_MEMORY;
4388 : }
4389 :
4390 210 : memberof_el = ldb_msg_find_element(res->msgs[0], "memberOf");
4391 210 : if (memberof_el != NULL) {
4392 226 : for (i = 0; i < memberof_el->num_values; i++) {
4393 0 : const struct ldb_val *memberof_sid_binary;
4394 0 : char *memberof_sid_escaped;
4395 0 : struct ldb_dn *memberof_dn
4396 146 : = ldb_dn_from_ldb_val(mem_ctx,
4397 146 : a_state->sam_ctx,
4398 146 : &memberof_el->values[i]);
4399 146 : if (memberof_dn == NULL) {
4400 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
4401 : }
4402 :
4403 0 : memberof_sid_binary
4404 146 : = ldb_dn_get_extended_component(memberof_dn,
4405 : "SID");
4406 146 : if (memberof_sid_binary == NULL) {
4407 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
4408 : }
4409 :
4410 146 : memberof_sid_escaped = ldb_binary_encode(mem_ctx,
4411 : *memberof_sid_binary);
4412 146 : if (memberof_sid_escaped == NULL) {
4413 0 : return NT_STATUS_NO_MEMORY;
4414 : }
4415 146 : filter = talloc_asprintf_append(filter, "(objectSID=%s)",
4416 : memberof_sid_escaped);
4417 146 : if (filter == NULL) {
4418 0 : return NT_STATUS_NO_MEMORY;
4419 : }
4420 : }
4421 :
4422 80 : ret = dsdb_search(a_state->sam_ctx, mem_ctx,
4423 : &res_memberof,
4424 : d_state->domain_dn,
4425 : LDB_SCOPE_SUBTREE,
4426 : group_attrs, 0,
4427 : "%s))", filter);
4428 :
4429 80 : if (ret != LDB_SUCCESS) {
4430 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
4431 : }
4432 80 : count = res_memberof->count;
4433 : }
4434 :
4435 210 : array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
4436 210 : if (array == NULL)
4437 0 : return NT_STATUS_NO_MEMORY;
4438 :
4439 210 : array->count = 0;
4440 210 : array->rids = NULL;
4441 :
4442 210 : array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
4443 : count + 1);
4444 210 : if (array->rids == NULL)
4445 0 : return NT_STATUS_NO_MEMORY;
4446 :
4447 : /* Adds the primary group */
4448 :
4449 210 : array->rids[0].rid = primary_group_id;
4450 210 : array->rids[0].attributes = SE_GROUP_DEFAULT_FLAGS;
4451 210 : array->count += 1;
4452 :
4453 : /* Adds the additional groups */
4454 292 : for (i = 0; i < count; i++) {
4455 0 : struct dom_sid *group_sid;
4456 :
4457 82 : group_sid = samdb_result_dom_sid(mem_ctx,
4458 82 : res_memberof->msgs[i],
4459 : "objectSid");
4460 82 : if (group_sid == NULL) {
4461 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
4462 : }
4463 :
4464 82 : array->rids[i + 1].rid =
4465 82 : group_sid->sub_auths[group_sid->num_auths-1];
4466 82 : array->rids[i + 1].attributes = SE_GROUP_DEFAULT_FLAGS;
4467 82 : array->count += 1;
4468 : }
4469 :
4470 210 : *r->out.rids = array;
4471 :
4472 210 : return NT_STATUS_OK;
4473 : }
4474 :
4475 : /*
4476 : * samr_QueryDisplayInfo
4477 : *
4478 : * A cache of the GUID's matching the last query is maintained
4479 : * in the SAMR_QUERY_DISPLAY_INFO_CACHE guid_cache maintained o
4480 : * n the dcesrv_handle.
4481 : */
4482 371 : static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4483 : struct samr_QueryDisplayInfo *r)
4484 : {
4485 0 : struct dcesrv_handle *h;
4486 0 : struct samr_domain_state *d_state;
4487 0 : struct ldb_result *res;
4488 0 : uint32_t i;
4489 371 : uint32_t results = 0;
4490 371 : uint32_t count = 0;
4491 371 : const char *const cache_attrs[] = {"objectGUID", NULL};
4492 371 : const char *const attrs[] = {
4493 : "objectSID", "sAMAccountName", "displayName", "description", NULL};
4494 371 : struct samr_DispEntryFull *entriesFull = NULL;
4495 371 : struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
4496 371 : struct samr_DispEntryAscii *entriesAscii = NULL;
4497 371 : struct samr_DispEntryGeneral *entriesGeneral = NULL;
4498 0 : const char *filter;
4499 0 : int ret;
4500 0 : NTSTATUS status;
4501 371 : struct samr_guid_cache *cache = NULL;
4502 :
4503 371 : DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4504 :
4505 371 : d_state = h->data;
4506 :
4507 371 : cache = &d_state->guid_caches[SAMR_QUERY_DISPLAY_INFO_CACHE];
4508 : /*
4509 : * Can the cached results be used?
4510 : * The cache is discarded if the start index is zero, or the requested
4511 : * level is different from that in the cache.
4512 : */
4513 371 : if ((r->in.start_idx == 0) || (r->in.level != cache->handle)) {
4514 : /*
4515 : * The cached results can not be used, so will need to query
4516 : * the database.
4517 : */
4518 :
4519 : /*
4520 : * Get the search filter for the current level
4521 : */
4522 141 : switch (r->in.level) {
4523 59 : case 1:
4524 : case 4:
4525 59 : filter = talloc_asprintf(mem_ctx,
4526 : "(&(objectclass=user)"
4527 : "(sAMAccountType=%d))",
4528 : ATYPE_NORMAL_ACCOUNT);
4529 59 : break;
4530 22 : case 2:
4531 22 : filter = talloc_asprintf(mem_ctx,
4532 : "(&(objectclass=user)"
4533 : "(sAMAccountType=%d))",
4534 : ATYPE_WORKSTATION_TRUST);
4535 22 : break;
4536 60 : case 3:
4537 : case 5:
4538 0 : filter =
4539 60 : talloc_asprintf(mem_ctx,
4540 : "(&(|(groupType=%d)(groupType=%d))"
4541 : "(objectClass=group))",
4542 : GTYPE_SECURITY_UNIVERSAL_GROUP,
4543 : GTYPE_SECURITY_GLOBAL_GROUP);
4544 60 : break;
4545 0 : default:
4546 0 : return NT_STATUS_INVALID_INFO_CLASS;
4547 : }
4548 141 : clear_guid_cache(cache);
4549 :
4550 : /*
4551 : * search for all requested objects in all domains.
4552 : */
4553 141 : ret = dsdb_search(d_state->sam_ctx,
4554 : mem_ctx,
4555 : &res,
4556 141 : ldb_get_default_basedn(d_state->sam_ctx),
4557 : LDB_SCOPE_SUBTREE,
4558 : cache_attrs,
4559 : 0,
4560 : "%s",
4561 : filter);
4562 141 : if (ret != LDB_SUCCESS) {
4563 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
4564 : }
4565 141 : if ((res->count == 0) || (r->in.max_entries == 0)) {
4566 0 : return NT_STATUS_OK;
4567 : }
4568 :
4569 141 : status = load_guid_cache(cache, d_state, res->count, res->msgs);
4570 141 : TALLOC_FREE(res);
4571 141 : if (!NT_STATUS_IS_OK(status)) {
4572 0 : return status;
4573 : }
4574 141 : cache->handle = r->in.level;
4575 : }
4576 371 : *r->out.total_size = cache->size;
4577 :
4578 : /*
4579 : * if there are no entries or the requested start index is greater
4580 : * than the number of entries, we return an empty response.
4581 : */
4582 371 : if (r->in.start_idx >= cache->size) {
4583 11 : *r->out.returned_size = 0;
4584 11 : switch(r->in.level) {
4585 7 : case 1:
4586 7 : r->out.info->info1.count = *r->out.returned_size;
4587 7 : r->out.info->info1.entries = NULL;
4588 7 : break;
4589 1 : case 2:
4590 1 : r->out.info->info2.count = *r->out.returned_size;
4591 1 : r->out.info->info2.entries = NULL;
4592 1 : break;
4593 1 : case 3:
4594 1 : r->out.info->info3.count = *r->out.returned_size;
4595 1 : r->out.info->info3.entries = NULL;
4596 1 : break;
4597 1 : case 4:
4598 1 : r->out.info->info4.count = *r->out.returned_size;
4599 1 : r->out.info->info4.entries = NULL;
4600 1 : break;
4601 1 : case 5:
4602 1 : r->out.info->info5.count = *r->out.returned_size;
4603 1 : r->out.info->info5.entries = NULL;
4604 1 : break;
4605 : }
4606 11 : return NT_STATUS_OK;
4607 : }
4608 :
4609 : /*
4610 : * Allocate an array of the appropriate result structures for the
4611 : * current query level.
4612 : *
4613 : * r->in.start_idx is always < cache->size due to the check above
4614 : */
4615 360 : results = MIN((cache->size - r->in.start_idx), r->in.max_entries);
4616 360 : switch (r->in.level) {
4617 134 : case 1:
4618 134 : entriesGeneral = talloc_array(
4619 : mem_ctx, struct samr_DispEntryGeneral, results);
4620 134 : break;
4621 26 : case 2:
4622 0 : entriesFull =
4623 26 : talloc_array(mem_ctx, struct samr_DispEntryFull, results);
4624 26 : break;
4625 68 : case 3:
4626 68 : entriesFullGroup = talloc_array(
4627 : mem_ctx, struct samr_DispEntryFullGroup, results);
4628 68 : break;
4629 132 : case 4:
4630 : case 5:
4631 0 : entriesAscii =
4632 132 : talloc_array(mem_ctx, struct samr_DispEntryAscii, results);
4633 132 : break;
4634 : }
4635 :
4636 360 : if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
4637 68 : (entriesAscii == NULL) && (entriesFullGroup == NULL))
4638 0 : return NT_STATUS_NO_MEMORY;
4639 :
4640 : /*
4641 : * Process the list of result GUID's.
4642 : * Read the details of each object and populate the result structure
4643 : * for the current level.
4644 : */
4645 360 : count = 0;
4646 2968 : for (i = 0; i < results; i++) {
4647 0 : struct dom_sid *objectsid;
4648 0 : struct ldb_result *rec;
4649 2608 : const uint32_t idx = r->in.start_idx + i;
4650 0 : uint32_t rid;
4651 :
4652 : /*
4653 : * Read an object from disk using the GUID as the key
4654 : *
4655 : * If the object can not be read, or it does not have a SID
4656 : * it is ignored. In this case the number of entries returned
4657 : * will be less than the requested size, there will also be
4658 : * a gap in the idx numbers in the returned elements e.g. if
4659 : * there are 3 GUIDs a, b, c in the cache and b is deleted from
4660 : * disk then details for a, and c will be returned with
4661 : * idx values of 1 and 3 respectively.
4662 : *
4663 : */
4664 2608 : ret = dsdb_search_by_dn_guid(d_state->sam_ctx,
4665 : mem_ctx,
4666 : &rec,
4667 2608 : &cache->entries[idx],
4668 : attrs,
4669 : 0);
4670 2608 : if (ret == LDB_ERR_NO_SUCH_OBJECT) {
4671 0 : struct GUID_txt_buf guid_buf;
4672 0 : char *guid_str =
4673 20 : GUID_buf_string(&cache->entries[idx],
4674 : &guid_buf);
4675 20 : DBG_WARNING("GUID [%s] not found\n", guid_str);
4676 20 : continue;
4677 2588 : } else if (ret != LDB_SUCCESS) {
4678 0 : clear_guid_cache(cache);
4679 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
4680 : }
4681 2588 : objectsid = samdb_result_dom_sid(mem_ctx,
4682 2588 : rec->msgs[0],
4683 : "objectSID");
4684 2588 : if (objectsid == NULL) {
4685 0 : struct GUID_txt_buf guid_buf;
4686 0 : DBG_WARNING(
4687 : "objectSID for GUID [%s] not found\n",
4688 : GUID_buf_string(&cache->entries[idx], &guid_buf));
4689 0 : continue;
4690 : }
4691 2588 : status = dom_sid_split_rid(NULL,
4692 : objectsid,
4693 : NULL,
4694 : &rid);
4695 2588 : if (!NT_STATUS_IS_OK(status)) {
4696 0 : struct dom_sid_buf sid_buf;
4697 0 : struct GUID_txt_buf guid_buf;
4698 0 : DBG_WARNING(
4699 : "objectSID [%s] for GUID [%s] invalid\n",
4700 : dom_sid_str_buf(objectsid, &sid_buf),
4701 : GUID_buf_string(&cache->entries[idx], &guid_buf));
4702 0 : continue;
4703 : }
4704 :
4705 : /*
4706 : * Populate the result structure for the current object
4707 : */
4708 2588 : switch(r->in.level) {
4709 939 : case 1:
4710 :
4711 939 : entriesGeneral[count].idx = idx + 1;
4712 939 : entriesGeneral[count].rid = rid;
4713 :
4714 1878 : entriesGeneral[count].acct_flags =
4715 939 : samdb_result_acct_flags(rec->msgs[0], NULL);
4716 1878 : entriesGeneral[count].account_name.string =
4717 939 : ldb_msg_find_attr_as_string(
4718 939 : rec->msgs[0], "sAMAccountName", "");
4719 1878 : entriesGeneral[count].full_name.string =
4720 939 : ldb_msg_find_attr_as_string(
4721 939 : rec->msgs[0], "displayName", "");
4722 1878 : entriesGeneral[count].description.string =
4723 939 : ldb_msg_find_attr_as_string(
4724 939 : rec->msgs[0], "description", "");
4725 939 : break;
4726 51 : case 2:
4727 51 : entriesFull[count].idx = idx + 1;
4728 51 : entriesFull[count].rid = rid;
4729 :
4730 : /*
4731 : * No idea why we need to or in ACB_NORMAL here,
4732 : * but this is what Win2k3 seems to do...
4733 : */
4734 51 : entriesFull[count].acct_flags =
4735 51 : samdb_result_acct_flags(rec->msgs[0], NULL) |
4736 : ACB_NORMAL;
4737 102 : entriesFull[count].account_name.string =
4738 51 : ldb_msg_find_attr_as_string(
4739 51 : rec->msgs[0], "sAMAccountName", "");
4740 102 : entriesFull[count].description.string =
4741 51 : ldb_msg_find_attr_as_string(
4742 51 : rec->msgs[0], "description", "");
4743 51 : break;
4744 905 : case 3:
4745 905 : entriesFullGroup[count].idx = idx + 1;
4746 905 : entriesFullGroup[count].rid = rid;
4747 :
4748 : /*
4749 : * We get a "7" here for groups
4750 : */
4751 905 : entriesFullGroup[count].acct_flags = SE_GROUP_DEFAULT_FLAGS;
4752 1810 : entriesFullGroup[count].account_name.string =
4753 905 : ldb_msg_find_attr_as_string(
4754 905 : rec->msgs[0], "sAMAccountName", "");
4755 1810 : entriesFullGroup[count].description.string =
4756 905 : ldb_msg_find_attr_as_string(
4757 905 : rec->msgs[0], "description", "");
4758 905 : break;
4759 693 : case 4:
4760 : case 5:
4761 693 : entriesAscii[count].idx = idx + 1;
4762 1386 : entriesAscii[count].account_name.string =
4763 693 : ldb_msg_find_attr_as_string(
4764 693 : rec->msgs[0], "sAMAccountName", "");
4765 693 : break;
4766 : }
4767 2588 : count++;
4768 : }
4769 :
4770 : /*
4771 : * Build the response based on the request level.
4772 : */
4773 360 : *r->out.returned_size = count;
4774 360 : switch(r->in.level) {
4775 134 : case 1:
4776 134 : r->out.info->info1.count = count;
4777 134 : r->out.info->info1.entries = entriesGeneral;
4778 134 : break;
4779 26 : case 2:
4780 26 : r->out.info->info2.count = count;
4781 26 : r->out.info->info2.entries = entriesFull;
4782 26 : break;
4783 68 : case 3:
4784 68 : r->out.info->info3.count = count;
4785 68 : r->out.info->info3.entries = entriesFullGroup;
4786 68 : break;
4787 56 : case 4:
4788 56 : r->out.info->info4.count = count;
4789 56 : r->out.info->info4.entries = entriesAscii;
4790 56 : break;
4791 76 : case 5:
4792 76 : r->out.info->info5.count = count;
4793 76 : r->out.info->info5.entries = entriesAscii;
4794 76 : break;
4795 : }
4796 :
4797 360 : return ((r->in.start_idx + results) < cache->size)
4798 : ? STATUS_MORE_ENTRIES
4799 360 : : NT_STATUS_OK;
4800 : }
4801 :
4802 :
4803 : /*
4804 : samr_GetDisplayEnumerationIndex
4805 : */
4806 0 : static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4807 : struct samr_GetDisplayEnumerationIndex *r)
4808 : {
4809 0 : DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4810 : }
4811 :
4812 :
4813 : /*
4814 : samr_TestPrivateFunctionsDomain
4815 : */
4816 6 : static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4817 : struct samr_TestPrivateFunctionsDomain *r)
4818 : {
4819 6 : return NT_STATUS_NOT_IMPLEMENTED;
4820 : }
4821 :
4822 :
4823 : /*
4824 : samr_TestPrivateFunctionsUser
4825 : */
4826 12 : static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4827 : struct samr_TestPrivateFunctionsUser *r)
4828 : {
4829 12 : return NT_STATUS_NOT_IMPLEMENTED;
4830 : }
4831 :
4832 :
4833 : /*
4834 : samr_GetUserPwInfo
4835 : */
4836 1235 : static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4837 : struct samr_GetUserPwInfo *r)
4838 : {
4839 72 : struct dcesrv_handle *h;
4840 72 : struct samr_account_state *a_state;
4841 :
4842 1235 : ZERO_STRUCTP(r->out.info);
4843 :
4844 1235 : DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
4845 :
4846 1235 : a_state = h->data;
4847 :
4848 2470 : r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
4849 1235 : mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
4850 : NULL);
4851 1235 : r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
4852 : mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
4853 :
4854 1235 : return NT_STATUS_OK;
4855 : }
4856 :
4857 :
4858 : /*
4859 : samr_RemoveMemberFromForeignDomain
4860 : */
4861 10 : static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call,
4862 : TALLOC_CTX *mem_ctx,
4863 : struct samr_RemoveMemberFromForeignDomain *r)
4864 : {
4865 0 : struct dcesrv_handle *h;
4866 0 : struct samr_domain_state *d_state;
4867 0 : const char *memberdn;
4868 0 : struct ldb_message **res;
4869 10 : const char *no_attrs[] = { NULL };
4870 0 : int i, count;
4871 :
4872 10 : DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4873 :
4874 10 : d_state = h->data;
4875 :
4876 10 : memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
4877 : "distinguishedName", "(objectSid=%s)",
4878 10 : ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
4879 : /* Nothing to do */
4880 10 : if (memberdn == NULL) {
4881 6 : return NT_STATUS_OK;
4882 : }
4883 :
4884 4 : count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
4885 : d_state->domain_dn, &res, no_attrs,
4886 4 : d_state->domain_sid,
4887 : "(&(member=%s)(objectClass=group)"
4888 : "(|(groupType=%d)(groupType=%d)))",
4889 : memberdn,
4890 : GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
4891 : GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
4892 :
4893 4 : if (count < 0)
4894 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
4895 :
4896 4 : for (i=0; i<count; i++) {
4897 0 : struct ldb_message *mod;
4898 0 : int ret;
4899 :
4900 0 : mod = ldb_msg_new(mem_ctx);
4901 0 : if (mod == NULL) {
4902 0 : return NT_STATUS_NO_MEMORY;
4903 : }
4904 :
4905 0 : mod->dn = res[i]->dn;
4906 :
4907 0 : if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
4908 : "member", memberdn) != LDB_SUCCESS)
4909 0 : return NT_STATUS_NO_MEMORY;
4910 :
4911 0 : ret = ldb_modify(d_state->sam_ctx, mod);
4912 0 : talloc_free(mod);
4913 0 : if (ret != LDB_SUCCESS) {
4914 0 : return dsdb_ldb_err_to_ntstatus(ret);
4915 : }
4916 : }
4917 :
4918 4 : return NT_STATUS_OK;
4919 : }
4920 :
4921 :
4922 : /*
4923 : samr_QueryDomainInfo2
4924 :
4925 : just an alias for samr_QueryDomainInfo
4926 : */
4927 107 : static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4928 : struct samr_QueryDomainInfo2 *r)
4929 : {
4930 0 : struct samr_QueryDomainInfo r1;
4931 0 : NTSTATUS status;
4932 :
4933 107 : r1 = (struct samr_QueryDomainInfo) {
4934 107 : .in.domain_handle = r->in.domain_handle,
4935 107 : .in.level = r->in.level,
4936 107 : .out.info = r->out.info,
4937 : };
4938 :
4939 107 : status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
4940 :
4941 107 : return status;
4942 : }
4943 :
4944 :
4945 : /*
4946 : samr_QueryUserInfo2
4947 :
4948 : just an alias for samr_QueryUserInfo
4949 : */
4950 928 : static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4951 : struct samr_QueryUserInfo2 *r)
4952 : {
4953 0 : struct samr_QueryUserInfo r1;
4954 0 : NTSTATUS status;
4955 :
4956 928 : r1 = (struct samr_QueryUserInfo) {
4957 928 : .in.user_handle = r->in.user_handle,
4958 928 : .in.level = r->in.level,
4959 928 : .out.info = r->out.info
4960 : };
4961 :
4962 928 : status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
4963 :
4964 928 : return status;
4965 : }
4966 :
4967 :
4968 : /*
4969 : samr_QueryDisplayInfo2
4970 : */
4971 34 : static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4972 : struct samr_QueryDisplayInfo2 *r)
4973 : {
4974 0 : struct samr_QueryDisplayInfo q;
4975 0 : NTSTATUS result;
4976 :
4977 34 : q = (struct samr_QueryDisplayInfo) {
4978 34 : .in.domain_handle = r->in.domain_handle,
4979 34 : .in.level = r->in.level,
4980 34 : .in.start_idx = r->in.start_idx,
4981 34 : .in.max_entries = r->in.max_entries,
4982 34 : .in.buf_size = r->in.buf_size,
4983 34 : .out.total_size = r->out.total_size,
4984 34 : .out.returned_size = r->out.returned_size,
4985 34 : .out.info = r->out.info,
4986 : };
4987 :
4988 34 : result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4989 :
4990 34 : return result;
4991 : }
4992 :
4993 :
4994 : /*
4995 : samr_GetDisplayEnumerationIndex2
4996 : */
4997 0 : static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4998 : struct samr_GetDisplayEnumerationIndex2 *r)
4999 : {
5000 0 : DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
5001 : }
5002 :
5003 :
5004 : /*
5005 : samr_QueryDisplayInfo3
5006 : */
5007 30 : static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5008 : struct samr_QueryDisplayInfo3 *r)
5009 : {
5010 0 : struct samr_QueryDisplayInfo q;
5011 0 : NTSTATUS result;
5012 :
5013 30 : q = (struct samr_QueryDisplayInfo) {
5014 30 : .in.domain_handle = r->in.domain_handle,
5015 30 : .in.level = r->in.level,
5016 30 : .in.start_idx = r->in.start_idx,
5017 30 : .in.max_entries = r->in.max_entries,
5018 30 : .in.buf_size = r->in.buf_size,
5019 30 : .out.total_size = r->out.total_size,
5020 30 : .out.returned_size = r->out.returned_size,
5021 30 : .out.info = r->out.info,
5022 : };
5023 :
5024 30 : result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
5025 :
5026 30 : return result;
5027 : }
5028 :
5029 :
5030 : /*
5031 : samr_AddMultipleMembersToAlias
5032 : */
5033 0 : static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5034 : struct samr_AddMultipleMembersToAlias *r)
5035 : {
5036 0 : DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
5037 : }
5038 :
5039 :
5040 : /*
5041 : samr_RemoveMultipleMembersFromAlias
5042 : */
5043 0 : static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5044 : struct samr_RemoveMultipleMembersFromAlias *r)
5045 : {
5046 0 : DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
5047 : }
5048 :
5049 :
5050 : /*
5051 : samr_GetDomPwInfo
5052 :
5053 : this fetches the default password properties for a domain
5054 :
5055 : note that w2k3 completely ignores the domain name in this call, and
5056 : always returns the information for the servers primary domain
5057 : */
5058 2867 : static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5059 : struct samr_GetDomPwInfo *r)
5060 : {
5061 480 : struct ldb_message **msgs;
5062 480 : int ret;
5063 2867 : const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
5064 480 : struct ldb_context *sam_ctx;
5065 :
5066 2867 : ZERO_STRUCTP(r->out.info);
5067 :
5068 2867 : sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
5069 2867 : if (sam_ctx == NULL) {
5070 0 : return NT_STATUS_INVALID_SYSTEM_SERVICE;
5071 : }
5072 :
5073 : /* The domain name in this call is ignored */
5074 2867 : ret = gendb_search_dn(sam_ctx,
5075 : mem_ctx, NULL, &msgs, attrs);
5076 2867 : if (ret <= 0) {
5077 0 : talloc_free(sam_ctx);
5078 :
5079 0 : return NT_STATUS_NO_SUCH_DOMAIN;
5080 : }
5081 2867 : if (ret > 1) {
5082 0 : talloc_free(msgs);
5083 0 : talloc_free(sam_ctx);
5084 :
5085 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
5086 : }
5087 :
5088 2867 : r->out.info->min_password_length = ldb_msg_find_attr_as_uint(msgs[0],
5089 : "minPwdLength", 0);
5090 2867 : r->out.info->password_properties = ldb_msg_find_attr_as_uint(msgs[0],
5091 : "pwdProperties", 1);
5092 :
5093 2867 : talloc_free(msgs);
5094 2867 : talloc_unlink(mem_ctx, sam_ctx);
5095 :
5096 2867 : return NT_STATUS_OK;
5097 : }
5098 :
5099 :
5100 : /*
5101 : samr_Connect2
5102 : */
5103 1017 : static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5104 : struct samr_Connect2 *r)
5105 : {
5106 4 : struct samr_Connect c;
5107 :
5108 1017 : c = (struct samr_Connect) {
5109 : .in.system_name = NULL,
5110 1017 : .in.access_mask = r->in.access_mask,
5111 1017 : .out.connect_handle = r->out.connect_handle,
5112 : };
5113 :
5114 1017 : return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
5115 : }
5116 :
5117 :
5118 : /*
5119 : samr_SetUserInfo2
5120 :
5121 : just an alias for samr_SetUserInfo
5122 : */
5123 1688 : static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5124 : struct samr_SetUserInfo2 *r)
5125 : {
5126 72 : struct samr_SetUserInfo r2;
5127 :
5128 1688 : r2 = (struct samr_SetUserInfo) {
5129 1688 : .in.user_handle = r->in.user_handle,
5130 1688 : .in.level = r->in.level,
5131 1688 : .in.info = r->in.info,
5132 : };
5133 :
5134 1688 : return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
5135 : }
5136 :
5137 :
5138 : /*
5139 : samr_SetBootKeyInformation
5140 : */
5141 0 : static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5142 : struct samr_SetBootKeyInformation *r)
5143 : {
5144 0 : DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
5145 : }
5146 :
5147 :
5148 : /*
5149 : samr_GetBootKeyInformation
5150 : */
5151 6 : static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5152 : struct samr_GetBootKeyInformation *r)
5153 : {
5154 : /* Windows Server 2008 returns this */
5155 6 : return NT_STATUS_NOT_SUPPORTED;
5156 : }
5157 :
5158 :
5159 : /*
5160 : samr_Connect3
5161 : */
5162 66 : static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5163 : struct samr_Connect3 *r)
5164 : {
5165 0 : struct samr_Connect c;
5166 :
5167 66 : c = (struct samr_Connect) {
5168 : .in.system_name = NULL,
5169 66 : .in.access_mask = r->in.access_mask,
5170 66 : .out.connect_handle = r->out.connect_handle,
5171 : };
5172 :
5173 66 : return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
5174 : }
5175 :
5176 :
5177 : /*
5178 : samr_Connect4
5179 : */
5180 66 : static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5181 : struct samr_Connect4 *r)
5182 : {
5183 0 : struct samr_Connect c;
5184 :
5185 66 : c = (struct samr_Connect) {
5186 : .in.system_name = NULL,
5187 66 : .in.access_mask = r->in.access_mask,
5188 66 : .out.connect_handle = r->out.connect_handle,
5189 : };
5190 :
5191 66 : return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
5192 : }
5193 :
5194 :
5195 : /*
5196 : samr_Connect5
5197 : */
5198 154 : static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5199 : struct samr_Connect5 *r)
5200 : {
5201 0 : struct samr_Connect c;
5202 0 : NTSTATUS status;
5203 :
5204 154 : c = (struct samr_Connect) {
5205 : .in.system_name = NULL,
5206 154 : .in.access_mask = r->in.access_mask,
5207 154 : .out.connect_handle = r->out.connect_handle,
5208 : };
5209 :
5210 154 : status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
5211 :
5212 154 : r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
5213 154 : r->out.info_out->info1.supported_features = 0;
5214 154 : *r->out.level_out = r->in.level_in;
5215 :
5216 154 : return status;
5217 : }
5218 :
5219 :
5220 : /*
5221 : samr_RidToSid
5222 : */
5223 24 : static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5224 : struct samr_RidToSid *r)
5225 : {
5226 0 : struct samr_domain_state *d_state;
5227 0 : struct dcesrv_handle *h;
5228 :
5229 24 : DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
5230 :
5231 24 : d_state = h->data;
5232 :
5233 : /* form the users SID */
5234 24 : *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
5235 24 : if (!*r->out.sid) {
5236 0 : return NT_STATUS_NO_MEMORY;
5237 : }
5238 :
5239 24 : return NT_STATUS_OK;
5240 : }
5241 :
5242 :
5243 : /*
5244 : samr_SetDsrmPassword
5245 : */
5246 0 : static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5247 : struct samr_SetDsrmPassword *r)
5248 : {
5249 0 : DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
5250 : }
5251 :
5252 :
5253 : /*
5254 : samr_ValidatePassword
5255 :
5256 : For now the call checks the password complexity (if active) and the minimum
5257 : password length on level 2 and 3. Level 1 is ignored for now.
5258 : */
5259 5 : static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
5260 : TALLOC_CTX *mem_ctx,
5261 : struct samr_ValidatePassword *r)
5262 : {
5263 5 : struct samr_GetDomPwInfo r2 = {};
5264 5 : struct samr_PwInfo pwInfo = {};
5265 5 : const char *account = NULL;
5266 0 : DATA_BLOB password;
5267 0 : enum samr_ValidationStatus res;
5268 0 : NTSTATUS status;
5269 0 : enum dcerpc_transport_t transport =
5270 5 : dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description);
5271 5 : enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
5272 :
5273 5 : if (transport != NCACN_IP_TCP && transport != NCALRPC) {
5274 0 : DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
5275 : }
5276 :
5277 5 : dcesrv_call_auth_info(dce_call, NULL, &auth_level);
5278 5 : if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
5279 2 : DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
5280 : }
5281 :
5282 3 : (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
5283 :
5284 3 : r2 = (struct samr_GetDomPwInfo) {
5285 : .in.domain_name = NULL,
5286 : .out.info = &pwInfo,
5287 : };
5288 :
5289 3 : status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
5290 3 : if (!NT_STATUS_IS_OK(status)) {
5291 0 : return status;
5292 : }
5293 :
5294 3 : switch (r->in.level) {
5295 0 : case NetValidateAuthentication:
5296 : /* we don't support this yet */
5297 0 : return NT_STATUS_NOT_SUPPORTED;
5298 0 : break;
5299 0 : case NetValidatePasswordChange:
5300 0 : account = r->in.req->req2.account.string;
5301 0 : password = data_blob_const(r->in.req->req2.password.string,
5302 0 : r->in.req->req2.password.length);
5303 0 : res = samdb_check_password(mem_ctx,
5304 0 : dce_call->conn->dce_ctx->lp_ctx,
5305 : account,
5306 : NULL, /* userPrincipalName */
5307 : NULL, /* displayName/full_name */
5308 : &password,
5309 : pwInfo.password_properties,
5310 0 : pwInfo.min_password_length);
5311 0 : (*r->out.rep)->ctr2.status = res;
5312 0 : break;
5313 3 : case NetValidatePasswordReset:
5314 3 : account = r->in.req->req3.account.string;
5315 3 : password = data_blob_const(r->in.req->req3.password.string,
5316 3 : r->in.req->req3.password.length);
5317 3 : res = samdb_check_password(mem_ctx,
5318 3 : dce_call->conn->dce_ctx->lp_ctx,
5319 : account,
5320 : NULL, /* userPrincipalName */
5321 : NULL, /* displayName/full_name */
5322 : &password,
5323 : pwInfo.password_properties,
5324 3 : pwInfo.min_password_length);
5325 3 : (*r->out.rep)->ctr3.status = res;
5326 3 : break;
5327 0 : default:
5328 0 : return NT_STATUS_INVALID_INFO_CLASS;
5329 : break;
5330 : }
5331 :
5332 3 : return NT_STATUS_OK;
5333 : }
5334 :
5335 0 : static void dcesrv_samr_Opnum68NotUsedOnWire(struct dcesrv_call_state *dce_call,
5336 : TALLOC_CTX *mem_ctx,
5337 : struct samr_Opnum68NotUsedOnWire *r)
5338 : {
5339 0 : DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
5340 : }
5341 :
5342 0 : static void dcesrv_samr_Opnum69NotUsedOnWire(struct dcesrv_call_state *dce_call,
5343 : TALLOC_CTX *mem_ctx,
5344 : struct samr_Opnum69NotUsedOnWire *r)
5345 : {
5346 0 : DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
5347 : }
5348 :
5349 0 : static void dcesrv_samr_Opnum70NotUsedOnWire(struct dcesrv_call_state *dce_call,
5350 : TALLOC_CTX *mem_ctx,
5351 : struct samr_Opnum70NotUsedOnWire *r)
5352 : {
5353 0 : DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
5354 : }
5355 :
5356 0 : static void dcesrv_samr_Opnum71NotUsedOnWire(struct dcesrv_call_state *dce_call,
5357 : TALLOC_CTX *mem_ctx,
5358 : struct samr_Opnum71NotUsedOnWire *r)
5359 : {
5360 0 : DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
5361 : }
5362 :
5363 0 : static void dcesrv_samr_Opnum72NotUsedOnWire(struct dcesrv_call_state *dce_call,
5364 : TALLOC_CTX *mem_ctx,
5365 : struct samr_Opnum72NotUsedOnWire *r)
5366 : {
5367 0 : DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
5368 : }
5369 :
5370 : /* include the generated boilerplate */
5371 : #include "librpc/gen_ndr/ndr_samr_s.c"
|