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