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 2528 : static NTSTATUS dcesrv_interface_samr_bind(struct dcesrv_connection_context *context,
49 : const struct dcesrv_interface *iface)
50 : {
51 2528 : 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 7167 : static void initialize_guid_cache(struct samr_guid_cache *cache)
164 : {
165 7167 : cache->handle = 0;
166 7167 : cache->size = 0;
167 7167 : cache->entries = NULL;
168 6651 : }
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 2694 : 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 2694 : ZERO_STRUCTP(r->out.connect_handle);
219 :
220 2694 : c_state = talloc(mem_ctx, struct samr_connect_state);
221 2694 : if (!c_state) {
222 0 : return NT_STATUS_NO_MEMORY;
223 : }
224 :
225 : /* make sure the sam database is accessible */
226 2694 : c_state->sam_ctx = dcesrv_samdb_connect_as_user(c_state, dce_call);
227 2694 : if (c_state->sam_ctx == NULL) {
228 0 : talloc_free(c_state);
229 0 : return NT_STATUS_INVALID_SYSTEM_SERVICE;
230 : }
231 :
232 2694 : handle = dcesrv_handle_create(dce_call, SAMR_HANDLE_CONNECT);
233 2694 : if (!handle) {
234 0 : talloc_free(c_state);
235 0 : return NT_STATUS_NO_MEMORY;
236 : }
237 :
238 2694 : handle->data = talloc_steal(handle, c_state);
239 :
240 2694 : c_state->access_mask = r->in.access_mask;
241 2694 : *r->out.connect_handle = handle->wire_handle;
242 :
243 2694 : 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 2395 : 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 2395 : 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 2395 : ZERO_STRUCTP(r->out.domain_handle);
441 :
442 2395 : DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
443 :
444 2389 : c_state = h_conn->data;
445 :
446 2389 : if (r->in.sid == NULL) {
447 0 : return NT_STATUS_INVALID_PARAMETER;
448 : }
449 :
450 2389 : d_state = talloc(mem_ctx, struct samr_domain_state);
451 2389 : if (!d_state) {
452 0 : return NT_STATUS_NO_MEMORY;
453 : }
454 :
455 2389 : d_state->domain_sid = talloc_steal(d_state, r->in.sid);
456 :
457 2389 : if (dom_sid_equal(d_state->domain_sid, &global_sid_Builtin)) {
458 558 : d_state->builtin = true;
459 558 : d_state->domain_name = "BUILTIN";
460 : } else {
461 1831 : d_state->builtin = false;
462 1831 : d_state->domain_name = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx);
463 : }
464 :
465 2389 : 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 2389 : ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
469 :
470 2389 : if (ret == 0) {
471 0 : talloc_free(d_state);
472 0 : return NT_STATUS_NO_SUCH_DOMAIN;
473 2389 : } else if (ret > 1) {
474 0 : talloc_free(d_state);
475 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
476 2389 : } 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 2389 : d_state->domain_dn = talloc_steal(d_state, dom_msgs[0]->dn);
483 2389 : d_state->role = lpcfg_server_role(dce_call->conn->dce_ctx->lp_ctx);
484 2389 : d_state->connect_state = talloc_reference(d_state, c_state);
485 2389 : d_state->sam_ctx = c_state->sam_ctx;
486 2389 : d_state->access_mask = r->in.access_mask;
487 2389 : d_state->domain_users_cached = NULL;
488 :
489 2389 : d_state->lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
490 :
491 9556 : for (i = 0; i < SAMR_LAST_CACHE; i++) {
492 7167 : initialize_guid_cache(&d_state->guid_caches[i]);
493 : }
494 :
495 2389 : h_domain = dcesrv_handle_create(dce_call, SAMR_HANDLE_DOMAIN);
496 2389 : if (!h_domain) {
497 0 : talloc_free(d_state);
498 0 : return NT_STATUS_NO_MEMORY;
499 : }
500 :
501 2389 : h_domain->data = talloc_steal(h_domain, d_state);
502 :
503 2389 : *r->out.domain_handle = h_domain->wire_handle;
504 :
505 2389 : 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 22 : 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 22 : info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
742 22 : time(NULL));
743 :
744 22 : info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
745 : 0x0LL);
746 :
747 22 : 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 34 : 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 34 : info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
795 : -18000000000LL);
796 34 : info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
797 : -18000000000LL);
798 34 : info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
799 :
800 34 : 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 22 : case 8:
896 : {
897 0 : static const char * const attrs2[] = { "modifiedCount",
898 : "creationTime",
899 : NULL };
900 22 : attrs = attrs2;
901 22 : 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 34 : case 12:
921 : {
922 0 : static const char * const attrs2[] = { "lockoutDuration",
923 : "lockOutObservationWindow",
924 : "lockoutThreshold",
925 : NULL};
926 34 : attrs = attrs2;
927 34 : 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 22 : case 8:
987 22 : 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 34 : case 12:
996 34 : 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 31421 : static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1168 : {
1169 31421 : return NUMERIC_CMP(e1->idx, e2->idx);
1170 : }
1171 :
1172 4331 : static int compare_msgRid(struct ldb_message **m1, struct ldb_message **m2) {
1173 4331 : struct dom_sid *sid1 = NULL;
1174 4331 : struct dom_sid *sid2 = NULL;
1175 0 : uint32_t rid1;
1176 0 : uint32_t rid2;
1177 4331 : int res = 0;
1178 0 : NTSTATUS status;
1179 4331 : TALLOC_CTX *frame = talloc_stackframe();
1180 :
1181 4331 : sid1 = samdb_result_dom_sid(frame, *m1, "objectSid");
1182 4331 : 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 4331 : if (sid1 == NULL && sid2 == NULL) {
1189 0 : res = 0;
1190 0 : goto exit;
1191 4331 : } else if (sid2 == NULL) {
1192 0 : res = 1;
1193 0 : goto exit;
1194 4331 : } 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 4331 : status = dom_sid_split_rid(NULL, sid1, NULL, &rid1);
1204 4331 : if (!NT_STATUS_IS_OK(status)) {
1205 0 : res = 1;
1206 0 : goto exit;
1207 : }
1208 :
1209 4331 : status = dom_sid_split_rid(NULL, sid2, NULL, &rid2);
1210 4331 : if (!NT_STATUS_IS_OK(status)) {
1211 0 : res = -1;
1212 0 : goto exit;
1213 : }
1214 :
1215 4331 : if (rid1 == rid2) {
1216 0 : res = 0;
1217 : }
1218 4331 : else if (rid1 > rid2) {
1219 2264 : res = 1;
1220 : }
1221 : else {
1222 2067 : res = -1;
1223 : }
1224 4331 : exit:
1225 4331 : TALLOC_FREE(frame);
1226 4331 : 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 5104 : 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 5104 : NTSTATUS status = NT_STATUS_OK;
2122 5104 : const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
2123 17 : int count;
2124 :
2125 5104 : ZERO_STRUCTP(r->out.rids);
2126 5104 : ZERO_STRUCTP(r->out.types);
2127 :
2128 5104 : DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2129 :
2130 5104 : d_state = h->data;
2131 :
2132 5104 : if (r->in.num_names == 0) {
2133 325 : return NT_STATUS_OK;
2134 : }
2135 :
2136 4779 : r->out.rids->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
2137 4779 : r->out.types->ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
2138 4779 : if (!r->out.rids->ids || !r->out.types->ids) {
2139 0 : return NT_STATUS_NO_MEMORY;
2140 : }
2141 4779 : r->out.rids->count = r->in.num_names;
2142 4779 : r->out.types->count = r->in.num_names;
2143 :
2144 4779 : num_mapped = 0;
2145 :
2146 10238 : 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 5459 : r->out.rids->ids[i] = 0;
2152 5459 : r->out.types->ids[i] = SID_NAME_UNKNOWN;
2153 :
2154 5459 : count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
2155 : "sAMAccountName=%s",
2156 5459 : ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
2157 5459 : if (count != 1) {
2158 3967 : status = STATUS_SOME_UNMAPPED;
2159 3967 : continue;
2160 : }
2161 :
2162 1492 : sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
2163 1492 : if (sid == NULL) {
2164 0 : status = STATUS_SOME_UNMAPPED;
2165 0 : continue;
2166 : }
2167 :
2168 1492 : atype = ldb_msg_find_attr_as_uint(res[0], "sAMAccountType", 0);
2169 1492 : if (atype == 0) {
2170 0 : status = STATUS_SOME_UNMAPPED;
2171 0 : continue;
2172 : }
2173 :
2174 1492 : rtype = ds_atype_map(atype);
2175 :
2176 1492 : if (rtype == SID_NAME_UNKNOWN) {
2177 0 : status = STATUS_SOME_UNMAPPED;
2178 0 : continue;
2179 : }
2180 :
2181 1492 : r->out.rids->ids[i] = sid->sub_auths[sid->num_auths-1];
2182 1492 : r->out.types->ids[i] = rtype;
2183 1492 : num_mapped++;
2184 : }
2185 :
2186 4779 : if (num_mapped == 0) {
2187 3323 : return NT_STATUS_NONE_MAPPED;
2188 : }
2189 1456 : 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 11215 : 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 11215 : const char * const *attrs = NULL;
3217 72 : union samr_UserInfo *info;
3218 :
3219 72 : NTSTATUS status;
3220 :
3221 11215 : *r->out.info = NULL;
3222 :
3223 11215 : DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3224 :
3225 11215 : a_state = h->data;
3226 11215 : sam_ctx = a_state->sam_ctx;
3227 :
3228 : /* fill in the reply */
3229 11215 : 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 267 : case 2:
3242 : {
3243 0 : static const char * const attrs2[] = {"comment",
3244 : "countryCode",
3245 : "codePage",
3246 : NULL};
3247 267 : attrs = attrs2;
3248 267 : 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 283 : case 10:
3340 : {
3341 0 : static const char * const attrs2[] = {"homeDirectory",
3342 : "homeDrive",
3343 : NULL};
3344 283 : attrs = attrs2;
3345 283 : 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 11215 : ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3450 : a_state->account_dn, &res, attrs);
3451 11215 : if (ret == 0) {
3452 0 : return NT_STATUS_NO_SUCH_USER;
3453 : }
3454 11215 : if (ret != 1) {
3455 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
3456 : }
3457 11215 : msg = res[0];
3458 :
3459 : /* allocate the info structure */
3460 11215 : info = talloc_zero(mem_ctx, union samr_UserInfo);
3461 11215 : if (info == NULL) {
3462 0 : return NT_STATUS_NO_MEMORY;
3463 : }
3464 :
3465 : /* fill in the reply */
3466 11215 : 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 267 : case 2:
3476 267 : QUERY_STRING(msg, info2.comment, "comment");
3477 267 : QUERY_UINT (msg, info2.country_code, "countryCode");
3478 267 : QUERY_UINT (msg, info2.code_page, "codePage");
3479 267 : 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 283 : case 10:
3546 283 : QUERY_STRING(msg, info10.home_directory,"homeDirectory");
3547 283 : QUERY_STRING(msg, info10.home_drive, "homeDrive");
3548 283 : 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 741 : info->info21.password_expired = PASS_MUST_CHANGE_AT_NEXT_LOGON;
3613 : } else {
3614 2230 : 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 11215 : *r->out.info = info;
3627 :
3628 11215 : return NT_STATUS_OK;
3629 : }
3630 :
3631 :
3632 : /*
3633 : samr_SetUserInfo
3634 : */
3635 4220 : 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 4220 : NTSTATUS status = NT_STATUS_OK;
3643 144 : struct ldb_context *sam_ctx;
3644 4220 : DATA_BLOB session_key = data_blob_null;
3645 :
3646 4220 : DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3647 :
3648 4220 : a_state = h->data;
3649 4220 : sam_ctx = a_state->sam_ctx;
3650 :
3651 4220 : msg = ldb_msg_new(mem_ctx);
3652 4220 : if (msg == NULL) {
3653 0 : return NT_STATUS_NO_MEMORY;
3654 : }
3655 :
3656 4220 : msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3657 4220 : if (!msg->dn) {
3658 0 : return NT_STATUS_NO_MEMORY;
3659 : }
3660 :
3661 4220 : ret = ldb_transaction_start(sam_ctx);
3662 4220 : 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 4220 : switch (r->in.level) {
3669 129 : case 2:
3670 129 : SET_STRING(msg, info2.comment, "comment");
3671 129 : SET_UINT (msg, info2.country_code, "countryCode");
3672 129 : SET_UINT (msg, info2.code_page, "codePage");
3673 129 : 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 146 : case 7:
3685 146 : SET_STRING(msg, info7.account_name, "samAccountName");
3686 146 : break;
3687 :
3688 59 : case 8:
3689 59 : SET_STRING(msg, info8.full_name, "displayName");
3690 59 : break;
3691 :
3692 0 : case 9:
3693 0 : SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3694 0 : break;
3695 :
3696 155 : case 10:
3697 155 : SET_STRING(msg, info10.home_directory, "homeDirectory");
3698 155 : SET_STRING(msg, info10.home_drive, "homeDrive");
3699 155 : break;
3700 :
3701 75 : case 11:
3702 75 : SET_STRING(msg, info11.logon_script, "scriptPath");
3703 75 : break;
3704 :
3705 76 : case 12:
3706 76 : SET_STRING(msg, info12.profile_path, "profilePath");
3707 76 : break;
3708 :
3709 80 : case 13:
3710 80 : SET_STRING(msg, info13.description, "description");
3711 80 : break;
3712 :
3713 72 : case 14:
3714 72 : SET_STRING(msg, info14.workstations, "userWorkstations");
3715 72 : break;
3716 :
3717 296 : case 16:
3718 296 : SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3719 296 : break;
3720 :
3721 54 : case 17:
3722 54 : SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3723 54 : break;
3724 :
3725 158 : case 18:
3726 158 : status = samr_set_password_buffers(dce_call,
3727 : sam_ctx,
3728 : a_state->account_dn,
3729 : mem_ctx,
3730 158 : r->in.info->info18.lm_pwd_active ? r->in.info->info18.lm_pwd.hash : NULL,
3731 158 : r->in.info->info18.nt_pwd_active ? r->in.info->info18.nt_pwd.hash : NULL);
3732 158 : if (!NT_STATUS_IS_OK(status)) {
3733 229 : goto done;
3734 : }
3735 :
3736 158 : if (r->in.info->info18.password_expired > 0) {
3737 0 : struct ldb_message_element *set_el;
3738 16 : if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3739 0 : status = NT_STATUS_NO_MEMORY;
3740 0 : goto done;
3741 : }
3742 16 : set_el = ldb_msg_find_element(msg, "pwdLastSet");
3743 16 : set_el->flags = LDB_FLAG_MOD_REPLACE;
3744 : }
3745 158 : break;
3746 :
3747 48 : case 20:
3748 48 : SET_PARAMETERS(msg, info20.parameters, "userParameters");
3749 48 : break;
3750 :
3751 1491 : case 21:
3752 1491 : if (r->in.info->info21.fields_present == 0) {
3753 8 : status = NT_STATUS_INVALID_PARAMETER;
3754 8 : goto done;
3755 : }
3756 :
3757 : #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3758 1483 : IFSET(SAMR_FIELD_LAST_LOGON)
3759 0 : SET_UINT64(msg, info21.last_logon, "lastLogon");
3760 1483 : IFSET(SAMR_FIELD_LAST_LOGOFF)
3761 0 : SET_UINT64(msg, info21.last_logoff, "lastLogoff");
3762 1483 : IFSET(SAMR_FIELD_ACCT_EXPIRY)
3763 74 : SET_UINT64(msg, info21.acct_expiry, "accountExpires");
3764 1483 : IFSET(SAMR_FIELD_ACCOUNT_NAME)
3765 25 : SET_STRING(msg, info21.account_name, "samAccountName");
3766 1483 : IFSET(SAMR_FIELD_FULL_NAME)
3767 563 : SET_STRING(msg, info21.full_name, "displayName");
3768 1483 : IFSET(SAMR_FIELD_HOME_DIRECTORY)
3769 50 : SET_STRING(msg, info21.home_directory, "homeDirectory");
3770 1483 : IFSET(SAMR_FIELD_HOME_DRIVE)
3771 50 : SET_STRING(msg, info21.home_drive, "homeDrive");
3772 1483 : IFSET(SAMR_FIELD_LOGON_SCRIPT)
3773 26 : SET_STRING(msg, info21.logon_script, "scriptPath");
3774 1483 : IFSET(SAMR_FIELD_PROFILE_PATH)
3775 26 : SET_STRING(msg, info21.profile_path, "profilePath");
3776 1483 : IFSET(SAMR_FIELD_DESCRIPTION)
3777 540 : SET_STRING(msg, info21.description, "description");
3778 1483 : IFSET(SAMR_FIELD_WORKSTATIONS)
3779 100 : SET_STRING(msg, info21.workstations, "userWorkstations");
3780 1483 : IFSET(SAMR_FIELD_COMMENT)
3781 571 : SET_STRING(msg, info21.comment, "comment");
3782 1483 : IFSET(SAMR_FIELD_PARAMETERS)
3783 96 : SET_PARAMETERS(msg, info21.parameters, "userParameters");
3784 1483 : IFSET(SAMR_FIELD_PRIMARY_GID)
3785 2 : SET_UINT(msg, info21.primary_gid, "primaryGroupID");
3786 1483 : IFSET(SAMR_FIELD_ACCT_FLAGS)
3787 43 : SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3788 1483 : IFSET(SAMR_FIELD_LOGON_HOURS)
3789 27 : SET_LHOURS(msg, info21.logon_hours, "logonHours");
3790 1483 : IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3791 0 : SET_UINT (msg, info21.bad_password_count, "badPwdCount");
3792 1483 : IFSET(SAMR_FIELD_NUM_LOGONS)
3793 0 : SET_UINT (msg, info21.logon_count, "logonCount");
3794 1483 : IFSET(SAMR_FIELD_COUNTRY_CODE)
3795 48 : SET_UINT (msg, info21.country_code, "countryCode");
3796 1483 : IFSET(SAMR_FIELD_CODE_PAGE)
3797 48 : SET_UINT (msg, info21.code_page, "codePage");
3798 :
3799 : /* password change fields */
3800 1483 : IFSET(SAMR_FIELD_LAST_PWD_CHANGE) {
3801 40 : status = NT_STATUS_ACCESS_DENIED;
3802 40 : goto done;
3803 : }
3804 :
3805 1443 : IFSET((SAMR_FIELD_LM_PASSWORD_PRESENT
3806 : | SAMR_FIELD_NT_PASSWORD_PRESENT)) {
3807 188 : uint8_t *lm_pwd_hash = NULL, *nt_pwd_hash = NULL;
3808 :
3809 188 : if (r->in.info->info21.lm_password_set) {
3810 100 : if ((r->in.info->info21.lm_owf_password.length != 16)
3811 88 : || (r->in.info->info21.lm_owf_password.size != 16)) {
3812 12 : status = NT_STATUS_INVALID_PARAMETER;
3813 12 : goto done;
3814 : }
3815 :
3816 88 : lm_pwd_hash = (uint8_t *) r->in.info->info21.lm_owf_password.array;
3817 : }
3818 176 : if (r->in.info->info21.nt_password_set) {
3819 176 : if ((r->in.info->info21.nt_owf_password.length != 16)
3820 152 : || (r->in.info->info21.nt_owf_password.size != 16)) {
3821 24 : status = NT_STATUS_INVALID_PARAMETER;
3822 24 : goto done;
3823 : }
3824 :
3825 152 : nt_pwd_hash = (uint8_t *) r->in.info->info21.nt_owf_password.array;
3826 : }
3827 152 : status = samr_set_password_buffers(dce_call,
3828 : sam_ctx,
3829 : a_state->account_dn,
3830 : mem_ctx,
3831 : lm_pwd_hash,
3832 : nt_pwd_hash);
3833 152 : if (!NT_STATUS_IS_OK(status)) {
3834 0 : goto done;
3835 : }
3836 : }
3837 :
3838 :
3839 1407 : IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3840 98 : const char *t = "0";
3841 0 : struct ldb_message_element *set_el;
3842 98 : if (r->in.info->info21.password_expired
3843 : == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3844 50 : t = "-1";
3845 : }
3846 98 : if (ldb_msg_add_string(msg, "pwdLastSet", t) != LDB_SUCCESS) {
3847 0 : status = NT_STATUS_NO_MEMORY;
3848 0 : goto done;
3849 : }
3850 98 : set_el = ldb_msg_find_element(msg, "pwdLastSet");
3851 98 : set_el->flags = LDB_FLAG_MOD_REPLACE;
3852 : }
3853 : #undef IFSET
3854 1335 : break;
3855 :
3856 74 : case 23:
3857 74 : if (r->in.info->info23.info.fields_present == 0) {
3858 0 : status = NT_STATUS_INVALID_PARAMETER;
3859 0 : goto done;
3860 : }
3861 :
3862 : #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3863 74 : IFSET(SAMR_FIELD_LAST_LOGON)
3864 0 : SET_UINT64(msg, info23.info.last_logon, "lastLogon");
3865 74 : IFSET(SAMR_FIELD_LAST_LOGOFF)
3866 0 : SET_UINT64(msg, info23.info.last_logoff, "lastLogoff");
3867 74 : IFSET(SAMR_FIELD_ACCT_EXPIRY)
3868 0 : SET_UINT64(msg, info23.info.acct_expiry, "accountExpires");
3869 74 : IFSET(SAMR_FIELD_ACCOUNT_NAME)
3870 0 : SET_STRING(msg, info23.info.account_name, "samAccountName");
3871 74 : IFSET(SAMR_FIELD_FULL_NAME)
3872 0 : SET_STRING(msg, info23.info.full_name, "displayName");
3873 74 : IFSET(SAMR_FIELD_HOME_DIRECTORY)
3874 0 : SET_STRING(msg, info23.info.home_directory, "homeDirectory");
3875 74 : IFSET(SAMR_FIELD_HOME_DRIVE)
3876 0 : SET_STRING(msg, info23.info.home_drive, "homeDrive");
3877 74 : IFSET(SAMR_FIELD_LOGON_SCRIPT)
3878 0 : SET_STRING(msg, info23.info.logon_script, "scriptPath");
3879 74 : IFSET(SAMR_FIELD_PROFILE_PATH)
3880 0 : SET_STRING(msg, info23.info.profile_path, "profilePath");
3881 74 : IFSET(SAMR_FIELD_DESCRIPTION)
3882 0 : SET_STRING(msg, info23.info.description, "description");
3883 74 : IFSET(SAMR_FIELD_WORKSTATIONS)
3884 0 : SET_STRING(msg, info23.info.workstations, "userWorkstations");
3885 74 : IFSET(SAMR_FIELD_COMMENT)
3886 0 : SET_STRING(msg, info23.info.comment, "comment");
3887 74 : IFSET(SAMR_FIELD_PARAMETERS)
3888 0 : SET_PARAMETERS(msg, info23.info.parameters, "userParameters");
3889 74 : IFSET(SAMR_FIELD_PRIMARY_GID)
3890 0 : SET_UINT(msg, info23.info.primary_gid, "primaryGroupID");
3891 74 : IFSET(SAMR_FIELD_ACCT_FLAGS)
3892 0 : SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3893 74 : IFSET(SAMR_FIELD_LOGON_HOURS)
3894 0 : SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3895 74 : IFSET(SAMR_FIELD_BAD_PWD_COUNT)
3896 0 : SET_UINT (msg, info23.info.bad_password_count, "badPwdCount");
3897 74 : IFSET(SAMR_FIELD_NUM_LOGONS)
3898 0 : SET_UINT (msg, info23.info.logon_count, "logonCount");
3899 :
3900 74 : IFSET(SAMR_FIELD_COUNTRY_CODE)
3901 0 : SET_UINT (msg, info23.info.country_code, "countryCode");
3902 74 : IFSET(SAMR_FIELD_CODE_PAGE)
3903 0 : SET_UINT (msg, info23.info.code_page, "codePage");
3904 :
3905 : /* password change fields */
3906 74 : IFSET(SAMR_FIELD_LAST_PWD_CHANGE) {
3907 0 : status = NT_STATUS_ACCESS_DENIED;
3908 0 : goto done;
3909 : }
3910 :
3911 74 : IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
3912 50 : status = samr_set_password(dce_call,
3913 : sam_ctx,
3914 : a_state->account_dn,
3915 : mem_ctx,
3916 50 : &r->in.info->info23.password);
3917 24 : } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
3918 24 : status = samr_set_password(dce_call,
3919 : sam_ctx,
3920 : a_state->account_dn,
3921 : mem_ctx,
3922 24 : &r->in.info->info23.password);
3923 : }
3924 74 : if (!NT_STATUS_IS_OK(status)) {
3925 36 : goto done;
3926 : }
3927 :
3928 38 : IFSET(SAMR_FIELD_EXPIRED_FLAG) {
3929 2 : const char *t = "0";
3930 0 : struct ldb_message_element *set_el;
3931 2 : if (r->in.info->info23.info.password_expired
3932 : == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
3933 2 : t = "-1";
3934 : }
3935 2 : if (ldb_msg_add_string(msg, "pwdLastSet", t) != LDB_SUCCESS) {
3936 0 : status = NT_STATUS_NO_MEMORY;
3937 0 : goto done;
3938 : }
3939 2 : set_el = ldb_msg_find_element(msg, "pwdLastSet");
3940 2 : set_el->flags = LDB_FLAG_MOD_REPLACE;
3941 : }
3942 : #undef IFSET
3943 38 : break;
3944 :
3945 : /* the set password levels are handled separately */
3946 173 : case 24:
3947 173 : status = samr_set_password(dce_call,
3948 : sam_ctx,
3949 : a_state->account_dn,
3950 : mem_ctx,
3951 173 : &r->in.info->info24.password);
3952 173 : if (!NT_STATUS_IS_OK(status)) {
3953 0 : goto done;
3954 : }
3955 :
3956 173 : if (r->in.info->info24.password_expired > 0) {
3957 0 : struct ldb_message_element *set_el;
3958 4 : if (samdb_msg_add_uint64(sam_ctx, mem_ctx, msg, "pwdLastSet", 0) != LDB_SUCCESS) {
3959 0 : status = NT_STATUS_NO_MEMORY;
3960 0 : goto done;
3961 : }
3962 4 : set_el = ldb_msg_find_element(msg, "pwdLastSet");
3963 4 : set_el->flags = LDB_FLAG_MOD_REPLACE;
3964 : }
3965 173 : break;
3966 :
3967 593 : case 25:
3968 593 : if (r->in.info->info25.info.fields_present == 0) {
3969 0 : status = NT_STATUS_INVALID_PARAMETER;
3970 0 : goto done;
3971 : }
3972 :
3973 : #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3974 593 : IFSET(SAMR_FIELD_LAST_LOGON)
3975 0 : SET_UINT64(msg, info25.info.last_logon, "lastLogon");
3976 593 : IFSET(SAMR_FIELD_LAST_LOGOFF)
3977 0 : SET_UINT64(msg, info25.info.last_logoff, "lastLogoff");
3978 593 : IFSET(SAMR_FIELD_ACCT_EXPIRY)
3979 0 : SET_UINT64(msg, info25.info.acct_expiry, "accountExpires");
3980 593 : IFSET(SAMR_FIELD_ACCOUNT_NAME)
3981 4 : SET_STRING(msg, info25.info.account_name, "samAccountName");
3982 593 : IFSET(SAMR_FIELD_FULL_NAME)
3983 509 : SET_STRING(msg, info25.info.full_name, "displayName");
3984 593 : IFSET(SAMR_FIELD_HOME_DIRECTORY)
3985 0 : SET_STRING(msg, info25.info.home_directory, "homeDirectory");
3986 593 : IFSET(SAMR_FIELD_HOME_DRIVE)
3987 0 : SET_STRING(msg, info25.info.home_drive, "homeDrive");
3988 593 : IFSET(SAMR_FIELD_LOGON_SCRIPT)
3989 0 : SET_STRING(msg, info25.info.logon_script, "scriptPath");
3990 593 : IFSET(SAMR_FIELD_PROFILE_PATH)
3991 0 : SET_STRING(msg, info25.info.profile_path, "profilePath");
3992 593 : IFSET(SAMR_FIELD_DESCRIPTION)
3993 2 : SET_STRING(msg, info25.info.description, "description");
3994 593 : IFSET(SAMR_FIELD_WORKSTATIONS)
3995 0 : SET_STRING(msg, info25.info.workstations, "userWorkstations");
3996 593 : IFSET(SAMR_FIELD_COMMENT)
3997 0 : SET_STRING(msg, info25.info.comment, "comment");
3998 593 : IFSET(SAMR_FIELD_PARAMETERS)
3999 0 : SET_PARAMETERS(msg, info25.info.parameters, "userParameters");
4000 593 : IFSET(SAMR_FIELD_PRIMARY_GID)
4001 0 : SET_UINT(msg, info25.info.primary_gid, "primaryGroupID");
4002 593 : IFSET(SAMR_FIELD_ACCT_FLAGS)
4003 513 : SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
4004 593 : IFSET(SAMR_FIELD_LOGON_HOURS)
4005 0 : SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
4006 593 : IFSET(SAMR_FIELD_BAD_PWD_COUNT)
4007 0 : SET_UINT (msg, info25.info.bad_password_count, "badPwdCount");
4008 593 : IFSET(SAMR_FIELD_NUM_LOGONS)
4009 0 : SET_UINT (msg, info25.info.logon_count, "logonCount");
4010 593 : IFSET(SAMR_FIELD_COUNTRY_CODE)
4011 0 : SET_UINT (msg, info25.info.country_code, "countryCode");
4012 593 : IFSET(SAMR_FIELD_CODE_PAGE)
4013 0 : SET_UINT (msg, info25.info.code_page, "codePage");
4014 :
4015 : /* password change fields */
4016 593 : IFSET(SAMR_FIELD_LAST_PWD_CHANGE) {
4017 0 : status = NT_STATUS_ACCESS_DENIED;
4018 0 : goto done;
4019 : }
4020 :
4021 593 : IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT) {
4022 569 : status = samr_set_password_ex(dce_call,
4023 : sam_ctx,
4024 : a_state->account_dn,
4025 : mem_ctx,
4026 497 : &r->in.info->info25.password);
4027 24 : } else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT) {
4028 24 : status = samr_set_password_ex(dce_call,
4029 : sam_ctx,
4030 : a_state->account_dn,
4031 : mem_ctx,
4032 24 : &r->in.info->info25.password);
4033 : }
4034 593 : if (!NT_STATUS_IS_OK(status)) {
4035 36 : goto done;
4036 : }
4037 :
4038 557 : IFSET(SAMR_FIELD_EXPIRED_FLAG) {
4039 0 : const char *t = "0";
4040 0 : struct ldb_message_element *set_el;
4041 0 : if (r->in.info->info25.info.password_expired
4042 : == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
4043 0 : t = "-1";
4044 : }
4045 0 : if (ldb_msg_add_string(msg, "pwdLastSet", t) != LDB_SUCCESS) {
4046 0 : status = NT_STATUS_NO_MEMORY;
4047 0 : goto done;
4048 : }
4049 0 : set_el = ldb_msg_find_element(msg, "pwdLastSet");
4050 0 : set_el->flags = LDB_FLAG_MOD_REPLACE;
4051 : }
4052 : #undef IFSET
4053 485 : break;
4054 :
4055 : /* the set password levels are handled separately */
4056 85 : case 26:
4057 85 : status = samr_set_password_ex(dce_call,
4058 : sam_ctx,
4059 : a_state->account_dn,
4060 : mem_ctx,
4061 85 : &r->in.info->info26.password);
4062 85 : if (!NT_STATUS_IS_OK(status)) {
4063 25 : goto done;
4064 : }
4065 :
4066 60 : if (r->in.info->info26.password_expired > 0) {
4067 16 : const char *t = "0";
4068 0 : struct ldb_message_element *set_el;
4069 16 : if (r->in.info->info26.password_expired
4070 : == PASS_DONT_CHANGE_AT_NEXT_LOGON) {
4071 0 : t = "-1";
4072 : }
4073 16 : if (ldb_msg_add_string(msg, "pwdLastSet", t) != LDB_SUCCESS) {
4074 0 : status = NT_STATUS_NO_MEMORY;
4075 0 : goto done;
4076 : }
4077 16 : set_el = ldb_msg_find_element(msg, "pwdLastSet");
4078 16 : set_el->flags = LDB_FLAG_MOD_REPLACE;
4079 : }
4080 60 : break;
4081 :
4082 24 : case 31:
4083 24 : status = dcesrv_transport_session_key(dce_call, &session_key);
4084 24 : if (!NT_STATUS_IS_OK(status)) {
4085 0 : DBG_NOTICE("samr: failed to get session key: %s\n",
4086 : nt_errstr(status));
4087 0 : goto done;
4088 : }
4089 :
4090 24 : status = samr_set_password_aes(dce_call,
4091 : mem_ctx,
4092 : &session_key,
4093 : sam_ctx,
4094 : a_state->account_dn,
4095 24 : &r->in.info->info31.password,
4096 : DSDB_PASSWORD_RESET);
4097 24 : if (!NT_STATUS_IS_OK(status)) {
4098 12 : goto done;
4099 : }
4100 :
4101 12 : if (r->in.info->info31.password_expired > 0) {
4102 0 : const char *t = "0";
4103 0 : struct ldb_message_element *set_el = NULL;
4104 :
4105 0 : if (r->in.info->info31.password_expired ==
4106 : PASS_DONT_CHANGE_AT_NEXT_LOGON) {
4107 0 : t = "-1";
4108 : }
4109 :
4110 0 : ret = ldb_msg_add_string(msg, "pwdLastSet", t);
4111 0 : if (ret != LDB_SUCCESS) {
4112 0 : status = NT_STATUS_NO_MEMORY;
4113 0 : goto done;
4114 : }
4115 0 : set_el = ldb_msg_find_element(msg, "pwdLastSet");
4116 0 : set_el->flags = LDB_FLAG_MOD_REPLACE;
4117 : }
4118 :
4119 12 : break;
4120 72 : case 32:
4121 72 : status = dcesrv_transport_session_key(dce_call, &session_key);
4122 72 : if (!NT_STATUS_IS_OK(status)) {
4123 0 : DBG_NOTICE("samr: failed to get session key: %s\n",
4124 : nt_errstr(status));
4125 0 : goto done;
4126 : }
4127 :
4128 72 : if (r->in.info->info32.info.fields_present == 0) {
4129 0 : status = NT_STATUS_INVALID_PARAMETER;
4130 0 : goto done;
4131 : }
4132 :
4133 : #define IFSET(bit) if (bit & r->in.info->info32.info.fields_present)
4134 72 : IFSET(SAMR_FIELD_LAST_LOGON)
4135 : {
4136 0 : SET_UINT64(msg, info32.info.last_logon, "lastLogon");
4137 : }
4138 72 : IFSET(SAMR_FIELD_LAST_LOGOFF)
4139 : {
4140 0 : SET_UINT64(msg, info32.info.last_logoff, "lastLogoff");
4141 : }
4142 72 : IFSET(SAMR_FIELD_ACCT_EXPIRY)
4143 : {
4144 0 : SET_UINT64(msg,
4145 : info32.info.acct_expiry,
4146 : "accountExpires");
4147 : }
4148 72 : IFSET(SAMR_FIELD_ACCOUNT_NAME)
4149 : {
4150 0 : SET_STRING(msg,
4151 : info32.info.account_name,
4152 : "samAccountName");
4153 : }
4154 72 : IFSET(SAMR_FIELD_FULL_NAME)
4155 : {
4156 0 : SET_STRING(msg, info32.info.full_name, "displayName");
4157 : }
4158 72 : IFSET(SAMR_FIELD_HOME_DIRECTORY)
4159 : {
4160 0 : SET_STRING(msg,
4161 : info32.info.home_directory,
4162 : "homeDirectory");
4163 : }
4164 72 : IFSET(SAMR_FIELD_HOME_DRIVE)
4165 : {
4166 0 : SET_STRING(msg, info32.info.home_drive, "homeDrive");
4167 : }
4168 72 : IFSET(SAMR_FIELD_LOGON_SCRIPT)
4169 : {
4170 0 : SET_STRING(msg, info32.info.logon_script, "scriptPath");
4171 : }
4172 72 : IFSET(SAMR_FIELD_PROFILE_PATH)
4173 : {
4174 0 : SET_STRING(msg,
4175 : info32.info.profile_path,
4176 : "profilePath");
4177 : }
4178 72 : IFSET(SAMR_FIELD_DESCRIPTION)
4179 : {
4180 0 : SET_STRING(msg, info32.info.description, "description");
4181 : }
4182 72 : IFSET(SAMR_FIELD_WORKSTATIONS)
4183 : {
4184 0 : SET_STRING(msg,
4185 : info32.info.workstations,
4186 : "userWorkstations");
4187 : }
4188 72 : IFSET(SAMR_FIELD_COMMENT)
4189 : {
4190 0 : SET_STRING(msg, info32.info.comment, "comment");
4191 : }
4192 72 : IFSET(SAMR_FIELD_PARAMETERS)
4193 : {
4194 0 : SET_PARAMETERS(msg,
4195 : info32.info.parameters,
4196 : "userParameters");
4197 : }
4198 72 : IFSET(SAMR_FIELD_PRIMARY_GID)
4199 : {
4200 0 : SET_UINT(msg,
4201 : info32.info.primary_gid,
4202 : "primaryGroupID");
4203 : }
4204 72 : IFSET(SAMR_FIELD_ACCT_FLAGS)
4205 : {
4206 0 : SET_AFLAGS(msg,
4207 : info32.info.acct_flags,
4208 : "userAccountControl");
4209 : }
4210 72 : IFSET(SAMR_FIELD_LOGON_HOURS)
4211 : {
4212 0 : SET_LHOURS(msg, info32.info.logon_hours, "logonHours");
4213 : }
4214 72 : IFSET(SAMR_FIELD_BAD_PWD_COUNT)
4215 : {
4216 0 : SET_UINT(msg,
4217 : info32.info.bad_password_count,
4218 : "badPwdCount");
4219 : }
4220 72 : IFSET(SAMR_FIELD_NUM_LOGONS)
4221 : {
4222 0 : SET_UINT(msg, info32.info.logon_count, "logonCount");
4223 : }
4224 72 : IFSET(SAMR_FIELD_COUNTRY_CODE)
4225 : {
4226 0 : SET_UINT(msg, info32.info.country_code, "countryCode");
4227 : }
4228 72 : IFSET(SAMR_FIELD_CODE_PAGE)
4229 : {
4230 0 : SET_UINT(msg, info32.info.code_page, "codePage");
4231 : }
4232 :
4233 : /* password change fields */
4234 72 : IFSET(SAMR_FIELD_LAST_PWD_CHANGE)
4235 : {
4236 0 : status = NT_STATUS_ACCESS_DENIED;
4237 0 : goto done;
4238 : }
4239 :
4240 72 : IFSET(SAMR_FIELD_NT_PASSWORD_PRESENT)
4241 : {
4242 48 : status = samr_set_password_aes(
4243 : dce_call,
4244 : mem_ctx,
4245 : &session_key,
4246 48 : a_state->sam_ctx,
4247 : a_state->account_dn,
4248 48 : &r->in.info->info32.password,
4249 : DSDB_PASSWORD_RESET);
4250 : }
4251 24 : else IFSET(SAMR_FIELD_LM_PASSWORD_PRESENT)
4252 : {
4253 24 : status = samr_set_password_aes(
4254 : dce_call,
4255 : mem_ctx,
4256 : &session_key,
4257 24 : a_state->sam_ctx,
4258 : a_state->account_dn,
4259 24 : &r->in.info->info32.password,
4260 : DSDB_PASSWORD_RESET);
4261 : }
4262 72 : if (!NT_STATUS_IS_OK(status)) {
4263 36 : goto done;
4264 : }
4265 :
4266 36 : IFSET(SAMR_FIELD_EXPIRED_FLAG)
4267 : {
4268 0 : const char *t = "0";
4269 0 : struct ldb_message_element *set_el;
4270 0 : if (r->in.info->info32.info.password_expired ==
4271 : PASS_DONT_CHANGE_AT_NEXT_LOGON) {
4272 0 : t = "-1";
4273 : }
4274 0 : if (ldb_msg_add_string(msg, "pwdLastSet", t) !=
4275 : LDB_SUCCESS) {
4276 0 : status = NT_STATUS_NO_MEMORY;
4277 0 : goto done;
4278 : }
4279 0 : set_el = ldb_msg_find_element(msg, "pwdLastSet");
4280 0 : set_el->flags = LDB_FLAG_MOD_REPLACE;
4281 : }
4282 : #undef IFSET
4283 :
4284 36 : break;
4285 0 : default:
4286 : /* many info classes are not valid for SetUserInfo */
4287 0 : status = NT_STATUS_INVALID_INFO_CLASS;
4288 0 : goto done;
4289 : }
4290 :
4291 3991 : if (!NT_STATUS_IS_OK(status)) {
4292 0 : goto done;
4293 : }
4294 :
4295 : /* modify the samdb record */
4296 3991 : if (msg->num_elements > 0) {
4297 3348 : ret = ldb_modify(sam_ctx, msg);
4298 3348 : if (ret != LDB_SUCCESS) {
4299 0 : DEBUG(1,("Failed to modify record %s: %s\n",
4300 : ldb_dn_get_linearized(a_state->account_dn),
4301 : ldb_errstring(sam_ctx)));
4302 :
4303 0 : status = dsdb_ldb_err_to_ntstatus(ret);
4304 0 : goto done;
4305 : }
4306 : }
4307 :
4308 3991 : ret = ldb_transaction_commit(sam_ctx);
4309 3991 : if (ret != LDB_SUCCESS) {
4310 0 : DBG_ERR("Failed to commit transaction modifying account record "
4311 : "%s: %s\n",
4312 : ldb_dn_get_linearized(msg->dn),
4313 : ldb_errstring(sam_ctx));
4314 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
4315 : }
4316 :
4317 3847 : status = NT_STATUS_OK;
4318 4220 : done:
4319 4220 : if (!NT_STATUS_IS_OK(status)) {
4320 229 : ldb_transaction_cancel(sam_ctx);
4321 : }
4322 :
4323 4220 : return status;
4324 : }
4325 :
4326 :
4327 : /*
4328 : samr_GetGroupsForUser
4329 : */
4330 210 : static NTSTATUS dcesrv_samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4331 : struct samr_GetGroupsForUser *r)
4332 : {
4333 0 : struct dcesrv_handle *h;
4334 0 : struct samr_account_state *a_state;
4335 0 : struct samr_domain_state *d_state;
4336 0 : struct ldb_result *res, *res_memberof;
4337 210 : const char * const attrs[] = { "primaryGroupID",
4338 : "memberOf",
4339 : NULL };
4340 210 : const char * const group_attrs[] = { "objectSid",
4341 : NULL };
4342 :
4343 0 : struct samr_RidWithAttributeArray *array;
4344 0 : struct ldb_message_element *memberof_el;
4345 210 : int i, ret, count = 0;
4346 0 : uint32_t primary_group_id;
4347 0 : char *filter;
4348 :
4349 210 : DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
4350 :
4351 210 : a_state = h->data;
4352 210 : d_state = a_state->domain_state;
4353 :
4354 210 : ret = dsdb_search_dn(a_state->sam_ctx, mem_ctx,
4355 : &res,
4356 : a_state->account_dn,
4357 : attrs, DSDB_SEARCH_SHOW_EXTENDED_DN);
4358 :
4359 210 : if (ret == LDB_ERR_NO_SUCH_OBJECT) {
4360 0 : return NT_STATUS_NO_SUCH_USER;
4361 210 : } else if (ret != LDB_SUCCESS) {
4362 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
4363 210 : } else if (res->count != 1) {
4364 0 : return NT_STATUS_NO_SUCH_USER;
4365 : }
4366 :
4367 210 : primary_group_id = ldb_msg_find_attr_as_uint(res->msgs[0], "primaryGroupID",
4368 : 0);
4369 :
4370 210 : filter = talloc_asprintf(mem_ctx,
4371 : "(&(|(grouptype=%d)(grouptype=%d))"
4372 : "(objectclass=group)(|",
4373 : GTYPE_SECURITY_UNIVERSAL_GROUP,
4374 : GTYPE_SECURITY_GLOBAL_GROUP);
4375 210 : if (filter == NULL) {
4376 0 : return NT_STATUS_NO_MEMORY;
4377 : }
4378 :
4379 210 : memberof_el = ldb_msg_find_element(res->msgs[0], "memberOf");
4380 210 : if (memberof_el != NULL) {
4381 226 : for (i = 0; i < memberof_el->num_values; i++) {
4382 0 : const struct ldb_val *memberof_sid_binary;
4383 0 : char *memberof_sid_escaped;
4384 0 : struct ldb_dn *memberof_dn
4385 146 : = ldb_dn_from_ldb_val(mem_ctx,
4386 146 : a_state->sam_ctx,
4387 146 : &memberof_el->values[i]);
4388 146 : if (memberof_dn == NULL) {
4389 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
4390 : }
4391 :
4392 0 : memberof_sid_binary
4393 146 : = ldb_dn_get_extended_component(memberof_dn,
4394 : "SID");
4395 146 : if (memberof_sid_binary == NULL) {
4396 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
4397 : }
4398 :
4399 146 : memberof_sid_escaped = ldb_binary_encode(mem_ctx,
4400 : *memberof_sid_binary);
4401 146 : if (memberof_sid_escaped == NULL) {
4402 0 : return NT_STATUS_NO_MEMORY;
4403 : }
4404 146 : filter = talloc_asprintf_append(filter, "(objectSID=%s)",
4405 : memberof_sid_escaped);
4406 146 : if (filter == NULL) {
4407 0 : return NT_STATUS_NO_MEMORY;
4408 : }
4409 : }
4410 :
4411 80 : ret = dsdb_search(a_state->sam_ctx, mem_ctx,
4412 : &res_memberof,
4413 : d_state->domain_dn,
4414 : LDB_SCOPE_SUBTREE,
4415 : group_attrs, 0,
4416 : "%s))", filter);
4417 :
4418 80 : if (ret != LDB_SUCCESS) {
4419 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
4420 : }
4421 80 : count = res_memberof->count;
4422 : }
4423 :
4424 210 : array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
4425 210 : if (array == NULL)
4426 0 : return NT_STATUS_NO_MEMORY;
4427 :
4428 210 : array->count = 0;
4429 210 : array->rids = NULL;
4430 :
4431 210 : array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
4432 : count + 1);
4433 210 : if (array->rids == NULL)
4434 0 : return NT_STATUS_NO_MEMORY;
4435 :
4436 : /* Adds the primary group */
4437 :
4438 210 : array->rids[0].rid = primary_group_id;
4439 210 : array->rids[0].attributes = SE_GROUP_DEFAULT_FLAGS;
4440 210 : array->count += 1;
4441 :
4442 : /* Adds the additional groups */
4443 292 : for (i = 0; i < count; i++) {
4444 0 : struct dom_sid *group_sid;
4445 :
4446 82 : group_sid = samdb_result_dom_sid(mem_ctx,
4447 82 : res_memberof->msgs[i],
4448 : "objectSid");
4449 82 : if (group_sid == NULL) {
4450 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
4451 : }
4452 :
4453 82 : array->rids[i + 1].rid =
4454 82 : group_sid->sub_auths[group_sid->num_auths-1];
4455 82 : array->rids[i + 1].attributes = SE_GROUP_DEFAULT_FLAGS;
4456 82 : array->count += 1;
4457 : }
4458 :
4459 210 : *r->out.rids = array;
4460 :
4461 210 : return NT_STATUS_OK;
4462 : }
4463 :
4464 : /*
4465 : * samr_QueryDisplayInfo
4466 : *
4467 : * A cache of the GUID's matching the last query is maintained
4468 : * in the SAMR_QUERY_DISPLAY_INFO_CACHE guid_cache maintained o
4469 : * n the dcesrv_handle.
4470 : */
4471 371 : static NTSTATUS dcesrv_samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4472 : struct samr_QueryDisplayInfo *r)
4473 : {
4474 0 : struct dcesrv_handle *h;
4475 0 : struct samr_domain_state *d_state;
4476 0 : struct ldb_result *res;
4477 0 : uint32_t i;
4478 371 : uint32_t results = 0;
4479 371 : uint32_t count = 0;
4480 371 : const char *const cache_attrs[] = {"objectGUID", NULL};
4481 371 : const char *const attrs[] = {
4482 : "objectSID", "sAMAccountName", "displayName", "description", NULL};
4483 371 : struct samr_DispEntryFull *entriesFull = NULL;
4484 371 : struct samr_DispEntryFullGroup *entriesFullGroup = NULL;
4485 371 : struct samr_DispEntryAscii *entriesAscii = NULL;
4486 371 : struct samr_DispEntryGeneral *entriesGeneral = NULL;
4487 0 : const char *filter;
4488 0 : int ret;
4489 0 : NTSTATUS status;
4490 371 : struct samr_guid_cache *cache = NULL;
4491 :
4492 371 : DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4493 :
4494 371 : d_state = h->data;
4495 :
4496 371 : cache = &d_state->guid_caches[SAMR_QUERY_DISPLAY_INFO_CACHE];
4497 : /*
4498 : * Can the cached results be used?
4499 : * The cache is discarded if the start index is zero, or the requested
4500 : * level is different from that in the cache.
4501 : */
4502 371 : if ((r->in.start_idx == 0) || (r->in.level != cache->handle)) {
4503 : /*
4504 : * The cached results can not be used, so will need to query
4505 : * the database.
4506 : */
4507 :
4508 : /*
4509 : * Get the search filter for the current level
4510 : */
4511 141 : switch (r->in.level) {
4512 59 : case 1:
4513 : case 4:
4514 59 : filter = talloc_asprintf(mem_ctx,
4515 : "(&(objectclass=user)"
4516 : "(sAMAccountType=%d))",
4517 : ATYPE_NORMAL_ACCOUNT);
4518 59 : break;
4519 22 : case 2:
4520 22 : filter = talloc_asprintf(mem_ctx,
4521 : "(&(objectclass=user)"
4522 : "(sAMAccountType=%d))",
4523 : ATYPE_WORKSTATION_TRUST);
4524 22 : break;
4525 60 : case 3:
4526 : case 5:
4527 0 : filter =
4528 60 : talloc_asprintf(mem_ctx,
4529 : "(&(|(groupType=%d)(groupType=%d))"
4530 : "(objectClass=group))",
4531 : GTYPE_SECURITY_UNIVERSAL_GROUP,
4532 : GTYPE_SECURITY_GLOBAL_GROUP);
4533 60 : break;
4534 0 : default:
4535 0 : return NT_STATUS_INVALID_INFO_CLASS;
4536 : }
4537 141 : clear_guid_cache(cache);
4538 :
4539 : /*
4540 : * search for all requested objects in all domains.
4541 : */
4542 141 : ret = dsdb_search(d_state->sam_ctx,
4543 : mem_ctx,
4544 : &res,
4545 141 : ldb_get_default_basedn(d_state->sam_ctx),
4546 : LDB_SCOPE_SUBTREE,
4547 : cache_attrs,
4548 : 0,
4549 : "%s",
4550 : filter);
4551 141 : if (ret != LDB_SUCCESS) {
4552 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
4553 : }
4554 141 : if ((res->count == 0) || (r->in.max_entries == 0)) {
4555 0 : return NT_STATUS_OK;
4556 : }
4557 :
4558 141 : status = load_guid_cache(cache, d_state, res->count, res->msgs);
4559 141 : TALLOC_FREE(res);
4560 141 : if (!NT_STATUS_IS_OK(status)) {
4561 0 : return status;
4562 : }
4563 141 : cache->handle = r->in.level;
4564 : }
4565 371 : *r->out.total_size = cache->size;
4566 :
4567 : /*
4568 : * if there are no entries or the requested start index is greater
4569 : * than the number of entries, we return an empty response.
4570 : */
4571 371 : if (r->in.start_idx >= cache->size) {
4572 11 : *r->out.returned_size = 0;
4573 11 : switch(r->in.level) {
4574 7 : case 1:
4575 7 : r->out.info->info1.count = *r->out.returned_size;
4576 7 : r->out.info->info1.entries = NULL;
4577 7 : break;
4578 1 : case 2:
4579 1 : r->out.info->info2.count = *r->out.returned_size;
4580 1 : r->out.info->info2.entries = NULL;
4581 1 : break;
4582 1 : case 3:
4583 1 : r->out.info->info3.count = *r->out.returned_size;
4584 1 : r->out.info->info3.entries = NULL;
4585 1 : break;
4586 1 : case 4:
4587 1 : r->out.info->info4.count = *r->out.returned_size;
4588 1 : r->out.info->info4.entries = NULL;
4589 1 : break;
4590 1 : case 5:
4591 1 : r->out.info->info5.count = *r->out.returned_size;
4592 1 : r->out.info->info5.entries = NULL;
4593 1 : break;
4594 : }
4595 11 : return NT_STATUS_OK;
4596 : }
4597 :
4598 : /*
4599 : * Allocate an array of the appropriate result structures for the
4600 : * current query level.
4601 : *
4602 : * r->in.start_idx is always < cache->size due to the check above
4603 : */
4604 360 : results = MIN((cache->size - r->in.start_idx), r->in.max_entries);
4605 360 : switch (r->in.level) {
4606 134 : case 1:
4607 134 : entriesGeneral = talloc_array(
4608 : mem_ctx, struct samr_DispEntryGeneral, results);
4609 134 : break;
4610 26 : case 2:
4611 0 : entriesFull =
4612 26 : talloc_array(mem_ctx, struct samr_DispEntryFull, results);
4613 26 : break;
4614 68 : case 3:
4615 68 : entriesFullGroup = talloc_array(
4616 : mem_ctx, struct samr_DispEntryFullGroup, results);
4617 68 : break;
4618 132 : case 4:
4619 : case 5:
4620 0 : entriesAscii =
4621 132 : talloc_array(mem_ctx, struct samr_DispEntryAscii, results);
4622 132 : break;
4623 : }
4624 :
4625 360 : if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
4626 68 : (entriesAscii == NULL) && (entriesFullGroup == NULL))
4627 0 : return NT_STATUS_NO_MEMORY;
4628 :
4629 : /*
4630 : * Process the list of result GUID's.
4631 : * Read the details of each object and populate the result structure
4632 : * for the current level.
4633 : */
4634 360 : count = 0;
4635 2968 : for (i = 0; i < results; i++) {
4636 0 : struct dom_sid *objectsid;
4637 0 : struct ldb_result *rec;
4638 2608 : const uint32_t idx = r->in.start_idx + i;
4639 0 : uint32_t rid;
4640 :
4641 : /*
4642 : * Read an object from disk using the GUID as the key
4643 : *
4644 : * If the object can not be read, or it does not have a SID
4645 : * it is ignored. In this case the number of entries returned
4646 : * will be less than the requested size, there will also be
4647 : * a gap in the idx numbers in the returned elements e.g. if
4648 : * there are 3 GUIDs a, b, c in the cache and b is deleted from
4649 : * disk then details for a, and c will be returned with
4650 : * idx values of 1 and 3 respectively.
4651 : *
4652 : */
4653 2608 : ret = dsdb_search_by_dn_guid(d_state->sam_ctx,
4654 : mem_ctx,
4655 : &rec,
4656 2608 : &cache->entries[idx],
4657 : attrs,
4658 : 0);
4659 2608 : if (ret == LDB_ERR_NO_SUCH_OBJECT) {
4660 0 : struct GUID_txt_buf guid_buf;
4661 0 : char *guid_str =
4662 18 : GUID_buf_string(&cache->entries[idx],
4663 : &guid_buf);
4664 18 : DBG_WARNING("GUID [%s] not found\n", guid_str);
4665 18 : continue;
4666 2590 : } else if (ret != LDB_SUCCESS) {
4667 0 : clear_guid_cache(cache);
4668 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
4669 : }
4670 2590 : objectsid = samdb_result_dom_sid(mem_ctx,
4671 2590 : rec->msgs[0],
4672 : "objectSID");
4673 2590 : if (objectsid == NULL) {
4674 0 : struct GUID_txt_buf guid_buf;
4675 0 : DBG_WARNING(
4676 : "objectSID for GUID [%s] not found\n",
4677 : GUID_buf_string(&cache->entries[idx], &guid_buf));
4678 0 : continue;
4679 : }
4680 2590 : status = dom_sid_split_rid(NULL,
4681 : objectsid,
4682 : NULL,
4683 : &rid);
4684 2590 : if (!NT_STATUS_IS_OK(status)) {
4685 0 : struct dom_sid_buf sid_buf;
4686 0 : struct GUID_txt_buf guid_buf;
4687 0 : DBG_WARNING(
4688 : "objectSID [%s] for GUID [%s] invalid\n",
4689 : dom_sid_str_buf(objectsid, &sid_buf),
4690 : GUID_buf_string(&cache->entries[idx], &guid_buf));
4691 0 : continue;
4692 : }
4693 :
4694 : /*
4695 : * Populate the result structure for the current object
4696 : */
4697 2590 : switch(r->in.level) {
4698 939 : case 1:
4699 :
4700 939 : entriesGeneral[count].idx = idx + 1;
4701 939 : entriesGeneral[count].rid = rid;
4702 :
4703 1878 : entriesGeneral[count].acct_flags =
4704 939 : samdb_result_acct_flags(rec->msgs[0], NULL);
4705 1878 : entriesGeneral[count].account_name.string =
4706 939 : ldb_msg_find_attr_as_string(
4707 939 : rec->msgs[0], "sAMAccountName", "");
4708 1878 : entriesGeneral[count].full_name.string =
4709 939 : ldb_msg_find_attr_as_string(
4710 939 : rec->msgs[0], "displayName", "");
4711 1878 : entriesGeneral[count].description.string =
4712 939 : ldb_msg_find_attr_as_string(
4713 939 : rec->msgs[0], "description", "");
4714 939 : break;
4715 51 : case 2:
4716 51 : entriesFull[count].idx = idx + 1;
4717 51 : entriesFull[count].rid = rid;
4718 :
4719 : /*
4720 : * No idea why we need to or in ACB_NORMAL here,
4721 : * but this is what Win2k3 seems to do...
4722 : */
4723 51 : entriesFull[count].acct_flags =
4724 51 : samdb_result_acct_flags(rec->msgs[0], NULL) |
4725 : ACB_NORMAL;
4726 102 : entriesFull[count].account_name.string =
4727 51 : ldb_msg_find_attr_as_string(
4728 51 : rec->msgs[0], "sAMAccountName", "");
4729 102 : entriesFull[count].description.string =
4730 51 : ldb_msg_find_attr_as_string(
4731 51 : rec->msgs[0], "description", "");
4732 51 : break;
4733 906 : case 3:
4734 906 : entriesFullGroup[count].idx = idx + 1;
4735 906 : entriesFullGroup[count].rid = rid;
4736 :
4737 : /*
4738 : * We get a "7" here for groups
4739 : */
4740 906 : entriesFullGroup[count].acct_flags = SE_GROUP_DEFAULT_FLAGS;
4741 1812 : entriesFullGroup[count].account_name.string =
4742 906 : ldb_msg_find_attr_as_string(
4743 906 : rec->msgs[0], "sAMAccountName", "");
4744 1812 : entriesFullGroup[count].description.string =
4745 906 : ldb_msg_find_attr_as_string(
4746 906 : rec->msgs[0], "description", "");
4747 906 : break;
4748 694 : case 4:
4749 : case 5:
4750 694 : entriesAscii[count].idx = idx + 1;
4751 1388 : entriesAscii[count].account_name.string =
4752 694 : ldb_msg_find_attr_as_string(
4753 694 : rec->msgs[0], "sAMAccountName", "");
4754 694 : break;
4755 : }
4756 2590 : count++;
4757 : }
4758 :
4759 : /*
4760 : * Build the response based on the request level.
4761 : */
4762 360 : *r->out.returned_size = count;
4763 360 : switch(r->in.level) {
4764 134 : case 1:
4765 134 : r->out.info->info1.count = count;
4766 134 : r->out.info->info1.entries = entriesGeneral;
4767 134 : break;
4768 26 : case 2:
4769 26 : r->out.info->info2.count = count;
4770 26 : r->out.info->info2.entries = entriesFull;
4771 26 : break;
4772 68 : case 3:
4773 68 : r->out.info->info3.count = count;
4774 68 : r->out.info->info3.entries = entriesFullGroup;
4775 68 : break;
4776 56 : case 4:
4777 56 : r->out.info->info4.count = count;
4778 56 : r->out.info->info4.entries = entriesAscii;
4779 56 : break;
4780 76 : case 5:
4781 76 : r->out.info->info5.count = count;
4782 76 : r->out.info->info5.entries = entriesAscii;
4783 76 : break;
4784 : }
4785 :
4786 360 : return ((r->in.start_idx + results) < cache->size)
4787 : ? STATUS_MORE_ENTRIES
4788 360 : : NT_STATUS_OK;
4789 : }
4790 :
4791 :
4792 : /*
4793 : samr_GetDisplayEnumerationIndex
4794 : */
4795 0 : static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4796 : struct samr_GetDisplayEnumerationIndex *r)
4797 : {
4798 0 : DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4799 : }
4800 :
4801 :
4802 : /*
4803 : samr_TestPrivateFunctionsDomain
4804 : */
4805 6 : static NTSTATUS dcesrv_samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4806 : struct samr_TestPrivateFunctionsDomain *r)
4807 : {
4808 6 : return NT_STATUS_NOT_IMPLEMENTED;
4809 : }
4810 :
4811 :
4812 : /*
4813 : samr_TestPrivateFunctionsUser
4814 : */
4815 12 : static NTSTATUS dcesrv_samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4816 : struct samr_TestPrivateFunctionsUser *r)
4817 : {
4818 12 : return NT_STATUS_NOT_IMPLEMENTED;
4819 : }
4820 :
4821 :
4822 : /*
4823 : samr_GetUserPwInfo
4824 : */
4825 1235 : static NTSTATUS dcesrv_samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4826 : struct samr_GetUserPwInfo *r)
4827 : {
4828 72 : struct dcesrv_handle *h;
4829 72 : struct samr_account_state *a_state;
4830 :
4831 1235 : ZERO_STRUCTP(r->out.info);
4832 :
4833 1235 : DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
4834 :
4835 1235 : a_state = h->data;
4836 :
4837 2470 : r->out.info->min_password_length = samdb_search_uint(a_state->sam_ctx,
4838 1235 : mem_ctx, 0, a_state->domain_state->domain_dn, "minPwdLength",
4839 : NULL);
4840 1235 : r->out.info->password_properties = samdb_search_uint(a_state->sam_ctx,
4841 : mem_ctx, 0, a_state->account_dn, "pwdProperties", NULL);
4842 :
4843 1235 : return NT_STATUS_OK;
4844 : }
4845 :
4846 :
4847 : /*
4848 : samr_RemoveMemberFromForeignDomain
4849 : */
4850 10 : static NTSTATUS dcesrv_samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call,
4851 : TALLOC_CTX *mem_ctx,
4852 : struct samr_RemoveMemberFromForeignDomain *r)
4853 : {
4854 0 : struct dcesrv_handle *h;
4855 0 : struct samr_domain_state *d_state;
4856 0 : const char *memberdn;
4857 0 : struct ldb_message **res;
4858 10 : const char *no_attrs[] = { NULL };
4859 0 : int i, count;
4860 :
4861 10 : DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4862 :
4863 10 : d_state = h->data;
4864 :
4865 10 : memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
4866 : "distinguishedName", "(objectSid=%s)",
4867 10 : ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
4868 : /* Nothing to do */
4869 10 : if (memberdn == NULL) {
4870 6 : return NT_STATUS_OK;
4871 : }
4872 :
4873 4 : count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
4874 : d_state->domain_dn, &res, no_attrs,
4875 4 : d_state->domain_sid,
4876 : "(&(member=%s)(objectClass=group)"
4877 : "(|(groupType=%d)(groupType=%d)))",
4878 : memberdn,
4879 : GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
4880 : GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
4881 :
4882 4 : if (count < 0)
4883 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
4884 :
4885 4 : for (i=0; i<count; i++) {
4886 0 : struct ldb_message *mod;
4887 0 : int ret;
4888 :
4889 0 : mod = ldb_msg_new(mem_ctx);
4890 0 : if (mod == NULL) {
4891 0 : return NT_STATUS_NO_MEMORY;
4892 : }
4893 :
4894 0 : mod->dn = res[i]->dn;
4895 :
4896 0 : if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
4897 : "member", memberdn) != LDB_SUCCESS)
4898 0 : return NT_STATUS_NO_MEMORY;
4899 :
4900 0 : ret = ldb_modify(d_state->sam_ctx, mod);
4901 0 : talloc_free(mod);
4902 0 : if (ret != LDB_SUCCESS) {
4903 0 : return dsdb_ldb_err_to_ntstatus(ret);
4904 : }
4905 : }
4906 :
4907 4 : return NT_STATUS_OK;
4908 : }
4909 :
4910 :
4911 : /*
4912 : samr_QueryDomainInfo2
4913 :
4914 : just an alias for samr_QueryDomainInfo
4915 : */
4916 107 : static NTSTATUS dcesrv_samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4917 : struct samr_QueryDomainInfo2 *r)
4918 : {
4919 0 : struct samr_QueryDomainInfo r1;
4920 0 : NTSTATUS status;
4921 :
4922 107 : r1 = (struct samr_QueryDomainInfo) {
4923 107 : .in.domain_handle = r->in.domain_handle,
4924 107 : .in.level = r->in.level,
4925 107 : .out.info = r->out.info,
4926 : };
4927 :
4928 107 : status = dcesrv_samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
4929 :
4930 107 : return status;
4931 : }
4932 :
4933 :
4934 : /*
4935 : samr_QueryUserInfo2
4936 :
4937 : just an alias for samr_QueryUserInfo
4938 : */
4939 928 : static NTSTATUS dcesrv_samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4940 : struct samr_QueryUserInfo2 *r)
4941 : {
4942 0 : struct samr_QueryUserInfo r1;
4943 0 : NTSTATUS status;
4944 :
4945 928 : r1 = (struct samr_QueryUserInfo) {
4946 928 : .in.user_handle = r->in.user_handle,
4947 928 : .in.level = r->in.level,
4948 928 : .out.info = r->out.info
4949 : };
4950 :
4951 928 : status = dcesrv_samr_QueryUserInfo(dce_call, mem_ctx, &r1);
4952 :
4953 928 : return status;
4954 : }
4955 :
4956 :
4957 : /*
4958 : samr_QueryDisplayInfo2
4959 : */
4960 34 : static NTSTATUS dcesrv_samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4961 : struct samr_QueryDisplayInfo2 *r)
4962 : {
4963 0 : struct samr_QueryDisplayInfo q;
4964 0 : NTSTATUS result;
4965 :
4966 34 : q = (struct samr_QueryDisplayInfo) {
4967 34 : .in.domain_handle = r->in.domain_handle,
4968 34 : .in.level = r->in.level,
4969 34 : .in.start_idx = r->in.start_idx,
4970 34 : .in.max_entries = r->in.max_entries,
4971 34 : .in.buf_size = r->in.buf_size,
4972 34 : .out.total_size = r->out.total_size,
4973 34 : .out.returned_size = r->out.returned_size,
4974 34 : .out.info = r->out.info,
4975 : };
4976 :
4977 34 : result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
4978 :
4979 34 : return result;
4980 : }
4981 :
4982 :
4983 : /*
4984 : samr_GetDisplayEnumerationIndex2
4985 : */
4986 0 : static NTSTATUS dcesrv_samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4987 : struct samr_GetDisplayEnumerationIndex2 *r)
4988 : {
4989 0 : DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4990 : }
4991 :
4992 :
4993 : /*
4994 : samr_QueryDisplayInfo3
4995 : */
4996 30 : static NTSTATUS dcesrv_samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4997 : struct samr_QueryDisplayInfo3 *r)
4998 : {
4999 0 : struct samr_QueryDisplayInfo q;
5000 0 : NTSTATUS result;
5001 :
5002 30 : q = (struct samr_QueryDisplayInfo) {
5003 30 : .in.domain_handle = r->in.domain_handle,
5004 30 : .in.level = r->in.level,
5005 30 : .in.start_idx = r->in.start_idx,
5006 30 : .in.max_entries = r->in.max_entries,
5007 30 : .in.buf_size = r->in.buf_size,
5008 30 : .out.total_size = r->out.total_size,
5009 30 : .out.returned_size = r->out.returned_size,
5010 30 : .out.info = r->out.info,
5011 : };
5012 :
5013 30 : result = dcesrv_samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
5014 :
5015 30 : return result;
5016 : }
5017 :
5018 :
5019 : /*
5020 : samr_AddMultipleMembersToAlias
5021 : */
5022 0 : static NTSTATUS dcesrv_samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5023 : struct samr_AddMultipleMembersToAlias *r)
5024 : {
5025 0 : DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
5026 : }
5027 :
5028 :
5029 : /*
5030 : samr_RemoveMultipleMembersFromAlias
5031 : */
5032 0 : static NTSTATUS dcesrv_samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5033 : struct samr_RemoveMultipleMembersFromAlias *r)
5034 : {
5035 0 : DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
5036 : }
5037 :
5038 :
5039 : /*
5040 : samr_GetDomPwInfo
5041 :
5042 : this fetches the default password properties for a domain
5043 :
5044 : note that w2k3 completely ignores the domain name in this call, and
5045 : always returns the information for the servers primary domain
5046 : */
5047 2867 : static NTSTATUS dcesrv_samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5048 : struct samr_GetDomPwInfo *r)
5049 : {
5050 480 : struct ldb_message **msgs;
5051 480 : int ret;
5052 2867 : const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
5053 480 : struct ldb_context *sam_ctx;
5054 :
5055 2867 : ZERO_STRUCTP(r->out.info);
5056 :
5057 2867 : sam_ctx = dcesrv_samdb_connect_as_user(mem_ctx, dce_call);
5058 2867 : if (sam_ctx == NULL) {
5059 0 : return NT_STATUS_INVALID_SYSTEM_SERVICE;
5060 : }
5061 :
5062 : /* The domain name in this call is ignored */
5063 2867 : ret = gendb_search_dn(sam_ctx,
5064 : mem_ctx, NULL, &msgs, attrs);
5065 2867 : if (ret <= 0) {
5066 0 : talloc_free(sam_ctx);
5067 :
5068 0 : return NT_STATUS_NO_SUCH_DOMAIN;
5069 : }
5070 2867 : if (ret > 1) {
5071 0 : talloc_free(msgs);
5072 0 : talloc_free(sam_ctx);
5073 :
5074 0 : return NT_STATUS_INTERNAL_DB_CORRUPTION;
5075 : }
5076 :
5077 2867 : r->out.info->min_password_length = ldb_msg_find_attr_as_uint(msgs[0],
5078 : "minPwdLength", 0);
5079 2867 : r->out.info->password_properties = ldb_msg_find_attr_as_uint(msgs[0],
5080 : "pwdProperties", 1);
5081 :
5082 2867 : talloc_free(msgs);
5083 2867 : talloc_unlink(mem_ctx, sam_ctx);
5084 :
5085 2867 : return NT_STATUS_OK;
5086 : }
5087 :
5088 :
5089 : /*
5090 : samr_Connect2
5091 : */
5092 1019 : static NTSTATUS dcesrv_samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5093 : struct samr_Connect2 *r)
5094 : {
5095 4 : struct samr_Connect c;
5096 :
5097 1019 : c = (struct samr_Connect) {
5098 : .in.system_name = NULL,
5099 1019 : .in.access_mask = r->in.access_mask,
5100 1019 : .out.connect_handle = r->out.connect_handle,
5101 : };
5102 :
5103 1019 : return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
5104 : }
5105 :
5106 :
5107 : /*
5108 : samr_SetUserInfo2
5109 :
5110 : just an alias for samr_SetUserInfo
5111 : */
5112 1688 : static NTSTATUS dcesrv_samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5113 : struct samr_SetUserInfo2 *r)
5114 : {
5115 72 : struct samr_SetUserInfo r2;
5116 :
5117 1688 : r2 = (struct samr_SetUserInfo) {
5118 1688 : .in.user_handle = r->in.user_handle,
5119 1688 : .in.level = r->in.level,
5120 1688 : .in.info = r->in.info,
5121 : };
5122 :
5123 1688 : return dcesrv_samr_SetUserInfo(dce_call, mem_ctx, &r2);
5124 : }
5125 :
5126 :
5127 : /*
5128 : samr_SetBootKeyInformation
5129 : */
5130 0 : static NTSTATUS dcesrv_samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5131 : struct samr_SetBootKeyInformation *r)
5132 : {
5133 0 : DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
5134 : }
5135 :
5136 :
5137 : /*
5138 : samr_GetBootKeyInformation
5139 : */
5140 6 : static NTSTATUS dcesrv_samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5141 : struct samr_GetBootKeyInformation *r)
5142 : {
5143 : /* Windows Server 2008 returns this */
5144 6 : return NT_STATUS_NOT_SUPPORTED;
5145 : }
5146 :
5147 :
5148 : /*
5149 : samr_Connect3
5150 : */
5151 66 : static NTSTATUS dcesrv_samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5152 : struct samr_Connect3 *r)
5153 : {
5154 0 : struct samr_Connect c;
5155 :
5156 66 : c = (struct samr_Connect) {
5157 : .in.system_name = NULL,
5158 66 : .in.access_mask = r->in.access_mask,
5159 66 : .out.connect_handle = r->out.connect_handle,
5160 : };
5161 :
5162 66 : return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
5163 : }
5164 :
5165 :
5166 : /*
5167 : samr_Connect4
5168 : */
5169 66 : static NTSTATUS dcesrv_samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5170 : struct samr_Connect4 *r)
5171 : {
5172 0 : struct samr_Connect c;
5173 :
5174 66 : c = (struct samr_Connect) {
5175 : .in.system_name = NULL,
5176 66 : .in.access_mask = r->in.access_mask,
5177 66 : .out.connect_handle = r->out.connect_handle,
5178 : };
5179 :
5180 66 : return dcesrv_samr_Connect(dce_call, mem_ctx, &c);
5181 : }
5182 :
5183 :
5184 : /*
5185 : samr_Connect5
5186 : */
5187 154 : static NTSTATUS dcesrv_samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5188 : struct samr_Connect5 *r)
5189 : {
5190 0 : struct samr_Connect c;
5191 0 : NTSTATUS status;
5192 :
5193 154 : c = (struct samr_Connect) {
5194 : .in.system_name = NULL,
5195 154 : .in.access_mask = r->in.access_mask,
5196 154 : .out.connect_handle = r->out.connect_handle,
5197 : };
5198 :
5199 154 : status = dcesrv_samr_Connect(dce_call, mem_ctx, &c);
5200 :
5201 154 : r->out.info_out->info1.client_version = SAMR_CONNECT_AFTER_W2K;
5202 154 : r->out.info_out->info1.supported_features = 0;
5203 154 : *r->out.level_out = r->in.level_in;
5204 :
5205 154 : return status;
5206 : }
5207 :
5208 :
5209 : /*
5210 : samr_RidToSid
5211 : */
5212 24 : static NTSTATUS dcesrv_samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5213 : struct samr_RidToSid *r)
5214 : {
5215 0 : struct samr_domain_state *d_state;
5216 0 : struct dcesrv_handle *h;
5217 :
5218 24 : DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
5219 :
5220 24 : d_state = h->data;
5221 :
5222 : /* form the users SID */
5223 24 : *r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
5224 24 : if (!*r->out.sid) {
5225 0 : return NT_STATUS_NO_MEMORY;
5226 : }
5227 :
5228 24 : return NT_STATUS_OK;
5229 : }
5230 :
5231 :
5232 : /*
5233 : samr_SetDsrmPassword
5234 : */
5235 0 : static NTSTATUS dcesrv_samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
5236 : struct samr_SetDsrmPassword *r)
5237 : {
5238 0 : DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
5239 : }
5240 :
5241 :
5242 : /*
5243 : samr_ValidatePassword
5244 :
5245 : For now the call checks the password complexity (if active) and the minimum
5246 : password length on level 2 and 3. Level 1 is ignored for now.
5247 : */
5248 5 : static NTSTATUS dcesrv_samr_ValidatePassword(struct dcesrv_call_state *dce_call,
5249 : TALLOC_CTX *mem_ctx,
5250 : struct samr_ValidatePassword *r)
5251 : {
5252 5 : struct samr_GetDomPwInfo r2 = {};
5253 5 : struct samr_PwInfo pwInfo = {};
5254 5 : const char *account = NULL;
5255 0 : DATA_BLOB password;
5256 0 : enum samr_ValidationStatus res;
5257 0 : NTSTATUS status;
5258 0 : enum dcerpc_transport_t transport =
5259 5 : dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description);
5260 5 : enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
5261 :
5262 5 : if (transport != NCACN_IP_TCP && transport != NCALRPC) {
5263 0 : DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
5264 : }
5265 :
5266 5 : dcesrv_call_auth_info(dce_call, NULL, &auth_level);
5267 5 : if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
5268 2 : DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED);
5269 : }
5270 :
5271 3 : (*r->out.rep) = talloc_zero(mem_ctx, union samr_ValidatePasswordRep);
5272 :
5273 3 : r2 = (struct samr_GetDomPwInfo) {
5274 : .in.domain_name = NULL,
5275 : .out.info = &pwInfo,
5276 : };
5277 :
5278 3 : status = dcesrv_samr_GetDomPwInfo(dce_call, mem_ctx, &r2);
5279 3 : if (!NT_STATUS_IS_OK(status)) {
5280 0 : return status;
5281 : }
5282 :
5283 3 : switch (r->in.level) {
5284 0 : case NetValidateAuthentication:
5285 : /* we don't support this yet */
5286 0 : return NT_STATUS_NOT_SUPPORTED;
5287 0 : break;
5288 0 : case NetValidatePasswordChange:
5289 0 : account = r->in.req->req2.account.string;
5290 0 : password = data_blob_const(r->in.req->req2.password.string,
5291 0 : r->in.req->req2.password.length);
5292 0 : res = samdb_check_password(mem_ctx,
5293 0 : dce_call->conn->dce_ctx->lp_ctx,
5294 : account,
5295 : NULL, /* userPrincipalName */
5296 : NULL, /* displayName/full_name */
5297 : &password,
5298 : pwInfo.password_properties,
5299 0 : pwInfo.min_password_length);
5300 0 : (*r->out.rep)->ctr2.status = res;
5301 0 : break;
5302 3 : case NetValidatePasswordReset:
5303 3 : account = r->in.req->req3.account.string;
5304 3 : password = data_blob_const(r->in.req->req3.password.string,
5305 3 : r->in.req->req3.password.length);
5306 3 : res = samdb_check_password(mem_ctx,
5307 3 : dce_call->conn->dce_ctx->lp_ctx,
5308 : account,
5309 : NULL, /* userPrincipalName */
5310 : NULL, /* displayName/full_name */
5311 : &password,
5312 : pwInfo.password_properties,
5313 3 : pwInfo.min_password_length);
5314 3 : (*r->out.rep)->ctr3.status = res;
5315 3 : break;
5316 0 : default:
5317 0 : return NT_STATUS_INVALID_INFO_CLASS;
5318 : break;
5319 : }
5320 :
5321 3 : return NT_STATUS_OK;
5322 : }
5323 :
5324 0 : static void dcesrv_samr_Opnum68NotUsedOnWire(struct dcesrv_call_state *dce_call,
5325 : TALLOC_CTX *mem_ctx,
5326 : struct samr_Opnum68NotUsedOnWire *r)
5327 : {
5328 0 : DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
5329 : }
5330 :
5331 0 : static void dcesrv_samr_Opnum69NotUsedOnWire(struct dcesrv_call_state *dce_call,
5332 : TALLOC_CTX *mem_ctx,
5333 : struct samr_Opnum69NotUsedOnWire *r)
5334 : {
5335 0 : DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
5336 : }
5337 :
5338 0 : static void dcesrv_samr_Opnum70NotUsedOnWire(struct dcesrv_call_state *dce_call,
5339 : TALLOC_CTX *mem_ctx,
5340 : struct samr_Opnum70NotUsedOnWire *r)
5341 : {
5342 0 : DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
5343 : }
5344 :
5345 0 : static void dcesrv_samr_Opnum71NotUsedOnWire(struct dcesrv_call_state *dce_call,
5346 : TALLOC_CTX *mem_ctx,
5347 : struct samr_Opnum71NotUsedOnWire *r)
5348 : {
5349 0 : DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
5350 : }
5351 :
5352 0 : static void dcesrv_samr_Opnum72NotUsedOnWire(struct dcesrv_call_state *dce_call,
5353 : TALLOC_CTX *mem_ctx,
5354 : struct samr_Opnum72NotUsedOnWire *r)
5355 : {
5356 0 : DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
5357 : }
5358 :
5359 : /* include the generated boilerplate */
5360 : #include "librpc/gen_ndr/ndr_samr_s.c"
|