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