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
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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 "lib/ldb/include/ldb.h"
32 #include "lib/ldb/include/ldb_errors.h"
33 #include "dsdb/common/flags.h"
34 #include "dsdb/samdb/samdb.h"
35 #include "libcli/ldap/ldap.h"
36 #include "libcli/security/security.h"
37 #include "rpc_server/samr/proto.h"
38 #include "db_wrap.h"
39
40 /* these query macros make samr_Query[User|Group]Info a bit easier to read */
41
42 #define QUERY_STRING(msg, field, attr) \
43 r->out.info->field = samdb_result_string(msg, attr, "");
44 #define QUERY_UINT(msg, field, attr) \
45 r->out.info->field = samdb_result_uint(msg, attr, 0);
46 #define QUERY_RID(msg, field, attr) \
47 r->out.info->field = samdb_result_rid_from_sid(mem_ctx, msg, attr, 0);
48 #define QUERY_NTTIME(msg, field, attr) \
49 r->out.info->field = samdb_result_nttime(msg, attr, 0);
50 #define QUERY_APASSC(msg, field, attr) \
51 r->out.info->field = samdb_result_allow_password_change(sam_ctx, mem_ctx, \
52 a_state->domain_state->domain_dn, msg, attr);
53 #define QUERY_FPASSC(msg, field, attr) \
54 r->out.info->field = samdb_result_force_password_change(sam_ctx, mem_ctx, \
55 a_state->domain_state->domain_dn, msg);
56 #define QUERY_LHOURS(msg, field, attr) \
57 r->out.info->field = samdb_result_logon_hours(mem_ctx, msg, attr);
58 #define QUERY_AFLAGS(msg, field, attr) \
59 r->out.info->field = samdb_result_acct_flags(msg, attr);
60
61
62 /* these are used to make the Set[User|Group]Info code easier to follow */
63
64 #define SET_STRING(mod, field, attr) do { \
65 if (r->in.info->field == NULL) return NT_STATUS_INVALID_PARAMETER; \
66 if (samdb_msg_add_string(sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
67 return NT_STATUS_NO_MEMORY; \
68 } \
69 } while (0)
70
71 #define SET_UINT(mod, field, attr) do { \
72 if (samdb_msg_add_uint(sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
73 return NT_STATUS_NO_MEMORY; \
74 } \
75 } while (0)
76
77 #define SET_INT64(mod, field, attr) do { \
78 if (samdb_msg_add_int64(sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
79 return NT_STATUS_NO_MEMORY; \
80 } \
81 } while (0)
82
83 #define SET_UINT64(mod, field, attr) do { \
84 if (samdb_msg_add_uint64(sam_ctx, mem_ctx, mod, attr, r->in.info->field) != 0) { \
85 return NT_STATUS_NO_MEMORY; \
86 } \
87 } while (0)
88
89 #define SET_AFLAGS(msg, field, attr) do { \
90 if (samdb_msg_add_acct_flags(sam_ctx, mem_ctx, msg, attr, r->in.info->field) != 0) { \
91 return NT_STATUS_NO_MEMORY; \
92 } \
93 } while (0)
94
95 #define SET_LHOURS(msg, field, attr) do { \
96 if (samdb_msg_add_logon_hours(sam_ctx, mem_ctx, msg, attr, &r->in.info->field) != 0) { \
97 return NT_STATUS_NO_MEMORY; \
98 } \
99 } while (0)
100
101
102 /*
103 samr_Connect
104
105 create a connection to the SAM database
106 */
samr_Connect(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_Connect * r)107 static NTSTATUS samr_Connect(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
108 struct samr_Connect *r)
109 {
110 struct samr_connect_state *c_state;
111 struct dcesrv_handle *handle;
112
113 ZERO_STRUCTP(r->out.connect_handle);
114
115 c_state = talloc(dce_call->conn, struct samr_connect_state);
116 if (!c_state) {
117 return NT_STATUS_NO_MEMORY;
118 }
119
120 /* make sure the sam database is accessible */
121 c_state->sam_ctx = samdb_connect(c_state, dce_call->conn->auth_state.session_info);
122 if (c_state->sam_ctx == NULL) {
123 talloc_free(c_state);
124 return NT_STATUS_INVALID_SYSTEM_SERVICE;
125 }
126
127
128 handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_CONNECT);
129 if (!handle) {
130 talloc_free(c_state);
131 return NT_STATUS_NO_MEMORY;
132 }
133
134 handle->data = talloc_steal(handle, c_state);
135
136 c_state->access_mask = r->in.access_mask;
137 *r->out.connect_handle = handle->wire_handle;
138
139 return NT_STATUS_OK;
140 }
141
142
143 /*
144 samr_Close
145 */
samr_Close(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_Close * r)146 static NTSTATUS samr_Close(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
147 struct samr_Close *r)
148 {
149 struct dcesrv_handle *h;
150
151 *r->out.handle = *r->in.handle;
152
153 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
154
155 talloc_free(h);
156
157 ZERO_STRUCTP(r->out.handle);
158
159 return NT_STATUS_OK;
160 }
161
162
163 /*
164 samr_SetSecurity
165 */
samr_SetSecurity(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_SetSecurity * r)166 static NTSTATUS samr_SetSecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
167 struct samr_SetSecurity *r)
168 {
169 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
170 }
171
172
173 /*
174 samr_QuerySecurity
175 */
samr_QuerySecurity(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_QuerySecurity * r)176 static NTSTATUS samr_QuerySecurity(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
177 struct samr_QuerySecurity *r)
178 {
179 struct dcesrv_handle *h;
180 struct sec_desc_buf *sd;
181
182 r->out.sdbuf = NULL;
183
184 DCESRV_PULL_HANDLE(h, r->in.handle, DCESRV_HANDLE_ANY);
185
186 sd = talloc(mem_ctx, struct sec_desc_buf);
187 if (sd == NULL) {
188 return NT_STATUS_NO_MEMORY;
189 }
190
191 sd->sd = samdb_default_security_descriptor(mem_ctx);
192
193 r->out.sdbuf = sd;
194
195 return NT_STATUS_OK;
196 }
197
198
199 /*
200 samr_Shutdown
201
202 we refuse this operation completely. If a admin wants to shutdown samr
203 in Samba then they should use the samba admin tools to disable the samr pipe
204 */
samr_Shutdown(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_Shutdown * r)205 static NTSTATUS samr_Shutdown(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
206 struct samr_Shutdown *r)
207 {
208 return NT_STATUS_ACCESS_DENIED;
209 }
210
211
212 /*
213 samr_LookupDomain
214
215 this maps from a domain name to a SID
216 */
samr_LookupDomain(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_LookupDomain * r)217 static NTSTATUS samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
218 struct samr_LookupDomain *r)
219 {
220 struct samr_connect_state *c_state;
221 struct dcesrv_handle *h;
222 struct dom_sid *sid;
223 const char * const dom_attrs[] = { "objectSid", NULL};
224 const char * const ref_attrs[] = { "ncName", NULL};
225 struct ldb_message **dom_msgs;
226 struct ldb_message **ref_msgs;
227 int ret;
228 struct ldb_dn *partitions_basedn;
229
230 r->out.sid = NULL;
231
232 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
233
234 c_state = h->data;
235
236 if (r->in.domain_name->string == NULL) {
237 return NT_STATUS_INVALID_PARAMETER;
238 }
239
240 partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx);
241
242 if (strcasecmp(r->in.domain_name->string, "BUILTIN") == 0) {
243 ret = gendb_search(c_state->sam_ctx,
244 mem_ctx, NULL, &dom_msgs, dom_attrs,
245 "(objectClass=builtinDomain)");
246 } else {
247 ret = gendb_search(c_state->sam_ctx,
248 mem_ctx, partitions_basedn, &ref_msgs, ref_attrs,
249 "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
250 ldb_binary_encode_string(mem_ctx, r->in.domain_name->string));
251 if (ret != 1) {
252 return NT_STATUS_NO_SUCH_DOMAIN;
253 }
254
255 ret = gendb_search_dn(c_state->sam_ctx, mem_ctx,
256 samdb_result_dn(c_state->sam_ctx, mem_ctx,
257 ref_msgs[0], "ncName", NULL),
258 &dom_msgs, dom_attrs);
259 }
260
261 if (ret != 1) {
262 return NT_STATUS_NO_SUCH_DOMAIN;
263 }
264
265 sid = samdb_result_dom_sid(mem_ctx, dom_msgs[0],
266 "objectSid");
267
268 if (sid == NULL) {
269 return NT_STATUS_NO_SUCH_DOMAIN;
270 }
271
272 r->out.sid = sid;
273
274 return NT_STATUS_OK;
275 }
276
277
278 /*
279 samr_EnumDomains
280
281 list the domains in the SAM
282 */
samr_EnumDomains(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_EnumDomains * r)283 static NTSTATUS samr_EnumDomains(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
284 struct samr_EnumDomains *r)
285 {
286 struct samr_connect_state *c_state;
287 struct dcesrv_handle *h;
288 struct samr_SamArray *array;
289 int count, i, start_i;
290 const char * const dom_attrs[] = { "cn", NULL};
291 const char * const ref_attrs[] = { "nETBIOSName", NULL};
292 struct ldb_message **dom_msgs;
293 struct ldb_message **ref_msgs;
294 struct ldb_dn *partitions_basedn;
295
296 *r->out.resume_handle = 0;
297 r->out.sam = NULL;
298 r->out.num_entries = 0;
299
300 DCESRV_PULL_HANDLE(h, r->in.connect_handle, SAMR_HANDLE_CONNECT);
301
302 c_state = h->data;
303
304 partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx);
305
306 count = gendb_search(c_state->sam_ctx,
307 mem_ctx, NULL, &dom_msgs, dom_attrs,
308 "(objectClass=domain)");
309 if (count == -1) {
310 DEBUG(0,("samdb: no domains found in EnumDomains\n"));
311 return NT_STATUS_INTERNAL_DB_CORRUPTION;
312 }
313
314 *r->out.resume_handle = count;
315
316 start_i = *r->in.resume_handle;
317
318 if (start_i >= count) {
319 /* search past end of list is not an error for this call */
320 return NT_STATUS_OK;
321 }
322
323 array = talloc(mem_ctx, struct samr_SamArray);
324 if (array == NULL) {
325 return NT_STATUS_NO_MEMORY;
326 }
327
328 array->count = 0;
329 array->entries = NULL;
330
331 array->entries = talloc_array(mem_ctx, struct samr_SamEntry, count - start_i);
332 if (array->entries == NULL) {
333 return NT_STATUS_NO_MEMORY;
334 }
335
336 for (i=0;i<count-start_i;i++) {
337 int ret;
338 array->entries[i].idx = start_i + i;
339 /* try and find the domain */
340 ret = gendb_search(c_state->sam_ctx, mem_ctx, partitions_basedn,
341 &ref_msgs, ref_attrs,
342 "(&(objectClass=crossRef)(ncName=%s))",
343 ldb_dn_get_linearized(dom_msgs[i]->dn));
344 if (ret == 1) {
345 array->entries[i].name.string = samdb_result_string(ref_msgs[0], "nETBIOSName", NULL);
346 } else {
347 array->entries[i].name.string = samdb_result_string(dom_msgs[i], "cn", NULL);
348 }
349 }
350
351 r->out.sam = array;
352 r->out.num_entries = i;
353 array->count = r->out.num_entries;
354
355 return NT_STATUS_OK;
356 }
357
358
359 /*
360 samr_OpenDomain
361 */
samr_OpenDomain(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_OpenDomain * r)362 static NTSTATUS samr_OpenDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
363 struct samr_OpenDomain *r)
364 {
365 struct dcesrv_handle *h_conn, *h_domain;
366 const char *domain_name;
367 struct samr_connect_state *c_state;
368 struct samr_domain_state *d_state;
369 const char * const dom_attrs[] = { "cn", NULL};
370 const char * const ref_attrs[] = { "nETBIOSName", NULL};
371 struct ldb_message **dom_msgs;
372 struct ldb_message **ref_msgs;
373 int ret;
374 struct ldb_dn *partitions_basedn;
375
376 ZERO_STRUCTP(r->out.domain_handle);
377
378 DCESRV_PULL_HANDLE(h_conn, r->in.connect_handle, SAMR_HANDLE_CONNECT);
379
380 c_state = h_conn->data;
381
382 if (r->in.sid == NULL) {
383 return NT_STATUS_INVALID_PARAMETER;
384 }
385
386 partitions_basedn = samdb_partitions_dn(c_state->sam_ctx, mem_ctx);
387
388 ret = gendb_search(c_state->sam_ctx,
389 mem_ctx, NULL, &dom_msgs, dom_attrs,
390 "(&(objectSid=%s)(&(|(objectclass=domain)(objectClass=builtinDomain))))",
391 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
392 if (ret == 0) {
393 return NT_STATUS_NO_SUCH_DOMAIN;
394 } else if (ret > 1) {
395 return NT_STATUS_INTERNAL_DB_CORRUPTION;
396 } else if (ret == -1) {
397 DEBUG(1, ("Failed to open domain %s: %s\n", dom_sid_string(mem_ctx, r->in.sid), ldb_errstring(c_state->sam_ctx)));
398 } else {
399 ret = gendb_search(c_state->sam_ctx,
400 mem_ctx, partitions_basedn, &ref_msgs, ref_attrs,
401 "(&(&(nETBIOSName=*)(objectclass=crossRef))(ncName=%s))",
402 ldb_dn_get_linearized(dom_msgs[0]->dn));
403 if (ret == 0) {
404 domain_name = ldb_msg_find_attr_as_string(dom_msgs[0], "cn", NULL);
405 if (domain_name == NULL) {
406 return NT_STATUS_NO_SUCH_DOMAIN;
407 }
408 } else if (ret == 1) {
409
410 domain_name = ldb_msg_find_attr_as_string(ref_msgs[0], "nETBIOSName", NULL);
411 if (domain_name == NULL) {
412 return NT_STATUS_NO_SUCH_DOMAIN;
413 }
414 } else {
415 return NT_STATUS_NO_SUCH_DOMAIN;
416 }
417 }
418
419 d_state = talloc(c_state, struct samr_domain_state);
420 if (!d_state) {
421 return NT_STATUS_NO_MEMORY;
422 }
423
424 d_state->connect_state = talloc_reference(d_state, c_state);
425 d_state->sam_ctx = c_state->sam_ctx;
426 d_state->domain_sid = dom_sid_dup(d_state, r->in.sid);
427 d_state->domain_name = talloc_strdup(d_state, domain_name);
428 d_state->domain_dn = ldb_dn_copy(d_state, dom_msgs[0]->dn);
429 if (!d_state->domain_sid || !d_state->domain_name || !d_state->domain_dn) {
430 talloc_free(d_state);
431 return NT_STATUS_NO_MEMORY;
432 }
433 d_state->access_mask = r->in.access_mask;
434
435 h_domain = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_DOMAIN);
436 if (!h_domain) {
437 talloc_free(d_state);
438 return NT_STATUS_NO_MEMORY;
439 }
440
441 h_domain->data = talloc_steal(h_domain, d_state);
442
443 *r->out.domain_handle = h_domain->wire_handle;
444
445 return NT_STATUS_OK;
446 }
447
448 /*
449 return DomInfo1
450 */
samr_info_DomInfo1(struct samr_domain_state * state,TALLOC_CTX * mem_ctx,struct ldb_message ** dom_msgs,struct samr_DomInfo1 * info)451 static NTSTATUS samr_info_DomInfo1(struct samr_domain_state *state,
452 TALLOC_CTX *mem_ctx,
453 struct ldb_message **dom_msgs,
454 struct samr_DomInfo1 *info)
455 {
456 info->min_password_length =
457 samdb_result_uint(dom_msgs[0], "minPwdLength", 0);
458 info->password_history_length =
459 samdb_result_uint(dom_msgs[0], "pwdHistoryLength", 0);
460 info->password_properties =
461 samdb_result_uint(dom_msgs[0], "pwdProperties", 0);
462 info->max_password_age =
463 samdb_result_int64(dom_msgs[0], "maxPwdAge", 0);
464 info->min_password_age =
465 samdb_result_int64(dom_msgs[0], "minPwdAge", 0);
466
467 return NT_STATUS_OK;
468 }
469
470 /*
471 return DomInfo2
472 */
samr_info_DomInfo2(struct samr_domain_state * state,TALLOC_CTX * mem_ctx,struct ldb_message ** dom_msgs,struct samr_DomInfo2 * info)473 static NTSTATUS samr_info_DomInfo2(struct samr_domain_state *state, TALLOC_CTX *mem_ctx,
474 struct ldb_message **dom_msgs,
475 struct samr_DomInfo2 *info)
476 {
477 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
478 0x8000000000000000LL);
479
480 info->comment.string = samdb_result_string(dom_msgs[0], "comment", NULL);
481 info->domain_name.string = state->domain_name;
482
483 /* FIXME: We should find the name of the real PDC emulator */
484 info->primary.string = lp_netbios_name();
485 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
486 0);
487
488 info->role = lp_server_role();
489
490 /* TODO: Should these filter on SID, to avoid counting BUILTIN? */
491 info->num_users = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
492 "(objectClass=user)");
493 info->num_groups = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
494 "(&(objectClass=group)(sAMAccountType=%u))",
495 ATYPE_GLOBAL_GROUP);
496 info->num_aliases = samdb_search_count(state->sam_ctx, mem_ctx, state->domain_dn,
497 "(&(objectClass=group)(sAMAccountType=%u))",
498 ATYPE_LOCAL_GROUP);
499
500 return NT_STATUS_OK;
501 }
502
503 /*
504 return DomInfo3
505 */
samr_info_DomInfo3(struct samr_domain_state * state,TALLOC_CTX * mem_ctx,struct ldb_message ** dom_msgs,struct samr_DomInfo3 * info)506 static NTSTATUS samr_info_DomInfo3(struct samr_domain_state *state,
507 TALLOC_CTX *mem_ctx,
508 struct ldb_message **dom_msgs,
509 struct samr_DomInfo3 *info)
510 {
511 info->force_logoff_time = ldb_msg_find_attr_as_uint64(dom_msgs[0], "forceLogoff",
512 0x8000000000000000LL);
513
514 return NT_STATUS_OK;
515 }
516
517 /*
518 return DomInfo4
519 */
samr_info_DomInfo4(struct samr_domain_state * state,TALLOC_CTX * mem_ctx,struct ldb_message ** dom_msgs,struct samr_DomInfo4 * info)520 static NTSTATUS samr_info_DomInfo4(struct samr_domain_state *state,
521 TALLOC_CTX *mem_ctx,
522 struct ldb_message **dom_msgs,
523 struct samr_DomInfo4 *info)
524 {
525 info->comment.string = samdb_result_string(dom_msgs[0], "comment", NULL);
526
527 return NT_STATUS_OK;
528 }
529
530 /*
531 return DomInfo5
532 */
samr_info_DomInfo5(struct samr_domain_state * state,TALLOC_CTX * mem_ctx,struct ldb_message ** dom_msgs,struct samr_DomInfo5 * info)533 static NTSTATUS samr_info_DomInfo5(struct samr_domain_state *state,
534 TALLOC_CTX *mem_ctx,
535 struct ldb_message **dom_msgs,
536 struct samr_DomInfo5 *info)
537 {
538 info->domain_name.string = state->domain_name;
539
540 return NT_STATUS_OK;
541 }
542
543 /*
544 return DomInfo6
545 */
samr_info_DomInfo6(struct samr_domain_state * state,TALLOC_CTX * mem_ctx,struct ldb_message ** dom_msgs,struct samr_DomInfo6 * info)546 static NTSTATUS samr_info_DomInfo6(struct samr_domain_state *state,
547 TALLOC_CTX *mem_ctx,
548 struct ldb_message **dom_msgs,
549 struct samr_DomInfo6 *info)
550 {
551
552 /* FIXME: We should find the name of the real PDC emulator */
553 info->primary.string = lp_netbios_name();
554
555 return NT_STATUS_OK;
556 }
557
558 /*
559 return DomInfo7
560 */
samr_info_DomInfo7(struct samr_domain_state * state,TALLOC_CTX * mem_ctx,struct ldb_message ** dom_msgs,struct samr_DomInfo7 * info)561 static NTSTATUS samr_info_DomInfo7(struct samr_domain_state *state,
562 TALLOC_CTX *mem_ctx,
563 struct ldb_message **dom_msgs,
564 struct samr_DomInfo7 *info)
565 {
566 info->role = lp_server_role();
567
568 return NT_STATUS_OK;
569 }
570
571 /*
572 return DomInfo8
573 */
samr_info_DomInfo8(struct samr_domain_state * state,TALLOC_CTX * mem_ctx,struct ldb_message ** dom_msgs,struct samr_DomInfo8 * info)574 static NTSTATUS samr_info_DomInfo8(struct samr_domain_state *state,
575 TALLOC_CTX *mem_ctx,
576 struct ldb_message **dom_msgs,
577 struct samr_DomInfo8 *info)
578 {
579 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
580 time(NULL));
581
582 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
583 0x0LL);
584
585 return NT_STATUS_OK;
586 }
587
588 /*
589 return DomInfo9
590 */
samr_info_DomInfo9(struct samr_domain_state * state,TALLOC_CTX * mem_ctx,struct ldb_message ** dom_msgs,struct samr_DomInfo9 * info)591 static NTSTATUS samr_info_DomInfo9(struct samr_domain_state *state,
592 TALLOC_CTX *mem_ctx,
593 struct ldb_message **dom_msgs,
594 struct samr_DomInfo9 *info)
595 {
596 info->unknown = 1;
597
598 return NT_STATUS_OK;
599 }
600
601 /*
602 return DomInfo11
603 */
samr_info_DomInfo11(struct samr_domain_state * state,TALLOC_CTX * mem_ctx,struct ldb_message ** dom_msgs,struct samr_DomInfo11 * info)604 static NTSTATUS samr_info_DomInfo11(struct samr_domain_state *state,
605 TALLOC_CTX *mem_ctx,
606 struct ldb_message **dom_msgs,
607 struct samr_DomInfo11 *info)
608 {
609 NTSTATUS status;
610 status = samr_info_DomInfo2(state, mem_ctx, dom_msgs, &info->info2);
611 if (!NT_STATUS_IS_OK(status)) {
612 return status;
613 }
614
615 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
616 -18000000000LL);
617 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
618 -18000000000LL);
619 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
620
621 return NT_STATUS_OK;
622 }
623
624 /*
625 return DomInfo12
626 */
samr_info_DomInfo12(struct samr_domain_state * state,TALLOC_CTX * mem_ctx,struct ldb_message ** dom_msgs,struct samr_DomInfo12 * info)627 static NTSTATUS samr_info_DomInfo12(struct samr_domain_state *state,
628 TALLOC_CTX *mem_ctx,
629 struct ldb_message **dom_msgs,
630 struct samr_DomInfo12 *info)
631 {
632 info->lockout_duration = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutDuration",
633 -18000000000LL);
634 info->lockout_window = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockOutObservationWindow",
635 -18000000000LL);
636 info->lockout_threshold = ldb_msg_find_attr_as_int64(dom_msgs[0], "lockoutThreshold", 0);
637
638 return NT_STATUS_OK;
639 }
640
641 /*
642 return DomInfo13
643 */
samr_info_DomInfo13(struct samr_domain_state * state,TALLOC_CTX * mem_ctx,struct ldb_message ** dom_msgs,struct samr_DomInfo13 * info)644 static NTSTATUS samr_info_DomInfo13(struct samr_domain_state *state,
645 TALLOC_CTX *mem_ctx,
646 struct ldb_message **dom_msgs,
647 struct samr_DomInfo13 *info)
648 {
649 info->sequence_num = ldb_msg_find_attr_as_uint64(dom_msgs[0], "modifiedCount",
650 time(NULL));
651
652 info->domain_create_time = ldb_msg_find_attr_as_uint(dom_msgs[0], "creationTime",
653 0x0LL);
654
655 info->unknown1 = 0;
656 info->unknown2 = 0;
657
658 return NT_STATUS_OK;
659 }
660
661 /*
662 samr_QueryDomainInfo
663 */
samr_QueryDomainInfo(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_QueryDomainInfo * r)664 static NTSTATUS samr_QueryDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
665 struct samr_QueryDomainInfo *r)
666 {
667 struct dcesrv_handle *h;
668 struct samr_domain_state *d_state;
669
670 struct ldb_message **dom_msgs;
671 const char * const *attrs = NULL;
672
673 r->out.info = NULL;
674
675 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
676
677 d_state = h->data;
678
679 r->out.info = talloc(mem_ctx, union samr_DomainInfo);
680 if (!r->out.info) {
681 return NT_STATUS_NO_MEMORY;
682 }
683
684 switch (r->in.level) {
685 case 1:
686 {
687 static const char * const attrs2[] = { "minPwdLength", "pwdHistoryLength",
688 "pwdProperties", "maxPwdAge",
689 "minPwdAge", NULL };
690 attrs = attrs2;
691 break;
692 }
693 case 2:
694 {
695 static const char * const attrs2[] = {"forceLogoff",
696 "comment",
697 "modifiedCount",
698 NULL};
699 attrs = attrs2;
700 break;
701 }
702 case 3:
703 {
704 static const char * const attrs2[] = {"forceLogoff",
705 NULL};
706 attrs = attrs2;
707 break;
708 }
709 case 4:
710 {
711 static const char * const attrs2[] = {"comment",
712 NULL};
713 attrs = attrs2;
714 break;
715 }
716 case 5:
717 case 6:
718 case 7:
719 {
720 attrs = NULL;
721 break;
722 }
723 case 8:
724 {
725 static const char * const attrs2[] = { "modifiedCount",
726 "creationTime",
727 NULL };
728 attrs = attrs2;
729 break;
730 }
731 case 9:
732 attrs = NULL;
733 break;
734 case 11:
735 {
736 static const char * const attrs2[] = { "comment", "forceLogoff",
737 "modifiedCount",
738 "lockoutDuration",
739 "lockOutObservationWindow",
740 "lockoutThreshold",
741 NULL};
742 attrs = attrs2;
743 break;
744 }
745 case 12:
746 {
747 static const char * const attrs2[] = { "lockoutDuration",
748 "lockOutObservationWindow",
749 "lockoutThreshold",
750 NULL};
751 attrs = attrs2;
752 break;
753 }
754 case 13:
755 {
756 static const char * const attrs2[] = { "modifiedCount",
757 "creationTime",
758 NULL };
759 attrs = attrs2;
760 break;
761 }
762 }
763
764 /* some levels don't need a search */
765 if (attrs) {
766 int ret;
767 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
768 d_state->domain_dn, &dom_msgs, attrs);
769 if (ret != 1) {
770 return NT_STATUS_INTERNAL_DB_CORRUPTION;
771 }
772 }
773
774 ZERO_STRUCTP(r->out.info);
775
776 switch (r->in.level) {
777 case 1:
778 return samr_info_DomInfo1(d_state, mem_ctx, dom_msgs,
779 &r->out.info->info1);
780 case 2:
781 return samr_info_DomInfo2(d_state, mem_ctx, dom_msgs,
782 &r->out.info->info2);
783 case 3:
784 return samr_info_DomInfo3(d_state, mem_ctx, dom_msgs,
785 &r->out.info->info3);
786 case 4:
787 return samr_info_DomInfo4(d_state, mem_ctx, dom_msgs,
788 &r->out.info->info4);
789 case 5:
790 return samr_info_DomInfo5(d_state, mem_ctx, dom_msgs,
791 &r->out.info->info5);
792 case 6:
793 return samr_info_DomInfo6(d_state, mem_ctx, dom_msgs,
794 &r->out.info->info6);
795 case 7:
796 return samr_info_DomInfo7(d_state, mem_ctx, dom_msgs,
797 &r->out.info->info7);
798 case 8:
799 return samr_info_DomInfo8(d_state, mem_ctx, dom_msgs,
800 &r->out.info->info8);
801 case 9:
802 return samr_info_DomInfo9(d_state, mem_ctx, dom_msgs,
803 &r->out.info->info9);
804 case 11:
805 return samr_info_DomInfo11(d_state, mem_ctx, dom_msgs,
806 &r->out.info->info11);
807 case 12:
808 return samr_info_DomInfo12(d_state, mem_ctx, dom_msgs,
809 &r->out.info->info12);
810 case 13:
811 return samr_info_DomInfo13(d_state, mem_ctx, dom_msgs,
812 &r->out.info->info13);
813 }
814
815 return NT_STATUS_INVALID_INFO_CLASS;
816 }
817
818
819 /*
820 samr_SetDomainInfo
821 */
samr_SetDomainInfo(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_SetDomainInfo * r)822 static NTSTATUS samr_SetDomainInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
823 struct samr_SetDomainInfo *r)
824 {
825 struct dcesrv_handle *h;
826 struct samr_domain_state *d_state;
827 struct ldb_message *msg;
828 int ret;
829 struct ldb_context *sam_ctx;
830
831 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
832
833 d_state = h->data;
834 sam_ctx = d_state->sam_ctx;
835
836 msg = ldb_msg_new(mem_ctx);
837 if (msg == NULL) {
838 return NT_STATUS_NO_MEMORY;
839 }
840
841 msg->dn = talloc_reference(mem_ctx, d_state->domain_dn);
842 if (!msg->dn) {
843 return NT_STATUS_NO_MEMORY;
844 }
845
846 switch (r->in.level) {
847 case 1:
848 SET_UINT (msg, info1.min_password_length, "minPwdLength");
849 SET_UINT (msg, info1.password_history_length, "pwdHistoryLength");
850 SET_UINT (msg, info1.password_properties, "pwdProperties");
851 SET_INT64 (msg, info1.max_password_age, "maxPwdAge");
852 SET_INT64 (msg, info1.min_password_age, "minPwdAge");
853 break;
854 case 3:
855 SET_UINT64 (msg, info3.force_logoff_time, "forceLogoff");
856 break;
857 case 4:
858 SET_STRING(msg, info4.comment.string, "comment");
859 break;
860
861 case 6:
862 case 7:
863 case 9:
864 /* No op, we don't know where to set these */
865 return NT_STATUS_OK;
866
867 case 12:
868
869 SET_INT64 (msg, info12.lockout_duration, "lockoutDuration");
870 SET_INT64 (msg, info12.lockout_window, "lockOutObservationWindow");
871 SET_INT64 (msg, info12.lockout_threshold, "lockoutThreshold");
872 break;
873
874 default:
875 /* many info classes are not valid for SetDomainInfo */
876 return NT_STATUS_INVALID_INFO_CLASS;
877 }
878
879 /* modify the samdb record */
880 ret = samdb_replace(sam_ctx, mem_ctx, msg);
881 if (ret != 0) {
882 DEBUG(1,("Failed to modify record %s: %s\n",
883 ldb_dn_get_linearized(d_state->domain_dn),
884 ldb_errstring(sam_ctx)));
885
886 /* we really need samdb.c to return NTSTATUS */
887 return NT_STATUS_UNSUCCESSFUL;
888 }
889
890 return NT_STATUS_OK;
891 }
892
893 /*
894 samr_CreateDomainGroup
895 */
samr_CreateDomainGroup(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_CreateDomainGroup * r)896 static NTSTATUS samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
897 struct samr_CreateDomainGroup *r)
898 {
899 struct samr_domain_state *d_state;
900 struct samr_account_state *a_state;
901 struct dcesrv_handle *h;
902 const char *name;
903 struct ldb_message *msg;
904 struct dom_sid *sid;
905 const char *groupname;
906 struct dcesrv_handle *g_handle;
907 int ret;
908
909 ZERO_STRUCTP(r->out.group_handle);
910 *r->out.rid = 0;
911
912 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
913
914 d_state = h->data;
915
916 groupname = r->in.name->string;
917
918 if (groupname == NULL) {
919 return NT_STATUS_INVALID_PARAMETER;
920 }
921
922 /* check if the group already exists */
923 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
924 "sAMAccountName",
925 "(&(sAMAccountName=%s)(objectclass=group))",
926 ldb_binary_encode_string(mem_ctx, groupname));
927 if (name != NULL) {
928 return NT_STATUS_GROUP_EXISTS;
929 }
930
931 msg = ldb_msg_new(mem_ctx);
932 if (msg == NULL) {
933 return NT_STATUS_NO_MEMORY;
934 }
935
936 /* add core elements to the ldb_message for the user */
937 msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
938 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", groupname);
939 if (!msg->dn) {
940 return NT_STATUS_NO_MEMORY;
941 }
942 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", groupname);
943 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
944
945 /* create the group */
946 ret = samdb_add(d_state->sam_ctx, mem_ctx, msg);
947 switch (ret) {
948 case LDB_SUCCESS:
949 break;
950 case LDB_ERR_ENTRY_ALREADY_EXISTS:
951 DEBUG(0,("Failed to create group record %s: %s\n",
952 ldb_dn_get_linearized(msg->dn),
953 ldb_errstring(d_state->sam_ctx)));
954 return NT_STATUS_GROUP_EXISTS;
955 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
956 DEBUG(0,("Failed to create group record %s: %s\n",
957 ldb_dn_get_linearized(msg->dn),
958 ldb_errstring(d_state->sam_ctx)));
959 return NT_STATUS_ACCESS_DENIED;
960 default:
961 DEBUG(0,("Failed to create group record %s: %s\n",
962 ldb_dn_get_linearized(msg->dn),
963 ldb_errstring(d_state->sam_ctx)));
964 return NT_STATUS_INTERNAL_DB_CORRUPTION;
965 }
966
967 a_state = talloc(d_state, struct samr_account_state);
968 if (!a_state) {
969 return NT_STATUS_NO_MEMORY;
970 }
971 a_state->sam_ctx = d_state->sam_ctx;
972 a_state->access_mask = r->in.access_mask;
973 a_state->domain_state = talloc_reference(a_state, d_state);
974 a_state->account_dn = talloc_steal(a_state, msg->dn);
975
976 /* retrieve the sid for the group just created */
977 sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
978 msg->dn, "objectSid", NULL);
979 if (sid == NULL) {
980 return NT_STATUS_UNSUCCESSFUL;
981 }
982
983 a_state->account_name = talloc_strdup(a_state, groupname);
984 if (!a_state->account_name) {
985 return NT_STATUS_NO_MEMORY;
986 }
987
988 /* create the policy handle */
989 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
990 if (!g_handle) {
991 return NT_STATUS_NO_MEMORY;
992 }
993
994 g_handle->data = talloc_steal(g_handle, a_state);
995
996 *r->out.group_handle = g_handle->wire_handle;
997 *r->out.rid = sid->sub_auths[sid->num_auths-1];
998
999 return NT_STATUS_OK;
1000 }
1001
1002
1003 /*
1004 comparison function for sorting SamEntry array
1005 */
compare_SamEntry(struct samr_SamEntry * e1,struct samr_SamEntry * e2)1006 static int compare_SamEntry(struct samr_SamEntry *e1, struct samr_SamEntry *e2)
1007 {
1008 return e1->idx - e2->idx;
1009 }
1010
1011 /*
1012 samr_EnumDomainGroups
1013 */
samr_EnumDomainGroups(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_EnumDomainGroups * r)1014 static NTSTATUS samr_EnumDomainGroups(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1015 struct samr_EnumDomainGroups *r)
1016 {
1017 struct dcesrv_handle *h;
1018 struct samr_domain_state *d_state;
1019 struct ldb_message **res;
1020 int ldb_cnt, count, i, first;
1021 struct samr_SamEntry *entries;
1022 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1023
1024 *r->out.resume_handle = 0;
1025 r->out.sam = NULL;
1026 r->out.num_entries = 0;
1027
1028 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1029
1030 d_state = h->data;
1031
1032 /* search for all domain groups in this domain. This could possibly be
1033 cached and resumed based on resume_key */
1034 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1035 d_state->domain_dn, &res, attrs,
1036 d_state->domain_sid,
1037 "(&(grouptype=%d)(objectclass=group))",
1038 GTYPE_SECURITY_GLOBAL_GROUP);
1039 if (ldb_cnt == -1) {
1040 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1041 }
1042 if (ldb_cnt == 0 || r->in.max_size == 0) {
1043 return NT_STATUS_OK;
1044 }
1045
1046 /* convert to SamEntry format */
1047 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1048 if (!entries) {
1049 return NT_STATUS_NO_MEMORY;
1050 }
1051
1052 count = 0;
1053
1054 for (i=0;i<ldb_cnt;i++) {
1055 struct dom_sid *group_sid;
1056
1057 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
1058 "objectSid");
1059 if (group_sid == NULL)
1060 continue;
1061
1062 entries[count].idx =
1063 group_sid->sub_auths[group_sid->num_auths-1];
1064 entries[count].name.string =
1065 samdb_result_string(res[i], "sAMAccountName", "");
1066 count += 1;
1067 }
1068
1069 /* sort the results by rid */
1070 qsort(entries, count, sizeof(struct samr_SamEntry),
1071 (comparison_fn_t)compare_SamEntry);
1072
1073 /* find the first entry to return */
1074 for (first=0;
1075 first<count && entries[first].idx <= *r->in.resume_handle;
1076 first++) ;
1077
1078 if (first == count) {
1079 return NT_STATUS_OK;
1080 }
1081
1082 /* return the rest, limit by max_size. Note that we
1083 use the w2k3 element size value of 54 */
1084 r->out.num_entries = count - first;
1085 r->out.num_entries = MIN(r->out.num_entries,
1086 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1087
1088 r->out.sam = talloc(mem_ctx, struct samr_SamArray);
1089 if (!r->out.sam) {
1090 return NT_STATUS_NO_MEMORY;
1091 }
1092
1093 r->out.sam->entries = entries+first;
1094 r->out.sam->count = r->out.num_entries;
1095
1096 if (r->out.num_entries < count - first) {
1097 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
1098 return STATUS_MORE_ENTRIES;
1099 }
1100
1101 return NT_STATUS_OK;
1102 }
1103
1104
1105 /*
1106 samr_CreateUser2
1107
1108 This call uses transactions to ensure we don't get a new conflicting
1109 user while we are processing this, and to ensure the user either
1110 completly exists, or does not.
1111 */
samr_CreateUser2(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_CreateUser2 * r)1112 static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1113 struct samr_CreateUser2 *r)
1114 {
1115 struct samr_domain_state *d_state;
1116 struct samr_account_state *a_state;
1117 struct dcesrv_handle *h;
1118 const char *name;
1119 struct ldb_message *msg;
1120 struct dom_sid *sid;
1121 const char *account_name;
1122 struct dcesrv_handle *u_handle;
1123 int ret;
1124 const char *container, *obj_class=NULL;
1125 char *cn_name;
1126 int cn_name_len;
1127
1128 const char *attrs[] = {
1129 "objectSid",
1130 "userAccountControl",
1131 NULL
1132 };
1133
1134 uint32_t user_account_control;
1135
1136 struct ldb_message **msgs;
1137
1138 ZERO_STRUCTP(r->out.user_handle);
1139 *r->out.access_granted = 0;
1140 *r->out.rid = 0;
1141
1142 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1143
1144 d_state = h->data;
1145
1146 account_name = r->in.account_name->string;
1147
1148 if (account_name == NULL) {
1149 return NT_STATUS_INVALID_PARAMETER;
1150 }
1151
1152 ret = ldb_transaction_start(d_state->sam_ctx);
1153 if (ret != 0) {
1154 DEBUG(0,("Failed to start a transaction for user creation: %s\n",
1155 ldb_errstring(d_state->sam_ctx)));
1156 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1157 }
1158
1159 /* check if the user already exists */
1160 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1161 "sAMAccountName",
1162 "(&(sAMAccountName=%s)(objectclass=user))",
1163 ldb_binary_encode_string(mem_ctx, account_name));
1164 if (name != NULL) {
1165 ldb_transaction_cancel(d_state->sam_ctx);
1166 return NT_STATUS_USER_EXISTS;
1167 }
1168
1169 msg = ldb_msg_new(mem_ctx);
1170 if (msg == NULL) {
1171 ldb_transaction_cancel(d_state->sam_ctx);
1172 return NT_STATUS_NO_MEMORY;
1173 }
1174
1175 cn_name = talloc_strdup(mem_ctx, account_name);
1176 if (!cn_name) {
1177 ldb_transaction_cancel(d_state->sam_ctx);
1178 return NT_STATUS_NO_MEMORY;
1179 }
1180
1181 cn_name_len = strlen(cn_name);
1182
1183 /* This must be one of these values *only* */
1184 if (r->in.acct_flags == ACB_NORMAL) {
1185 container = "Users";
1186 obj_class = "user";
1187
1188 } else if (r->in.acct_flags == ACB_WSTRUST) {
1189 if (cn_name[cn_name_len - 1] != '$') {
1190 return NT_STATUS_FOOBAR;
1191 }
1192 cn_name[cn_name_len - 1] = '\0';
1193 container = "Computers";
1194 obj_class = "computer";
1195
1196 } else if (r->in.acct_flags == ACB_SVRTRUST) {
1197 if (cn_name[cn_name_len - 1] != '$') {
1198 return NT_STATUS_FOOBAR;
1199 }
1200 cn_name[cn_name_len - 1] = '\0';
1201 container = "Domain Controllers";
1202 obj_class = "computer";
1203
1204 } else if (r->in.acct_flags == ACB_DOMTRUST) {
1205 container = "Users";
1206 obj_class = "user";
1207
1208 } else {
1209 ldb_transaction_cancel(d_state->sam_ctx);
1210 return NT_STATUS_INVALID_PARAMETER;
1211 }
1212
1213 /* add core elements to the ldb_message for the user */
1214 msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1215 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=%s", cn_name, container)) {
1216 ldb_transaction_cancel(d_state->sam_ctx);
1217 return NT_STATUS_FOOBAR;
1218 }
1219
1220 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", account_name);
1221 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", obj_class);
1222
1223 /* Start a transaction, so we can query and do a subsequent atomic modify */
1224
1225 /* create the user */
1226 ret = samdb_add(d_state->sam_ctx, mem_ctx, msg);
1227 switch (ret) {
1228 case LDB_SUCCESS:
1229 break;
1230 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1231 ldb_transaction_cancel(d_state->sam_ctx);
1232 DEBUG(0,("Failed to create user record %s: %s\n",
1233 ldb_dn_get_linearized(msg->dn),
1234 ldb_errstring(d_state->sam_ctx)));
1235 return NT_STATUS_USER_EXISTS;
1236 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1237 ldb_transaction_cancel(d_state->sam_ctx);
1238 DEBUG(0,("Failed to create user record %s: %s\n",
1239 ldb_dn_get_linearized(msg->dn),
1240 ldb_errstring(d_state->sam_ctx)));
1241 return NT_STATUS_ACCESS_DENIED;
1242 default:
1243 ldb_transaction_cancel(d_state->sam_ctx);
1244 DEBUG(0,("Failed to create user record %s: %s\n",
1245 ldb_dn_get_linearized(msg->dn),
1246 ldb_errstring(d_state->sam_ctx)));
1247 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1248 }
1249
1250 a_state = talloc(d_state, struct samr_account_state);
1251 if (!a_state) {
1252 ldb_transaction_cancel(d_state->sam_ctx);
1253 return NT_STATUS_NO_MEMORY;
1254 }
1255 a_state->sam_ctx = d_state->sam_ctx;
1256 a_state->access_mask = r->in.access_mask;
1257 a_state->domain_state = talloc_reference(a_state, d_state);
1258 a_state->account_dn = talloc_steal(a_state, msg->dn);
1259
1260 /* retrieve the sid and account control bits for the user just created */
1261 ret = gendb_search_dn(d_state->sam_ctx, a_state,
1262 msg->dn, &msgs, attrs);
1263
1264 if (ret != 1) {
1265 ldb_transaction_cancel(d_state->sam_ctx);
1266 DEBUG(0,("Apparently we failed to create an account record, as %s now doesn't exist\n",
1267 ldb_dn_get_linearized(msg->dn)));
1268 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1269 }
1270 sid = samdb_result_dom_sid(mem_ctx, msgs[0], "objectSid");
1271 if (sid == NULL) {
1272 ldb_transaction_cancel(d_state->sam_ctx);
1273 DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n",
1274 ldb_dn_get_linearized(msg->dn)));
1275 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1276 }
1277
1278 /* Change the account control to be the correct account type.
1279 * The default is for a workstation account */
1280 user_account_control = samdb_result_uint(msgs[0], "userAccountControl", 0);
1281 user_account_control = (user_account_control &
1282 ~(UF_NORMAL_ACCOUNT |
1283 UF_INTERDOMAIN_TRUST_ACCOUNT |
1284 UF_WORKSTATION_TRUST_ACCOUNT |
1285 UF_SERVER_TRUST_ACCOUNT));
1286 user_account_control |= samdb_acb2uf(r->in.acct_flags);
1287
1288 talloc_free(msg);
1289 msg = ldb_msg_new(mem_ctx);
1290 if (msg == NULL) {
1291 ldb_transaction_cancel(d_state->sam_ctx);
1292 return NT_STATUS_NO_MEMORY;
1293 }
1294
1295 msg->dn = ldb_dn_copy(msg, a_state->account_dn);
1296
1297 if (samdb_msg_add_uint(a_state->sam_ctx, mem_ctx, msg,
1298 "userAccountControl",
1299 user_account_control) != 0) {
1300 ldb_transaction_cancel(d_state->sam_ctx);
1301 return NT_STATUS_NO_MEMORY;
1302 }
1303
1304 /* modify the samdb record */
1305 ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
1306 if (ret != 0) {
1307 DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
1308 ldb_dn_get_linearized(msg->dn),
1309 ldb_errstring(d_state->sam_ctx)));
1310 ldb_transaction_cancel(d_state->sam_ctx);
1311
1312 /* we really need samdb.c to return NTSTATUS */
1313 return NT_STATUS_UNSUCCESSFUL;
1314 }
1315
1316 ret = ldb_transaction_commit(d_state->sam_ctx);
1317 if (ret != 0) {
1318 DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
1319 ldb_dn_get_linearized(msg->dn),
1320 ldb_errstring(d_state->sam_ctx)));
1321 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1322 }
1323
1324 a_state->account_name = talloc_steal(a_state, account_name);
1325 if (!a_state->account_name) {
1326 return NT_STATUS_NO_MEMORY;
1327 }
1328
1329 /* create the policy handle */
1330 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
1331 if (!u_handle) {
1332 return NT_STATUS_NO_MEMORY;
1333 }
1334
1335 u_handle->data = talloc_steal(u_handle, a_state);
1336
1337 *r->out.user_handle = u_handle->wire_handle;
1338 *r->out.access_granted = 0xf07ff; /* TODO: fix access mask calculations */
1339
1340 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1341
1342 return NT_STATUS_OK;
1343 }
1344
1345
1346 /*
1347 samr_CreateUser
1348 */
samr_CreateUser(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_CreateUser * r)1349 static NTSTATUS samr_CreateUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1350 struct samr_CreateUser *r)
1351 {
1352 struct samr_CreateUser2 r2;
1353 uint32_t access_granted = 0;
1354
1355
1356 /* a simple wrapper around samr_CreateUser2 works nicely */
1357 r2.in.domain_handle = r->in.domain_handle;
1358 r2.in.account_name = r->in.account_name;
1359 r2.in.acct_flags = ACB_NORMAL;
1360 r2.in.access_mask = r->in.access_mask;
1361 r2.out.user_handle = r->out.user_handle;
1362 r2.out.access_granted = &access_granted;
1363 r2.out.rid = r->out.rid;
1364
1365 return samr_CreateUser2(dce_call, mem_ctx, &r2);
1366 }
1367
1368 /*
1369 samr_EnumDomainUsers
1370 */
samr_EnumDomainUsers(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_EnumDomainUsers * r)1371 static NTSTATUS samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1372 struct samr_EnumDomainUsers *r)
1373 {
1374 struct dcesrv_handle *h;
1375 struct samr_domain_state *d_state;
1376 struct ldb_message **res;
1377 int count, i, first;
1378 struct samr_SamEntry *entries;
1379 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1380
1381 *r->out.resume_handle = 0;
1382 r->out.sam = NULL;
1383 r->out.num_entries = 0;
1384
1385 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1386
1387 d_state = h->data;
1388
1389 /* search for all users in this domain. This could possibly be cached and
1390 resumed based on resume_key */
1391 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1392 "objectclass=user");
1393 if (count == -1) {
1394 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1395 }
1396 if (count == 0 || r->in.max_size == 0) {
1397 return NT_STATUS_OK;
1398 }
1399
1400 /* convert to SamEntry format */
1401 entries = talloc_array(mem_ctx, struct samr_SamEntry, count);
1402 if (!entries) {
1403 return NT_STATUS_NO_MEMORY;
1404 }
1405 for (i=0;i<count;i++) {
1406 entries[i].idx = samdb_result_rid_from_sid(mem_ctx, res[i], "objectSid", 0);
1407 entries[i].name.string = samdb_result_string(res[i], "sAMAccountName", "");
1408 }
1409
1410 /* sort the results by rid */
1411 qsort(entries, count, sizeof(struct samr_SamEntry),
1412 (comparison_fn_t)compare_SamEntry);
1413
1414 /* find the first entry to return */
1415 for (first=0;
1416 first<count && entries[first].idx <= *r->in.resume_handle;
1417 first++) ;
1418
1419 if (first == count) {
1420 return NT_STATUS_OK;
1421 }
1422
1423 /* return the rest, limit by max_size. Note that we
1424 use the w2k3 element size value of 54 */
1425 r->out.num_entries = count - first;
1426 r->out.num_entries = MIN(r->out.num_entries,
1427 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER));
1428
1429 r->out.sam = talloc(mem_ctx, struct samr_SamArray);
1430 if (!r->out.sam) {
1431 return NT_STATUS_NO_MEMORY;
1432 }
1433
1434 r->out.sam->entries = entries+first;
1435 r->out.sam->count = r->out.num_entries;
1436
1437 if (r->out.num_entries < count - first) {
1438 *r->out.resume_handle = entries[first+r->out.num_entries-1].idx;
1439 return STATUS_MORE_ENTRIES;
1440 }
1441
1442 return NT_STATUS_OK;
1443 }
1444
1445
1446 /*
1447 samr_CreateDomAlias
1448 */
samr_CreateDomAlias(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_CreateDomAlias * r)1449 static NTSTATUS samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1450 struct samr_CreateDomAlias *r)
1451 {
1452 struct samr_domain_state *d_state;
1453 struct samr_account_state *a_state;
1454 struct dcesrv_handle *h;
1455 const char *alias_name, *name;
1456 struct ldb_message *msg;
1457 struct dom_sid *sid;
1458 struct dcesrv_handle *a_handle;
1459 int ret;
1460
1461 ZERO_STRUCTP(r->out.alias_handle);
1462 *r->out.rid = 0;
1463
1464 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1465
1466 d_state = h->data;
1467
1468 alias_name = r->in.alias_name->string;
1469
1470 if (alias_name == NULL) {
1471 return NT_STATUS_INVALID_PARAMETER;
1472 }
1473
1474 /* Check if alias already exists */
1475 name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
1476 "sAMAccountName",
1477 "(sAMAccountName=%s)(objectclass=group))",
1478 ldb_binary_encode_string(mem_ctx, alias_name));
1479
1480 if (name != NULL) {
1481 return NT_STATUS_ALIAS_EXISTS;
1482 }
1483
1484 msg = ldb_msg_new(mem_ctx);
1485 if (msg == NULL) {
1486 return NT_STATUS_NO_MEMORY;
1487 }
1488
1489 /* add core elements to the ldb_message for the alias */
1490 msg->dn = ldb_dn_copy(mem_ctx, d_state->domain_dn);
1491 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", alias_name);
1492 if (!msg->dn) {
1493 return NT_STATUS_NO_MEMORY;
1494 }
1495
1496 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "sAMAccountName", alias_name);
1497 samdb_msg_add_string(d_state->sam_ctx, mem_ctx, msg, "objectClass", "group");
1498 samdb_msg_add_int(d_state->sam_ctx, mem_ctx, msg, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1499
1500 /* create the alias */
1501 ret = samdb_add(d_state->sam_ctx, mem_ctx, msg);
1502 switch (ret) {
1503 case LDB_SUCCESS:
1504 break;
1505 case LDB_ERR_ENTRY_ALREADY_EXISTS:
1506 return NT_STATUS_ALIAS_EXISTS;
1507 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
1508 return NT_STATUS_ACCESS_DENIED;
1509 default:
1510 DEBUG(0,("Failed to create alias record %s: %s\n",
1511 ldb_dn_get_linearized(msg->dn),
1512 ldb_errstring(d_state->sam_ctx)));
1513 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1514 }
1515
1516 a_state = talloc(d_state, struct samr_account_state);
1517 if (!a_state) {
1518 return NT_STATUS_NO_MEMORY;
1519 }
1520
1521 a_state->sam_ctx = d_state->sam_ctx;
1522 a_state->access_mask = r->in.access_mask;
1523 a_state->domain_state = talloc_reference(a_state, d_state);
1524 a_state->account_dn = talloc_steal(a_state, msg->dn);
1525
1526 /* retrieve the sid for the alias just created */
1527 sid = samdb_search_dom_sid(d_state->sam_ctx, a_state,
1528 msg->dn, "objectSid", NULL);
1529
1530 a_state->account_name = talloc_strdup(a_state, alias_name);
1531 if (!a_state->account_name) {
1532 return NT_STATUS_NO_MEMORY;
1533 }
1534
1535 /* create the policy handle */
1536 a_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
1537 if (a_handle == NULL)
1538 return NT_STATUS_NO_MEMORY;
1539
1540 a_handle->data = talloc_steal(a_handle, a_state);
1541
1542 *r->out.alias_handle = a_handle->wire_handle;
1543
1544 *r->out.rid = sid->sub_auths[sid->num_auths-1];
1545
1546 return NT_STATUS_OK;
1547 }
1548
1549
1550 /*
1551 samr_EnumDomainAliases
1552 */
samr_EnumDomainAliases(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_EnumDomainAliases * r)1553 static NTSTATUS samr_EnumDomainAliases(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1554 struct samr_EnumDomainAliases *r)
1555 {
1556 struct dcesrv_handle *h;
1557 struct samr_domain_state *d_state;
1558 struct ldb_message **res;
1559 int ldb_cnt, count, i, first;
1560 struct samr_SamEntry *entries;
1561 const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL };
1562
1563 *r->out.resume_handle = 0;
1564 r->out.sam = NULL;
1565 r->out.num_entries = 0;
1566
1567 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1568
1569 d_state = h->data;
1570
1571 /* search for all domain groups in this domain. This could possibly be
1572 cached and resumed based on resume_key */
1573 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1574 d_state->domain_dn,
1575 &res, attrs,
1576 d_state->domain_sid,
1577 "(&(|(grouptype=%d)(grouptype=%d)))"
1578 "(objectclass=group))",
1579 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1580 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1581 if (ldb_cnt == -1) {
1582 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1583 }
1584 if (ldb_cnt == 0) {
1585 return NT_STATUS_OK;
1586 }
1587
1588 /* convert to SamEntry format */
1589 entries = talloc_array(mem_ctx, struct samr_SamEntry, ldb_cnt);
1590 if (!entries) {
1591 return NT_STATUS_NO_MEMORY;
1592 }
1593
1594 count = 0;
1595
1596 for (i=0;i<ldb_cnt;i++) {
1597 struct dom_sid *alias_sid;
1598
1599 alias_sid = samdb_result_dom_sid(mem_ctx, res[i],
1600 "objectSid");
1601
1602 if (alias_sid == NULL)
1603 continue;
1604
1605 entries[count].idx =
1606 alias_sid->sub_auths[alias_sid->num_auths-1];
1607 entries[count].name.string =
1608 samdb_result_string(res[i], "sAMAccountName", "");
1609 count += 1;
1610 }
1611
1612 /* sort the results by rid */
1613 qsort(entries, count, sizeof(struct samr_SamEntry),
1614 (comparison_fn_t)compare_SamEntry);
1615
1616 /* find the first entry to return */
1617 for (first=0;
1618 first<count && entries[first].idx <= *r->in.resume_handle;
1619 first++) ;
1620
1621 if (first == count) {
1622 return NT_STATUS_OK;
1623 }
1624
1625 r->out.num_entries = count - first;
1626 r->out.num_entries = MIN(r->out.num_entries, 1000);
1627
1628 r->out.sam = talloc(mem_ctx, struct samr_SamArray);
1629 if (!r->out.sam) {
1630 return NT_STATUS_NO_MEMORY;
1631 }
1632
1633 r->out.sam->entries = entries+first;
1634 r->out.sam->count = r->out.num_entries;
1635
1636 if (r->out.num_entries < count - first) {
1637 *r->out.resume_handle =
1638 entries[first+r->out.num_entries-1].idx;
1639 return STATUS_MORE_ENTRIES;
1640 }
1641
1642 return NT_STATUS_OK;
1643 }
1644
1645
1646 /*
1647 samr_GetAliasMembership
1648 */
samr_GetAliasMembership(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_GetAliasMembership * r)1649 static NTSTATUS samr_GetAliasMembership(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1650 struct samr_GetAliasMembership *r)
1651 {
1652 struct dcesrv_handle *h;
1653 struct samr_domain_state *d_state;
1654 struct ldb_message **res;
1655 int i, count = 0;
1656
1657 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1658
1659 d_state = h->data;
1660
1661 if (r->in.sids->num_sids > 0) {
1662 const char *filter;
1663 const char * const attrs[2] = { "objectSid", NULL };
1664
1665 filter = talloc_asprintf(mem_ctx,
1666 "(&(|(grouptype=%d)(grouptype=%d))"
1667 "(objectclass=group)(|",
1668 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
1669 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
1670 if (filter == NULL)
1671 return NT_STATUS_NO_MEMORY;
1672
1673 for (i=0; i<r->in.sids->num_sids; i++) {
1674 const char *memberdn;
1675
1676 memberdn =
1677 samdb_search_string(d_state->sam_ctx,
1678 mem_ctx, NULL, "distinguishedName",
1679 "(objectSid=%s)",
1680 ldap_encode_ndr_dom_sid(mem_ctx,
1681 r->in.sids->sids[i].sid));
1682
1683 if (memberdn == NULL)
1684 continue;
1685
1686 filter = talloc_asprintf(mem_ctx, "%s(member=%s)",
1687 filter, memberdn);
1688 if (filter == NULL)
1689 return NT_STATUS_NO_MEMORY;
1690 }
1691
1692 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
1693 d_state->domain_dn, &res, attrs,
1694 d_state->domain_sid, "%s))", filter);
1695 if (count < 0)
1696 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1697 }
1698
1699 r->out.rids->count = 0;
1700 r->out.rids->ids = talloc_array(mem_ctx, uint32_t, count);
1701 if (r->out.rids->ids == NULL)
1702 return NT_STATUS_NO_MEMORY;
1703
1704 for (i=0; i<count; i++) {
1705 struct dom_sid *alias_sid;
1706
1707 alias_sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
1708
1709 if (alias_sid == NULL) {
1710 DEBUG(0, ("Could not find objectSid\n"));
1711 continue;
1712 }
1713
1714 r->out.rids->ids[r->out.rids->count] =
1715 alias_sid->sub_auths[alias_sid->num_auths-1];
1716 r->out.rids->count += 1;
1717 }
1718
1719 return NT_STATUS_OK;
1720 }
1721
1722
1723 /*
1724 samr_LookupNames
1725 */
samr_LookupNames(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_LookupNames * r)1726 static NTSTATUS samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1727 struct samr_LookupNames *r)
1728 {
1729 struct dcesrv_handle *h;
1730 struct samr_domain_state *d_state;
1731 int i;
1732 NTSTATUS status = NT_STATUS_OK;
1733 const char * const attrs[] = { "sAMAccountType", "objectSid", NULL };
1734 int count;
1735
1736 ZERO_STRUCT(r->out.rids);
1737 ZERO_STRUCT(r->out.types);
1738
1739 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1740
1741 d_state = h->data;
1742
1743 if (r->in.num_names == 0) {
1744 return NT_STATUS_OK;
1745 }
1746
1747 r->out.rids.ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1748 r->out.types.ids = talloc_array(mem_ctx, uint32_t, r->in.num_names);
1749 if (!r->out.rids.ids || !r->out.types.ids) {
1750 return NT_STATUS_NO_MEMORY;
1751 }
1752 r->out.rids.count = r->in.num_names;
1753 r->out.types.count = r->in.num_names;
1754
1755 for (i=0;i<r->in.num_names;i++) {
1756 struct ldb_message **res;
1757 struct dom_sid *sid;
1758 uint32_t atype, rtype;
1759
1760 r->out.rids.ids[i] = 0;
1761 r->out.types.ids[i] = SID_NAME_UNKNOWN;
1762
1763 count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
1764 "sAMAccountName=%s",
1765 ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
1766 if (count != 1) {
1767 status = STATUS_SOME_UNMAPPED;
1768 continue;
1769 }
1770
1771 sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
1772 if (sid == NULL) {
1773 status = STATUS_SOME_UNMAPPED;
1774 continue;
1775 }
1776
1777 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1778 if (atype == 0) {
1779 status = STATUS_SOME_UNMAPPED;
1780 continue;
1781 }
1782
1783 rtype = samdb_atype_map(atype);
1784
1785 if (rtype == SID_NAME_UNKNOWN) {
1786 status = STATUS_SOME_UNMAPPED;
1787 continue;
1788 }
1789
1790 r->out.rids.ids[i] = sid->sub_auths[sid->num_auths-1];
1791 r->out.types.ids[i] = rtype;
1792 }
1793
1794
1795 return status;
1796 }
1797
1798
1799 /*
1800 samr_LookupRids
1801 */
samr_LookupRids(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_LookupRids * r)1802 static NTSTATUS samr_LookupRids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1803 struct samr_LookupRids *r)
1804 {
1805 struct dcesrv_handle *h;
1806 struct samr_domain_state *d_state;
1807 int i, total;
1808 NTSTATUS status = NT_STATUS_OK;
1809 struct lsa_String *names;
1810 uint32_t *ids;
1811
1812 ZERO_STRUCT(r->out.names);
1813 ZERO_STRUCT(r->out.types);
1814
1815 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1816
1817 d_state = h->data;
1818
1819 if (r->in.num_rids == 0)
1820 return NT_STATUS_OK;
1821
1822 names = talloc_array(mem_ctx, struct lsa_String, r->in.num_rids);
1823 ids = talloc_array(mem_ctx, uint32_t, r->in.num_rids);
1824
1825 if ((names == NULL) || (ids == NULL))
1826 return NT_STATUS_NO_MEMORY;
1827
1828 total = 0;
1829
1830 for (i=0; i<r->in.num_rids; i++) {
1831 struct ldb_message **res;
1832 int count;
1833 const char * const attrs[] = { "sAMAccountType",
1834 "sAMAccountName", NULL };
1835 uint32_t atype;
1836 struct dom_sid *sid;
1837
1838 ids[i] = SID_NAME_UNKNOWN;
1839
1840 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rids[i]);
1841 if (sid == NULL) {
1842 names[i].string = NULL;
1843 status = STATUS_SOME_UNMAPPED;
1844 continue;
1845 }
1846
1847 count = gendb_search(d_state->sam_ctx, mem_ctx,
1848 d_state->domain_dn, &res, attrs,
1849 "(objectSid=%s)",
1850 ldap_encode_ndr_dom_sid(mem_ctx, sid));
1851 if (count != 1) {
1852 names[i].string = NULL;
1853 status = STATUS_SOME_UNMAPPED;
1854 continue;
1855 }
1856
1857 names[i].string = samdb_result_string(res[0], "sAMAccountName",
1858 NULL);
1859
1860 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
1861 if (atype == 0) {
1862 status = STATUS_SOME_UNMAPPED;
1863 continue;
1864 }
1865
1866 ids[i] = samdb_atype_map(atype);
1867
1868 if (ids[i] == SID_NAME_UNKNOWN) {
1869 status = STATUS_SOME_UNMAPPED;
1870 continue;
1871 }
1872 }
1873
1874 r->out.names.names = names;
1875 r->out.names.count = r->in.num_rids;
1876
1877 r->out.types.ids = ids;
1878 r->out.types.count = r->in.num_rids;
1879
1880 return status;
1881 }
1882
1883
1884 /*
1885 samr_OpenGroup
1886 */
samr_OpenGroup(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_OpenGroup * r)1887 static NTSTATUS samr_OpenGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1888 struct samr_OpenGroup *r)
1889 {
1890 struct samr_domain_state *d_state;
1891 struct samr_account_state *a_state;
1892 struct dcesrv_handle *h;
1893 const char *groupname;
1894 struct dom_sid *sid;
1895 struct ldb_message **msgs;
1896 struct dcesrv_handle *g_handle;
1897 const char * const attrs[2] = { "sAMAccountName", NULL };
1898 int ret;
1899
1900 ZERO_STRUCTP(r->out.group_handle);
1901
1902 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
1903
1904 d_state = h->data;
1905
1906 /* form the group SID */
1907 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
1908 if (!sid) {
1909 return NT_STATUS_NO_MEMORY;
1910 }
1911
1912 /* search for the group record */
1913 ret = gendb_search(d_state->sam_ctx,
1914 mem_ctx, d_state->domain_dn, &msgs, attrs,
1915 "(&(objectSid=%s)(objectclass=group)"
1916 "(grouptype=%d))",
1917 ldap_encode_ndr_dom_sid(mem_ctx, sid),
1918 GTYPE_SECURITY_GLOBAL_GROUP);
1919 if (ret == 0) {
1920 return NT_STATUS_NO_SUCH_GROUP;
1921 }
1922 if (ret != 1) {
1923 DEBUG(0,("Found %d records matching sid %s\n",
1924 ret, dom_sid_string(mem_ctx, sid)));
1925 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1926 }
1927
1928 groupname = samdb_result_string(msgs[0], "sAMAccountName", NULL);
1929 if (groupname == NULL) {
1930 DEBUG(0,("sAMAccountName field missing for sid %s\n",
1931 dom_sid_string(mem_ctx, sid)));
1932 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1933 }
1934
1935 a_state = talloc(d_state, struct samr_account_state);
1936 if (!a_state) {
1937 return NT_STATUS_NO_MEMORY;
1938 }
1939 a_state->sam_ctx = d_state->sam_ctx;
1940 a_state->access_mask = r->in.access_mask;
1941 a_state->domain_state = talloc_reference(a_state, d_state);
1942 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
1943 a_state->account_sid = talloc_steal(a_state, sid);
1944 a_state->account_name = talloc_strdup(a_state, groupname);
1945 if (!a_state->account_name) {
1946 return NT_STATUS_NO_MEMORY;
1947 }
1948
1949 /* create the policy handle */
1950 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_GROUP);
1951 if (!g_handle) {
1952 return NT_STATUS_NO_MEMORY;
1953 }
1954
1955 g_handle->data = talloc_steal(g_handle, a_state);
1956
1957 *r->out.group_handle = g_handle->wire_handle;
1958
1959 return NT_STATUS_OK;
1960 }
1961
1962 /*
1963 samr_QueryGroupInfo
1964 */
samr_QueryGroupInfo(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_QueryGroupInfo * r)1965 static NTSTATUS samr_QueryGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
1966 struct samr_QueryGroupInfo *r)
1967 {
1968 struct dcesrv_handle *h;
1969 struct samr_account_state *a_state;
1970 struct ldb_message *msg, **res;
1971 const char * const attrs[4] = { "sAMAccountName", "description",
1972 "numMembers", NULL };
1973 int ret;
1974
1975 r->out.info = NULL;
1976
1977 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
1978
1979 a_state = h->data;
1980
1981 /* pull all the group attributes */
1982 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
1983 a_state->account_dn, &res, attrs);
1984 if (ret != 1) {
1985 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1986 }
1987 msg = res[0];
1988
1989 /* allocate the info structure */
1990 r->out.info = talloc(mem_ctx, union samr_GroupInfo);
1991 if (r->out.info == NULL) {
1992 return NT_STATUS_NO_MEMORY;
1993 }
1994 ZERO_STRUCTP(r->out.info);
1995
1996 /* Fill in the level */
1997 switch (r->in.level) {
1998 case GROUPINFOALL:
1999 QUERY_STRING(msg, all.name.string, "sAMAccountName");
2000 r->out.info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2001 QUERY_UINT (msg, all.num_members, "numMembers")
2002 QUERY_STRING(msg, all.description.string, "description");
2003 break;
2004 case GROUPINFONAME:
2005 QUERY_STRING(msg, name.string, "sAMAccountName");
2006 break;
2007 case GROUPINFOATTRIBUTES:
2008 r->out.info->attributes.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2009 break;
2010 case GROUPINFODESCRIPTION:
2011 QUERY_STRING(msg, description.string, "description");
2012 break;
2013 case GROUPINFOALL2:
2014 QUERY_STRING(msg, all2.name.string, "sAMAccountName");
2015 r->out.info->all.attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; /* Do like w2k3 */
2016 QUERY_UINT (msg, all2.num_members, "numMembers")
2017 QUERY_STRING(msg, all2.description.string, "description");
2018 break;
2019 default:
2020 r->out.info = NULL;
2021 return NT_STATUS_INVALID_INFO_CLASS;
2022 }
2023
2024 return NT_STATUS_OK;
2025 }
2026
2027
2028 /*
2029 samr_SetGroupInfo
2030 */
samr_SetGroupInfo(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_SetGroupInfo * r)2031 static NTSTATUS samr_SetGroupInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2032 struct samr_SetGroupInfo *r)
2033 {
2034 struct dcesrv_handle *h;
2035 struct samr_account_state *g_state;
2036 struct ldb_message *msg;
2037 struct ldb_context *sam_ctx;
2038 int ret;
2039
2040 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2041
2042 g_state = h->data;
2043 sam_ctx = g_state->sam_ctx;
2044
2045 msg = ldb_msg_new(mem_ctx);
2046 if (msg == NULL) {
2047 return NT_STATUS_NO_MEMORY;
2048 }
2049
2050 msg->dn = ldb_dn_copy(mem_ctx, g_state->account_dn);
2051 if (!msg->dn) {
2052 return NT_STATUS_NO_MEMORY;
2053 }
2054
2055 switch (r->in.level) {
2056 case GROUPINFODESCRIPTION:
2057 SET_STRING(msg, description.string, "description");
2058 break;
2059 case GROUPINFONAME:
2060 /* On W2k3 this does not change the name, it changes the
2061 * sAMAccountName attribute */
2062 SET_STRING(msg, name.string, "sAMAccountName");
2063 break;
2064 case GROUPINFOATTRIBUTES:
2065 /* This does not do anything obviously visible in W2k3 LDAP */
2066 return NT_STATUS_OK;
2067 default:
2068 return NT_STATUS_INVALID_INFO_CLASS;
2069 }
2070
2071 /* modify the samdb record */
2072 ret = samdb_replace(g_state->sam_ctx, mem_ctx, msg);
2073 if (ret != 0) {
2074 /* we really need samdb.c to return NTSTATUS */
2075 return NT_STATUS_UNSUCCESSFUL;
2076 }
2077
2078 return NT_STATUS_OK;
2079 }
2080
2081
2082 /*
2083 samr_AddGroupMember
2084 */
samr_AddGroupMember(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_AddGroupMember * r)2085 static NTSTATUS samr_AddGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2086 struct samr_AddGroupMember *r)
2087 {
2088 struct dcesrv_handle *h;
2089 struct samr_account_state *a_state;
2090 struct samr_domain_state *d_state;
2091 struct ldb_message *mod;
2092 struct dom_sid *membersid;
2093 const char *memberdn;
2094 struct ldb_result *res;
2095 const char * const attrs[] = { NULL };
2096 int ret;
2097
2098 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2099
2100 a_state = h->data;
2101 d_state = a_state->domain_state;
2102
2103 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2104 if (membersid == NULL)
2105 return NT_STATUS_NO_MEMORY;
2106
2107 /* In native mode, AD can also nest domain groups. Not sure yet
2108 * whether this is also available via RPC. */
2109 ret = ldb_search_exp_fmt(d_state->sam_ctx, mem_ctx, &res,
2110 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2111 "(&(objectSid=%s)(objectclass=user))",
2112 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2113
2114 if (ret != 0) {
2115 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2116 }
2117
2118 if (res->count == 0) {
2119 return NT_STATUS_NO_SUCH_USER;
2120 }
2121
2122 if (res->count > 1) {
2123 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2124 }
2125
2126 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2127
2128 if (memberdn == NULL)
2129 return NT_STATUS_NO_MEMORY;
2130
2131 mod = ldb_msg_new(mem_ctx);
2132 if (mod == NULL) {
2133 return NT_STATUS_NO_MEMORY;
2134 }
2135
2136 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2137
2138 if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2139 memberdn) != 0)
2140 return NT_STATUS_UNSUCCESSFUL;
2141
2142 ret = samdb_modify(a_state->sam_ctx, mem_ctx, mod);
2143 switch (ret) {
2144 case LDB_SUCCESS:
2145 return NT_STATUS_OK;
2146 case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
2147 return NT_STATUS_MEMBER_IN_GROUP;
2148 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2149 return NT_STATUS_ACCESS_DENIED;
2150 default:
2151 return NT_STATUS_UNSUCCESSFUL;
2152 }
2153
2154 }
2155
2156
2157 /*
2158 samr_DeleteDomainGroup
2159 */
samr_DeleteDomainGroup(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_DeleteDomainGroup * r)2160 static NTSTATUS samr_DeleteDomainGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2161 struct samr_DeleteDomainGroup *r)
2162 {
2163 struct dcesrv_handle *h;
2164 struct samr_account_state *a_state;
2165 int ret;
2166
2167 *r->out.group_handle = *r->in.group_handle;
2168
2169 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2170
2171 a_state = h->data;
2172
2173 ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
2174 if (ret != 0) {
2175 return NT_STATUS_UNSUCCESSFUL;
2176 }
2177
2178 ZERO_STRUCTP(r->out.group_handle);
2179
2180 return NT_STATUS_OK;
2181 }
2182
2183
2184 /*
2185 samr_DeleteGroupMember
2186 */
samr_DeleteGroupMember(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_DeleteGroupMember * r)2187 static NTSTATUS samr_DeleteGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2188 struct samr_DeleteGroupMember *r)
2189 {
2190 struct dcesrv_handle *h;
2191 struct samr_account_state *a_state;
2192 struct samr_domain_state *d_state;
2193 struct ldb_message *mod;
2194 struct dom_sid *membersid;
2195 const char *memberdn;
2196 struct ldb_result *res;
2197 const char * const attrs[] = { NULL };
2198 int ret;
2199
2200 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2201
2202 a_state = h->data;
2203 d_state = a_state->domain_state;
2204
2205 membersid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2206 if (membersid == NULL)
2207 return NT_STATUS_NO_MEMORY;
2208
2209 /* In native mode, AD can also nest domain groups. Not sure yet
2210 * whether this is also available via RPC. */
2211 ret = ldb_search_exp_fmt(d_state->sam_ctx, mem_ctx, &res,
2212 d_state->domain_dn, LDB_SCOPE_SUBTREE, attrs,
2213 "(&(objectSid=%s)(objectclass=user))",
2214 ldap_encode_ndr_dom_sid(mem_ctx, membersid));
2215
2216 if (ret != 0) {
2217 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2218 }
2219
2220 if (res->count == 0) {
2221 return NT_STATUS_NO_SUCH_USER;
2222 }
2223
2224 if (res->count > 1) {
2225 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2226 }
2227
2228 memberdn = ldb_dn_alloc_linearized(mem_ctx, res->msgs[0]->dn);
2229
2230 if (memberdn == NULL)
2231 return NT_STATUS_NO_MEMORY;
2232
2233 mod = ldb_msg_new(mem_ctx);
2234 if (mod == NULL) {
2235 return NT_STATUS_NO_MEMORY;
2236 }
2237
2238 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2239
2240 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2241 memberdn) != 0) {
2242 return NT_STATUS_NO_MEMORY;
2243 }
2244
2245 ret = samdb_modify(a_state->sam_ctx, mem_ctx, mod);
2246 switch (ret) {
2247 case LDB_SUCCESS:
2248 return NT_STATUS_OK;
2249 case LDB_ERR_NO_SUCH_ATTRIBUTE:
2250 return NT_STATUS_MEMBER_NOT_IN_GROUP;
2251 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
2252 return NT_STATUS_ACCESS_DENIED;
2253 default:
2254 return NT_STATUS_UNSUCCESSFUL;
2255 }
2256
2257 }
2258
2259
2260 /*
2261 samr_QueryGroupMember
2262 */
samr_QueryGroupMember(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_QueryGroupMember * r)2263 static NTSTATUS samr_QueryGroupMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2264 struct samr_QueryGroupMember *r)
2265 {
2266 struct dcesrv_handle *h;
2267 struct samr_account_state *a_state;
2268 struct ldb_message **res;
2269 struct ldb_message_element *el;
2270 struct samr_RidTypeArray *array;
2271 const char * const attrs[2] = { "member", NULL };
2272 int ret;
2273
2274 DCESRV_PULL_HANDLE(h, r->in.group_handle, SAMR_HANDLE_GROUP);
2275
2276 a_state = h->data;
2277
2278 /* pull the member attribute */
2279 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2280 a_state->account_dn, &res, attrs);
2281
2282 if (ret != 1) {
2283 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2284 }
2285
2286 array = talloc(mem_ctx, struct samr_RidTypeArray);
2287
2288 if (array == NULL)
2289 return NT_STATUS_NO_MEMORY;
2290
2291 ZERO_STRUCTP(array);
2292
2293 el = ldb_msg_find_element(res[0], "member");
2294
2295 if (el != NULL) {
2296 int i;
2297
2298 array->count = el->num_values;
2299
2300 array->rids = talloc_array(mem_ctx, uint32_t,
2301 el->num_values);
2302 if (array->rids == NULL)
2303 return NT_STATUS_NO_MEMORY;
2304
2305 array->types = talloc_array(mem_ctx, uint32_t,
2306 el->num_values);
2307 if (array->types == NULL)
2308 return NT_STATUS_NO_MEMORY;
2309
2310 for (i=0; i<el->num_values; i++) {
2311 struct ldb_message **res2;
2312 const char * const attrs2[2] = { "objectSid", NULL };
2313 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2314 ldb_dn_new(mem_ctx, a_state->sam_ctx, (const char *)el->values[i].data),
2315 &res2, attrs2);
2316 if (ret != 1)
2317 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2318
2319 array->rids[i] =
2320 samdb_result_rid_from_sid(mem_ctx, res2[0],
2321 "objectSid", 0);
2322
2323 if (array->rids[i] == 0)
2324 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2325
2326 array->types[i] = 7; /* RID type of some kind, not sure what the value means. */
2327 }
2328 }
2329
2330 r->out.rids = array;
2331
2332 return NT_STATUS_OK;
2333 }
2334
2335
2336 /*
2337 samr_SetMemberAttributesOfGroup
2338 */
samr_SetMemberAttributesOfGroup(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_SetMemberAttributesOfGroup * r)2339 static NTSTATUS samr_SetMemberAttributesOfGroup(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2340 struct samr_SetMemberAttributesOfGroup *r)
2341 {
2342 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
2343 }
2344
2345
2346 /*
2347 samr_OpenAlias
2348 */
samr_OpenAlias(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_OpenAlias * r)2349 static NTSTATUS samr_OpenAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2350 struct samr_OpenAlias *r)
2351 {
2352 struct samr_domain_state *d_state;
2353 struct samr_account_state *a_state;
2354 struct dcesrv_handle *h;
2355 const char *alias_name;
2356 struct dom_sid *sid;
2357 struct ldb_message **msgs;
2358 struct dcesrv_handle *g_handle;
2359 const char * const attrs[2] = { "sAMAccountName", NULL };
2360 int ret;
2361
2362 ZERO_STRUCTP(r->out.alias_handle);
2363
2364 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2365
2366 d_state = h->data;
2367
2368 /* form the alias SID */
2369 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2370 if (sid == NULL)
2371 return NT_STATUS_NO_MEMORY;
2372
2373 /* search for the group record */
2374 ret = gendb_search(d_state->sam_ctx,
2375 mem_ctx, d_state->domain_dn, &msgs, attrs,
2376 "(&(objectSid=%s)(objectclass=group)"
2377 "(|(grouptype=%d)(grouptype=%d)))",
2378 ldap_encode_ndr_dom_sid(mem_ctx, sid),
2379 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
2380 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
2381 if (ret == 0) {
2382 return NT_STATUS_NO_SUCH_ALIAS;
2383 }
2384 if (ret != 1) {
2385 DEBUG(0,("Found %d records matching sid %s\n",
2386 ret, dom_sid_string(mem_ctx, sid)));
2387 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2388 }
2389
2390 alias_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2391 if (alias_name == NULL) {
2392 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2393 dom_sid_string(mem_ctx, sid)));
2394 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2395 }
2396
2397 a_state = talloc(d_state, struct samr_account_state);
2398 if (!a_state) {
2399 return NT_STATUS_NO_MEMORY;
2400 }
2401 a_state->sam_ctx = d_state->sam_ctx;
2402 a_state->access_mask = r->in.access_mask;
2403 a_state->domain_state = talloc_reference(a_state, d_state);
2404 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2405 a_state->account_sid = talloc_steal(a_state, sid);
2406 a_state->account_name = talloc_strdup(a_state, alias_name);
2407 if (!a_state->account_name) {
2408 return NT_STATUS_NO_MEMORY;
2409 }
2410
2411 /* create the policy handle */
2412 g_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_ALIAS);
2413 if (!g_handle) {
2414 return NT_STATUS_NO_MEMORY;
2415 }
2416
2417 g_handle->data = talloc_steal(g_handle, a_state);
2418
2419 *r->out.alias_handle = g_handle->wire_handle;
2420
2421 return NT_STATUS_OK;
2422 }
2423
2424
2425 /*
2426 samr_QueryAliasInfo
2427 */
samr_QueryAliasInfo(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_QueryAliasInfo * r)2428 static NTSTATUS samr_QueryAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2429 struct samr_QueryAliasInfo *r)
2430 {
2431 struct dcesrv_handle *h;
2432 struct samr_account_state *a_state;
2433 struct ldb_message *msg, **res;
2434 const char * const attrs[4] = { "sAMAccountName", "description",
2435 "numMembers", NULL };
2436 int ret;
2437
2438 r->out.info = NULL;
2439
2440 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2441
2442 a_state = h->data;
2443
2444 /* pull all the alias attributes */
2445 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2446 a_state->account_dn ,&res, attrs);
2447 if (ret != 1) {
2448 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2449 }
2450 msg = res[0];
2451
2452 /* allocate the info structure */
2453 r->out.info = talloc(mem_ctx, union samr_AliasInfo);
2454 if (r->out.info == NULL) {
2455 return NT_STATUS_NO_MEMORY;
2456 }
2457 ZERO_STRUCTP(r->out.info);
2458
2459 switch(r->in.level) {
2460 case ALIASINFOALL:
2461 QUERY_STRING(msg, all.name.string, "sAMAccountName");
2462 QUERY_UINT (msg, all.num_members, "numMembers");
2463 QUERY_STRING(msg, all.description.string, "description");
2464 break;
2465 case ALIASINFONAME:
2466 QUERY_STRING(msg, name.string, "sAMAccountName");
2467 break;
2468 case ALIASINFODESCRIPTION:
2469 QUERY_STRING(msg, description.string, "description");
2470 break;
2471 default:
2472 r->out.info = NULL;
2473 return NT_STATUS_INVALID_INFO_CLASS;
2474 }
2475
2476 return NT_STATUS_OK;
2477 }
2478
2479
2480 /*
2481 samr_SetAliasInfo
2482 */
samr_SetAliasInfo(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_SetAliasInfo * r)2483 static NTSTATUS samr_SetAliasInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2484 struct samr_SetAliasInfo *r)
2485 {
2486 struct dcesrv_handle *h;
2487 struct samr_account_state *a_state;
2488 struct ldb_message *msg;
2489 struct ldb_context *sam_ctx;
2490 int ret;
2491
2492 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2493
2494 a_state = h->data;
2495 sam_ctx = a_state->sam_ctx;
2496
2497 msg = ldb_msg_new(mem_ctx);
2498 if (msg == NULL) {
2499 return NT_STATUS_NO_MEMORY;
2500 }
2501
2502 msg->dn = ldb_dn_copy(mem_ctx, a_state->account_dn);
2503 if (!msg->dn) {
2504 return NT_STATUS_NO_MEMORY;
2505 }
2506
2507 switch (r->in.level) {
2508 case ALIASINFODESCRIPTION:
2509 SET_STRING(msg, description.string, "description");
2510 break;
2511 case ALIASINFONAME:
2512 /* On W2k3 this does not change the name, it changes the
2513 * sAMAccountName attribute */
2514 SET_STRING(msg, name.string, "sAMAccountName");
2515 break;
2516 default:
2517 return NT_STATUS_INVALID_INFO_CLASS;
2518 }
2519
2520 /* modify the samdb record */
2521 ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
2522 if (ret != 0) {
2523 /* we really need samdb.c to return NTSTATUS */
2524 return NT_STATUS_UNSUCCESSFUL;
2525 }
2526
2527 return NT_STATUS_OK;
2528 }
2529
2530
2531 /*
2532 samr_DeleteDomAlias
2533 */
samr_DeleteDomAlias(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_DeleteDomAlias * r)2534 static NTSTATUS samr_DeleteDomAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2535 struct samr_DeleteDomAlias *r)
2536 {
2537 struct dcesrv_handle *h;
2538 struct samr_account_state *a_state;
2539 int ret;
2540
2541 *r->out.alias_handle = *r->in.alias_handle;
2542
2543 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2544
2545 a_state = h->data;
2546
2547 ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
2548 if (ret != 0) {
2549 return NT_STATUS_UNSUCCESSFUL;
2550 }
2551
2552 ZERO_STRUCTP(r->out.alias_handle);
2553
2554 return NT_STATUS_OK;
2555 }
2556
2557
2558 /*
2559 samr_AddAliasMember
2560 */
samr_AddAliasMember(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_AddAliasMember * r)2561 static NTSTATUS samr_AddAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2562 struct samr_AddAliasMember *r)
2563 {
2564 struct dcesrv_handle *h;
2565 struct samr_account_state *a_state;
2566 struct samr_domain_state *d_state;
2567 struct ldb_message *mod;
2568 struct ldb_message **msgs;
2569 const char * const attrs[] = { NULL };
2570 struct ldb_dn *memberdn = NULL;
2571 int ret;
2572 NTSTATUS status;
2573
2574 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2575
2576 a_state = h->data;
2577 d_state = a_state->domain_state;
2578
2579 ret = gendb_search(d_state->sam_ctx, mem_ctx, NULL,
2580 &msgs, attrs, "(objectsid=%s)",
2581 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2582
2583 if (ret == 1) {
2584 memberdn = msgs[0]->dn;
2585 } else if (ret > 1) {
2586 DEBUG(0,("Found %d records matching sid %s\n",
2587 ret, dom_sid_string(mem_ctx, r->in.sid)));
2588 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2589 } else if (ret == 0) {
2590 status = samdb_create_foreign_security_principal(d_state->sam_ctx, mem_ctx,
2591 r->in.sid, &memberdn);
2592 if (!NT_STATUS_IS_OK(status)) {
2593 return status;
2594 }
2595 } else {
2596 DEBUG(0, ("samdb_search returned %d: %s\n", ret, ldb_errstring(d_state->sam_ctx)));
2597 }
2598
2599 if (memberdn == NULL) {
2600 DEBUG(0, ("Could not find memberdn\n"));
2601 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2602 }
2603
2604 mod = ldb_msg_new(mem_ctx);
2605 if (mod == NULL) {
2606 return NT_STATUS_NO_MEMORY;
2607 }
2608
2609 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2610
2611 if (samdb_msg_add_addval(d_state->sam_ctx, mem_ctx, mod, "member",
2612 ldb_dn_alloc_linearized(mem_ctx, memberdn)) != 0)
2613 return NT_STATUS_UNSUCCESSFUL;
2614
2615 if (samdb_modify(a_state->sam_ctx, mem_ctx, mod) != 0)
2616 return NT_STATUS_UNSUCCESSFUL;
2617
2618 return NT_STATUS_OK;
2619 }
2620
2621
2622 /*
2623 samr_DeleteAliasMember
2624 */
samr_DeleteAliasMember(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_DeleteAliasMember * r)2625 static NTSTATUS samr_DeleteAliasMember(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2626 struct samr_DeleteAliasMember *r)
2627 {
2628 struct dcesrv_handle *h;
2629 struct samr_account_state *a_state;
2630 struct samr_domain_state *d_state;
2631 struct ldb_message *mod;
2632 const char *memberdn;
2633
2634 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2635
2636 a_state = h->data;
2637 d_state = a_state->domain_state;
2638
2639 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
2640 "distinguishedName", "(objectSid=%s)",
2641 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
2642
2643 if (memberdn == NULL)
2644 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
2645
2646 mod = ldb_msg_new(mem_ctx);
2647 if (mod == NULL) {
2648 return NT_STATUS_NO_MEMORY;
2649 }
2650
2651 mod->dn = talloc_reference(mem_ctx, a_state->account_dn);
2652
2653 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod, "member",
2654 memberdn) != 0)
2655 return NT_STATUS_UNSUCCESSFUL;
2656
2657 if (samdb_modify(a_state->sam_ctx, mem_ctx, mod) != 0)
2658 return NT_STATUS_UNSUCCESSFUL;
2659
2660 return NT_STATUS_OK;
2661 }
2662
2663
2664 /*
2665 samr_GetMembersInAlias
2666 */
samr_GetMembersInAlias(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_GetMembersInAlias * r)2667 static NTSTATUS samr_GetMembersInAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2668 struct samr_GetMembersInAlias *r)
2669 {
2670 struct dcesrv_handle *h;
2671 struct samr_account_state *a_state;
2672 struct samr_domain_state *d_state;
2673 struct ldb_message **msgs;
2674 struct lsa_SidPtr *sids;
2675 struct ldb_message_element *el;
2676 const char * const attrs[2] = { "member", NULL};
2677 int ret;
2678
2679 DCESRV_PULL_HANDLE(h, r->in.alias_handle, SAMR_HANDLE_ALIAS);
2680
2681 a_state = h->data;
2682 d_state = a_state->domain_state;
2683
2684 ret = gendb_search_dn(d_state->sam_ctx, mem_ctx,
2685 a_state->account_dn, &msgs, attrs);
2686
2687 if (ret != 1)
2688 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2689
2690 r->out.sids->num_sids = 0;
2691 r->out.sids->sids = NULL;
2692
2693 el = ldb_msg_find_element(msgs[0], "member");
2694
2695 if (el != NULL) {
2696 int i;
2697
2698 sids = talloc_array(mem_ctx, struct lsa_SidPtr,
2699 el->num_values);
2700
2701 if (sids == NULL)
2702 return NT_STATUS_NO_MEMORY;
2703
2704 for (i=0; i<el->num_values; i++) {
2705 struct ldb_message **msgs2;
2706 const char * const attrs2[2] = { "objectSid", NULL };
2707 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
2708 ldb_dn_new(mem_ctx, a_state->sam_ctx, (const char *)el->values[i].data),
2709 &msgs2, attrs2);
2710 if (ret != 1)
2711 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2712
2713 sids[i].sid = samdb_result_dom_sid(mem_ctx, msgs2[0],
2714 "objectSid");
2715
2716 if (sids[i].sid == NULL)
2717 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2718 }
2719 r->out.sids->num_sids = el->num_values;
2720 r->out.sids->sids = sids;
2721 }
2722
2723 return NT_STATUS_OK;
2724 }
2725
2726 /*
2727 samr_OpenUser
2728 */
samr_OpenUser(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_OpenUser * r)2729 static NTSTATUS samr_OpenUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2730 struct samr_OpenUser *r)
2731 {
2732 struct samr_domain_state *d_state;
2733 struct samr_account_state *a_state;
2734 struct dcesrv_handle *h;
2735 const char *account_name;
2736 struct dom_sid *sid;
2737 struct ldb_message **msgs;
2738 struct dcesrv_handle *u_handle;
2739 const char * const attrs[2] = { "sAMAccountName", NULL };
2740 int ret;
2741
2742 ZERO_STRUCTP(r->out.user_handle);
2743
2744 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
2745
2746 d_state = h->data;
2747
2748 /* form the users SID */
2749 sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
2750 if (!sid) {
2751 return NT_STATUS_NO_MEMORY;
2752 }
2753
2754 /* search for the user record */
2755 ret = gendb_search(d_state->sam_ctx,
2756 mem_ctx, d_state->domain_dn, &msgs, attrs,
2757 "(&(objectSid=%s)(objectclass=user))",
2758 ldap_encode_ndr_dom_sid(mem_ctx, sid));
2759 if (ret == 0) {
2760 return NT_STATUS_NO_SUCH_USER;
2761 }
2762 if (ret != 1) {
2763 DEBUG(0,("Found %d records matching sid %s\n", ret,
2764 dom_sid_string(mem_ctx, sid)));
2765 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2766 }
2767
2768 account_name = samdb_result_string(msgs[0], "sAMAccountName", NULL);
2769 if (account_name == NULL) {
2770 DEBUG(0,("sAMAccountName field missing for sid %s\n",
2771 dom_sid_string(mem_ctx, sid)));
2772 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2773 }
2774
2775 a_state = talloc(mem_ctx, struct samr_account_state);
2776 if (!a_state) {
2777 return NT_STATUS_NO_MEMORY;
2778 }
2779 a_state->sam_ctx = d_state->sam_ctx;
2780 a_state->access_mask = r->in.access_mask;
2781 a_state->domain_state = talloc_reference(a_state, d_state);
2782 a_state->account_dn = talloc_steal(a_state, msgs[0]->dn);
2783 a_state->account_sid = talloc_steal(a_state, sid);
2784 a_state->account_name = talloc_strdup(a_state, account_name);
2785 if (!a_state->account_name) {
2786 return NT_STATUS_NO_MEMORY;
2787 }
2788
2789 /* create the policy handle */
2790 u_handle = dcesrv_handle_new(dce_call->context, SAMR_HANDLE_USER);
2791 if (!u_handle) {
2792 return NT_STATUS_NO_MEMORY;
2793 }
2794
2795 u_handle->data = talloc_steal(u_handle, a_state);
2796
2797 *r->out.user_handle = u_handle->wire_handle;
2798
2799 return NT_STATUS_OK;
2800
2801 }
2802
2803
2804 /*
2805 samr_DeleteUser
2806 */
samr_DeleteUser(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_DeleteUser * r)2807 static NTSTATUS samr_DeleteUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2808 struct samr_DeleteUser *r)
2809 {
2810 struct dcesrv_handle *h;
2811 struct samr_account_state *a_state;
2812 int ret;
2813
2814 *r->out.user_handle = *r->in.user_handle;
2815
2816 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2817
2818 a_state = h->data;
2819
2820 ret = samdb_delete(a_state->sam_ctx, mem_ctx, a_state->account_dn);
2821 if (ret != 0) {
2822 return NT_STATUS_UNSUCCESSFUL;
2823 }
2824
2825 ZERO_STRUCTP(r->out.user_handle);
2826
2827 return NT_STATUS_OK;
2828 }
2829
2830
2831 /*
2832 samr_QueryUserInfo
2833 */
samr_QueryUserInfo(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_QueryUserInfo * r)2834 static NTSTATUS samr_QueryUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
2835 struct samr_QueryUserInfo *r)
2836 {
2837 struct dcesrv_handle *h;
2838 struct samr_account_state *a_state;
2839 struct ldb_message *msg, **res;
2840 int ret;
2841 struct ldb_context *sam_ctx;
2842
2843 const char * const *attrs = NULL;
2844
2845 r->out.info = NULL;
2846
2847 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
2848
2849 a_state = h->data;
2850 sam_ctx = a_state->sam_ctx;
2851
2852 /* fill in the reply */
2853 switch (r->in.level) {
2854 case 1:
2855 {
2856 static const char * const attrs2[] = {"sAMAccountName", "displayName",
2857 "primaryGroupID", "description",
2858 "comment", NULL};
2859 attrs = attrs2;
2860 break;
2861 }
2862 case 2:
2863 {
2864 static const char * const attrs2[] = {"comment", "countryCode", "codePage", NULL};
2865 attrs = attrs2;
2866 break;
2867 }
2868 case 3:
2869 {
2870 static const char * const attrs2[] = {"sAMAccountName",
2871 "displayName",
2872 "objectSid",
2873 "primaryGroupID",
2874 "homeDirectory",
2875 "homeDrive",
2876 "scriptPath",
2877 "profilePath",
2878 "userWorkstations",
2879 "lastLogon",
2880 "lastLogoff",
2881 "pwdLastSet",
2882 "logonHours",
2883 "badPwdCount",
2884 "logonCount",
2885 "userAccountControl", NULL};
2886 attrs = attrs2;
2887 break;
2888 }
2889 case 4:
2890 {
2891 static const char * const attrs2[] = {"logonHours", NULL};
2892 attrs = attrs2;
2893 break;
2894 }
2895 case 5:
2896 {
2897 static const char * const attrs2[] = {"sAMAccountName",
2898 "displayName",
2899 "objectSid",
2900 "primaryGroupID",
2901 "homeDirectory",
2902 "homeDrive",
2903 "scriptPath",
2904 "profilePath",
2905 "description",
2906 "userWorkstations",
2907 "lastLogon",
2908 "lastLogoff",
2909 "logonHours",
2910 "badPwdCount",
2911 "logonCount",
2912 "pwdLastSet",
2913 "accountExpires",
2914 "userAccountControl",
2915 NULL};
2916 attrs = attrs2;
2917 break;
2918 }
2919 case 6:
2920 {
2921 static const char * const attrs2[] = {"sAMAccountName", "displayName", NULL};
2922 attrs = attrs2;
2923 break;
2924 }
2925 case 7:
2926 {
2927 static const char * const attrs2[] = {"sAMAccountName", NULL};
2928 attrs = attrs2;
2929 break;
2930 }
2931 case 8:
2932 {
2933 static const char * const attrs2[] = {"displayName", NULL};
2934 attrs = attrs2;
2935 break;
2936 }
2937 case 9:
2938 {
2939 static const char * const attrs2[] = {"primaryGroupID", NULL};
2940 attrs = attrs2;
2941 break;
2942 }
2943 case 10:
2944 {
2945 static const char * const attrs2[] = {"homeDirectory", "homeDrive", NULL};
2946 attrs = attrs2;
2947 break;
2948 }
2949 case 11:
2950 {
2951 static const char * const attrs2[] = {"scriptPath", NULL};
2952 attrs = attrs2;
2953 break;
2954 }
2955 case 12:
2956 {
2957 static const char * const attrs2[] = {"profilePath", NULL};
2958 attrs = attrs2;
2959 break;
2960 }
2961 case 13:
2962 {
2963 static const char * const attrs2[] = {"description", NULL};
2964 attrs = attrs2;
2965 break;
2966 }
2967 case 14:
2968 {
2969 static const char * const attrs2[] = {"userWorkstations", NULL};
2970 attrs = attrs2;
2971 break;
2972 }
2973 case 16:
2974 {
2975 static const char * const attrs2[] = {"userAccountControl", NULL};
2976 attrs = attrs2;
2977 break;
2978 }
2979 case 17:
2980 {
2981 static const char * const attrs2[] = {"accountExpires", NULL};
2982 attrs = attrs2;
2983 break;
2984 }
2985 case 20:
2986 {
2987 static const char * const attrs2[] = {"userParameters", NULL};
2988 attrs = attrs2;
2989 break;
2990 }
2991 case 21:
2992 {
2993 static const char * const attrs2[] = {"lastLogon",
2994 "lastLogoff",
2995 "pwdLastSet",
2996 "accountExpires",
2997 "sAMAccountName",
2998 "displayName",
2999 "homeDirectory",
3000 "homeDrive",
3001 "scriptPath",
3002 "profilePath",
3003 "description",
3004 "userWorkstations",
3005 "comment",
3006 "userParameters",
3007 "objectSid",
3008 "primaryGroupID",
3009 "userAccountControl",
3010 "logonHours",
3011 "badPwdCount",
3012 "logonCount",
3013 "countryCode",
3014 "codePage",
3015 NULL};
3016 attrs = attrs2;
3017 break;
3018 }
3019 }
3020
3021 /* pull all the user attributes */
3022 ret = gendb_search_dn(a_state->sam_ctx, mem_ctx,
3023 a_state->account_dn ,&res, attrs);
3024 if (ret != 1) {
3025 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3026 }
3027 msg = res[0];
3028
3029 /* allocate the info structure */
3030 r->out.info = talloc(mem_ctx, union samr_UserInfo);
3031 if (r->out.info == NULL) {
3032 return NT_STATUS_NO_MEMORY;
3033 }
3034 ZERO_STRUCTP(r->out.info);
3035
3036 /* fill in the reply */
3037 switch (r->in.level) {
3038 case 1:
3039 QUERY_STRING(msg, info1.account_name.string, "sAMAccountName");
3040 QUERY_STRING(msg, info1.full_name.string, "displayName");
3041 QUERY_UINT (msg, info1.primary_gid, "primaryGroupID");
3042 QUERY_STRING(msg, info1.description.string, "description");
3043 QUERY_STRING(msg, info1.comment.string, "comment");
3044 break;
3045
3046 case 2:
3047 QUERY_STRING(msg, info2.comment.string, "comment");
3048 QUERY_UINT (msg, info2.country_code, "countryCode");
3049 QUERY_UINT (msg, info2.code_page, "codePage");
3050 break;
3051
3052 case 3:
3053 QUERY_STRING(msg, info3.account_name.string, "sAMAccountName");
3054 QUERY_STRING(msg, info3.full_name.string, "displayName");
3055 QUERY_RID (msg, info3.rid, "objectSid");
3056 QUERY_UINT (msg, info3.primary_gid, "primaryGroupID");
3057 QUERY_STRING(msg, info3.home_directory.string, "homeDirectory");
3058 QUERY_STRING(msg, info3.home_drive.string, "homeDrive");
3059 QUERY_STRING(msg, info3.logon_script.string, "scriptPath");
3060 QUERY_STRING(msg, info3.profile_path.string, "profilePath");
3061 QUERY_STRING(msg, info3.workstations.string, "userWorkstations");
3062 QUERY_NTTIME(msg, info3.last_logon, "lastLogon");
3063 QUERY_NTTIME(msg, info3.last_logoff, "lastLogoff");
3064 QUERY_NTTIME(msg, info3.last_password_change, "pwdLastSet");
3065 QUERY_APASSC(msg, info3.allow_password_change, "pwdLastSet");
3066 QUERY_FPASSC(msg, info3.force_password_change, "pwdLastSet");
3067 QUERY_LHOURS(msg, info3.logon_hours, "logonHours");
3068 QUERY_UINT (msg, info3.bad_password_count, "badPwdCount");
3069 QUERY_UINT (msg, info3.logon_count, "logonCount");
3070 QUERY_AFLAGS(msg, info3.acct_flags, "userAccountControl");
3071 break;
3072
3073 case 4:
3074 QUERY_LHOURS(msg, info4.logon_hours, "logonHours");
3075 break;
3076
3077 case 5:
3078 QUERY_STRING(msg, info5.account_name.string, "sAMAccountName");
3079 QUERY_STRING(msg, info5.full_name.string, "displayName");
3080 QUERY_RID (msg, info5.rid, "objectSid");
3081 QUERY_UINT (msg, info5.primary_gid, "primaryGroupID");
3082 QUERY_STRING(msg, info5.home_directory.string, "homeDirectory");
3083 QUERY_STRING(msg, info5.home_drive.string, "homeDrive");
3084 QUERY_STRING(msg, info5.logon_script.string, "scriptPath");
3085 QUERY_STRING(msg, info5.profile_path.string, "profilePath");
3086 QUERY_STRING(msg, info5.description.string, "description");
3087 QUERY_STRING(msg, info5.workstations.string, "userWorkstations");
3088 QUERY_NTTIME(msg, info5.last_logon, "lastLogon");
3089 QUERY_NTTIME(msg, info5.last_logoff, "lastLogoff");
3090 QUERY_LHOURS(msg, info5.logon_hours, "logonHours");
3091 QUERY_UINT (msg, info5.bad_password_count, "badPwdCount");
3092 QUERY_UINT (msg, info5.logon_count, "logonCount");
3093 QUERY_NTTIME(msg, info5.last_password_change, "pwdLastSet");
3094 QUERY_NTTIME(msg, info5.acct_expiry, "accountExpires");
3095 QUERY_AFLAGS(msg, info5.acct_flags, "userAccountControl");
3096 break;
3097
3098 case 6:
3099 QUERY_STRING(msg, info6.account_name.string, "sAMAccountName");
3100 QUERY_STRING(msg, info6.full_name.string, "displayName");
3101 break;
3102
3103 case 7:
3104 QUERY_STRING(msg, info7.account_name.string, "sAMAccountName");
3105 break;
3106
3107 case 8:
3108 QUERY_STRING(msg, info8.full_name.string, "displayName");
3109 break;
3110
3111 case 9:
3112 QUERY_UINT (msg, info9.primary_gid, "primaryGroupID");
3113 break;
3114
3115 case 10:
3116 QUERY_STRING(msg, info10.home_directory.string,"homeDirectory");
3117 QUERY_STRING(msg, info10.home_drive.string, "homeDrive");
3118 break;
3119
3120 case 11:
3121 QUERY_STRING(msg, info11.logon_script.string, "scriptPath");
3122 break;
3123
3124 case 12:
3125 QUERY_STRING(msg, info12.profile_path.string, "profilePath");
3126 break;
3127
3128 case 13:
3129 QUERY_STRING(msg, info13.description.string, "description");
3130 break;
3131
3132 case 14:
3133 QUERY_STRING(msg, info14.workstations.string, "userWorkstations");
3134 break;
3135
3136 case 16:
3137 QUERY_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3138 break;
3139
3140 case 17:
3141 QUERY_NTTIME(msg, info17.acct_expiry, "accountExpires");
3142
3143 case 20:
3144 QUERY_STRING(msg, info20.parameters.string, "userParameters");
3145 break;
3146
3147 case 21:
3148 QUERY_NTTIME(msg, info21.last_logon, "lastLogon");
3149 QUERY_NTTIME(msg, info21.last_logoff, "lastLogoff");
3150 QUERY_NTTIME(msg, info21.last_password_change, "pwdLastSet");
3151 QUERY_NTTIME(msg, info21.acct_expiry, "accountExpires");
3152 QUERY_APASSC(msg, info21.allow_password_change,"pwdLastSet");
3153 QUERY_FPASSC(msg, info21.force_password_change,"pwdLastSet");
3154 QUERY_STRING(msg, info21.account_name.string, "sAMAccountName");
3155 QUERY_STRING(msg, info21.full_name.string, "displayName");
3156 QUERY_STRING(msg, info21.home_directory.string,"homeDirectory");
3157 QUERY_STRING(msg, info21.home_drive.string, "homeDrive");
3158 QUERY_STRING(msg, info21.logon_script.string, "scriptPath");
3159 QUERY_STRING(msg, info21.profile_path.string, "profilePath");
3160 QUERY_STRING(msg, info21.description.string, "description");
3161 QUERY_STRING(msg, info21.workstations.string, "userWorkstations");
3162 QUERY_STRING(msg, info21.comment.string, "comment");
3163 QUERY_STRING(msg, info21.parameters.string, "userParameters");
3164 QUERY_RID (msg, info21.rid, "objectSid");
3165 QUERY_UINT (msg, info21.primary_gid, "primaryGroupID");
3166 QUERY_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3167 r->out.info->info21.fields_present = 0x00FFFFFF;
3168 QUERY_LHOURS(msg, info21.logon_hours, "logonHours");
3169 QUERY_UINT (msg, info21.bad_password_count, "badPwdCount");
3170 QUERY_UINT (msg, info21.logon_count, "logonCount");
3171 QUERY_UINT (msg, info21.country_code, "countryCode");
3172 QUERY_UINT (msg, info21.code_page, "codePage");
3173 break;
3174
3175
3176 default:
3177 r->out.info = NULL;
3178 return NT_STATUS_INVALID_INFO_CLASS;
3179 }
3180
3181 return NT_STATUS_OK;
3182 }
3183
3184
3185 /*
3186 samr_SetUserInfo
3187 */
samr_SetUserInfo(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_SetUserInfo * r)3188 static NTSTATUS samr_SetUserInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3189 struct samr_SetUserInfo *r)
3190 {
3191 struct dcesrv_handle *h;
3192 struct samr_account_state *a_state;
3193 struct ldb_message *msg;
3194 int ret;
3195 NTSTATUS status = NT_STATUS_OK;
3196 struct ldb_context *sam_ctx;
3197
3198 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3199
3200 a_state = h->data;
3201 sam_ctx = a_state->sam_ctx;
3202
3203 msg = ldb_msg_new(mem_ctx);
3204 if (msg == NULL) {
3205 return NT_STATUS_NO_MEMORY;
3206 }
3207
3208 msg->dn = talloc_reference(mem_ctx, a_state->account_dn);
3209 if (!msg->dn) {
3210 return NT_STATUS_NO_MEMORY;
3211 }
3212
3213 switch (r->in.level) {
3214 case 2:
3215 SET_STRING(msg, info2.comment.string, "comment");
3216 SET_UINT (msg, info2.country_code, "countryCode");
3217 SET_UINT (msg, info2.code_page, "codePage");
3218 break;
3219
3220 case 4:
3221 SET_LHOURS(msg, info4.logon_hours, "logonHours");
3222 break;
3223
3224 case 6:
3225 SET_STRING(msg, info6.full_name.string, "displayName");
3226 break;
3227
3228 case 7:
3229 SET_STRING(msg, info7.account_name.string, "samAccountName");
3230 break;
3231
3232 case 8:
3233 SET_STRING(msg, info8.full_name.string, "displayName");
3234 break;
3235
3236 case 9:
3237 SET_UINT(msg, info9.primary_gid, "primaryGroupID");
3238 break;
3239
3240 case 10:
3241 SET_STRING(msg, info10.home_directory.string, "homeDirectory");
3242 SET_STRING(msg, info10.home_drive.string, "homeDrive");
3243 break;
3244
3245 case 11:
3246 SET_STRING(msg, info11.logon_script.string, "scriptPath");
3247 break;
3248
3249 case 12:
3250 SET_STRING(msg, info12.profile_path.string, "profilePath");
3251 break;
3252
3253 case 13:
3254 SET_STRING(msg, info13.description.string, "description");
3255 break;
3256
3257 case 14:
3258 SET_STRING(msg, info14.workstations.string, "userWorkstations");
3259 break;
3260
3261 case 16:
3262 SET_AFLAGS(msg, info16.acct_flags, "userAccountControl");
3263 break;
3264
3265 case 17:
3266 SET_UINT64(msg, info17.acct_expiry, "accountExpires");
3267 break;
3268
3269 case 20:
3270 SET_STRING(msg, info20.parameters.string, "userParameters");
3271 break;
3272
3273 case 21:
3274 #define IFSET(bit) if (bit & r->in.info->info21.fields_present)
3275 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3276 SET_STRING(msg, info21.account_name.string, "samAccountName");
3277 IFSET(SAMR_FIELD_FULL_NAME)
3278 SET_STRING(msg, info21.full_name.string, "displayName");
3279 IFSET(SAMR_FIELD_DESCRIPTION)
3280 SET_STRING(msg, info21.description.string, "description");
3281 IFSET(SAMR_FIELD_COMMENT)
3282 SET_STRING(msg, info21.comment.string, "comment");
3283 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3284 SET_STRING(msg, info21.logon_script.string, "scriptPath");
3285 IFSET(SAMR_FIELD_PROFILE_PATH)
3286 SET_STRING(msg, info21.profile_path.string, "profilePath");
3287 IFSET(SAMR_FIELD_HOME_DIRECTORY)
3288 SET_STRING(msg, info21.home_directory.string, "homeDirectory");
3289 IFSET(SAMR_FIELD_HOME_DRIVE)
3290 SET_STRING(msg, info21.home_drive.string, "homeDrive");
3291 IFSET(SAMR_FIELD_WORKSTATIONS)
3292 SET_STRING(msg, info21.workstations.string, "userWorkstations");
3293 IFSET(SAMR_FIELD_LOGON_HOURS)
3294 SET_LHOURS(msg, info21.logon_hours, "logonHours");
3295 IFSET(SAMR_FIELD_ACCT_FLAGS)
3296 SET_AFLAGS(msg, info21.acct_flags, "userAccountControl");
3297 IFSET(SAMR_FIELD_PARAMETERS)
3298 SET_STRING(msg, info21.parameters.string, "userParameters");
3299 IFSET(SAMR_FIELD_COUNTRY_CODE)
3300 SET_UINT (msg, info21.country_code, "countryCode");
3301 IFSET(SAMR_FIELD_CODE_PAGE)
3302 SET_UINT (msg, info21.code_page, "codePage");
3303
3304
3305 /* Any reason the rest of these can't be set? */
3306 #undef IFSET
3307 break;
3308
3309 case 23:
3310 #define IFSET(bit) if (bit & r->in.info->info23.info.fields_present)
3311 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3312 SET_STRING(msg, info23.info.account_name.string, "samAccountName");
3313 IFSET(SAMR_FIELD_FULL_NAME)
3314 SET_STRING(msg, info23.info.full_name.string, "displayName");
3315 IFSET(SAMR_FIELD_DESCRIPTION)
3316 SET_STRING(msg, info23.info.description.string, "description");
3317 IFSET(SAMR_FIELD_COMMENT)
3318 SET_STRING(msg, info23.info.comment.string, "comment");
3319 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3320 SET_STRING(msg, info23.info.logon_script.string, "scriptPath");
3321 IFSET(SAMR_FIELD_PROFILE_PATH)
3322 SET_STRING(msg, info23.info.profile_path.string, "profilePath");
3323 IFSET(SAMR_FIELD_WORKSTATIONS)
3324 SET_STRING(msg, info23.info.workstations.string, "userWorkstations");
3325 IFSET(SAMR_FIELD_LOGON_HOURS)
3326 SET_LHOURS(msg, info23.info.logon_hours, "logonHours");
3327 IFSET(SAMR_FIELD_ACCT_FLAGS)
3328 SET_AFLAGS(msg, info23.info.acct_flags, "userAccountControl");
3329 IFSET(SAMR_FIELD_PARAMETERS)
3330 SET_STRING(msg, info23.info.parameters.string, "userParameters");
3331 IFSET(SAMR_FIELD_COUNTRY_CODE)
3332 SET_UINT (msg, info23.info.country_code, "countryCode");
3333 IFSET(SAMR_FIELD_CODE_PAGE)
3334 SET_UINT (msg, info23.info.code_page, "codePage");
3335 IFSET(SAMR_FIELD_PASSWORD) {
3336 status = samr_set_password(dce_call,
3337 a_state->sam_ctx,
3338 a_state->account_dn,
3339 a_state->domain_state->domain_dn,
3340 mem_ctx, msg,
3341 &r->in.info->info23.password);
3342 } else IFSET(SAMR_FIELD_PASSWORD2) {
3343 status = samr_set_password(dce_call,
3344 a_state->sam_ctx,
3345 a_state->account_dn,
3346 a_state->domain_state->domain_dn,
3347 mem_ctx, msg,
3348 &r->in.info->info23.password);
3349 }
3350 #undef IFSET
3351 break;
3352
3353 /* the set password levels are handled separately */
3354 case 24:
3355 status = samr_set_password(dce_call,
3356 a_state->sam_ctx,
3357 a_state->account_dn,
3358 a_state->domain_state->domain_dn,
3359 mem_ctx, msg,
3360 &r->in.info->info24.password);
3361 break;
3362
3363 case 25:
3364 #define IFSET(bit) if (bit & r->in.info->info25.info.fields_present)
3365 IFSET(SAMR_FIELD_ACCOUNT_NAME)
3366 SET_STRING(msg, info25.info.account_name.string, "samAccountName");
3367 IFSET(SAMR_FIELD_FULL_NAME)
3368 SET_STRING(msg, info25.info.full_name.string, "displayName");
3369 IFSET(SAMR_FIELD_DESCRIPTION)
3370 SET_STRING(msg, info25.info.description.string, "description");
3371 IFSET(SAMR_FIELD_COMMENT)
3372 SET_STRING(msg, info25.info.comment.string, "comment");
3373 IFSET(SAMR_FIELD_LOGON_SCRIPT)
3374 SET_STRING(msg, info25.info.logon_script.string, "scriptPath");
3375 IFSET(SAMR_FIELD_PROFILE_PATH)
3376 SET_STRING(msg, info25.info.profile_path.string, "profilePath");
3377 IFSET(SAMR_FIELD_WORKSTATIONS)
3378 SET_STRING(msg, info25.info.workstations.string, "userWorkstations");
3379 IFSET(SAMR_FIELD_LOGON_HOURS)
3380 SET_LHOURS(msg, info25.info.logon_hours, "logonHours");
3381 IFSET(SAMR_FIELD_ACCT_FLAGS)
3382 SET_AFLAGS(msg, info25.info.acct_flags, "userAccountControl");
3383 IFSET(SAMR_FIELD_PARAMETERS)
3384 SET_STRING(msg, info25.info.parameters.string, "userParameters");
3385 IFSET(SAMR_FIELD_COUNTRY_CODE)
3386 SET_UINT (msg, info25.info.country_code, "countryCode");
3387 IFSET(SAMR_FIELD_CODE_PAGE)
3388 SET_UINT (msg, info25.info.code_page, "codePage");
3389 IFSET(SAMR_FIELD_PASSWORD) {
3390 status = samr_set_password_ex(dce_call,
3391 a_state->sam_ctx,
3392 a_state->account_dn,
3393 a_state->domain_state->domain_dn,
3394 mem_ctx, msg,
3395 &r->in.info->info25.password);
3396 } else IFSET(SAMR_FIELD_PASSWORD2) {
3397 status = samr_set_password_ex(dce_call,
3398 a_state->sam_ctx,
3399 a_state->account_dn,
3400 a_state->domain_state->domain_dn,
3401 mem_ctx, msg,
3402 &r->in.info->info25.password);
3403 }
3404 #undef IFSET
3405 break;
3406
3407 /* the set password levels are handled separately */
3408 case 26:
3409 status = samr_set_password_ex(dce_call,
3410 a_state->sam_ctx,
3411 a_state->account_dn,
3412 a_state->domain_state->domain_dn,
3413 mem_ctx, msg,
3414 &r->in.info->info26.password);
3415 break;
3416
3417
3418 default:
3419 /* many info classes are not valid for SetUserInfo */
3420 return NT_STATUS_INVALID_INFO_CLASS;
3421 }
3422
3423 if (!NT_STATUS_IS_OK(status)) {
3424 return status;
3425 }
3426
3427 /* modify the samdb record */
3428 ret = samdb_replace(a_state->sam_ctx, mem_ctx, msg);
3429 if (ret != 0) {
3430 DEBUG(1,("Failed to modify record %s: %s\n",
3431 ldb_dn_get_linearized(a_state->account_dn),
3432 ldb_errstring(a_state->sam_ctx)));
3433
3434 /* we really need samdb.c to return NTSTATUS */
3435 return NT_STATUS_UNSUCCESSFUL;
3436 }
3437
3438 return NT_STATUS_OK;
3439 }
3440
3441
3442 /*
3443 samr_GetGroupsForUser
3444 */
samr_GetGroupsForUser(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_GetGroupsForUser * r)3445 static NTSTATUS samr_GetGroupsForUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3446 struct samr_GetGroupsForUser *r)
3447 {
3448 struct dcesrv_handle *h;
3449 struct samr_account_state *a_state;
3450 struct samr_domain_state *d_state;
3451 struct ldb_message **res;
3452 const char * const attrs[2] = { "objectSid", NULL };
3453 struct samr_RidWithAttributeArray *array;
3454 int count;
3455
3456 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3457
3458 a_state = h->data;
3459 d_state = a_state->domain_state;
3460
3461 count = samdb_search_domain(a_state->sam_ctx, mem_ctx, d_state->domain_dn, &res,
3462 attrs, d_state->domain_sid,
3463 "(&(member=%s)(grouptype=%d)(objectclass=group))",
3464 ldb_dn_get_linearized(a_state->account_dn),
3465 GTYPE_SECURITY_GLOBAL_GROUP);
3466 if (count < 0)
3467 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3468
3469 array = talloc(mem_ctx, struct samr_RidWithAttributeArray);
3470 if (array == NULL)
3471 return NT_STATUS_NO_MEMORY;
3472
3473 array->count = 0;
3474 array->rids = NULL;
3475
3476 if (count > 0) {
3477 int i;
3478 array->rids = talloc_array(mem_ctx, struct samr_RidWithAttribute,
3479 count);
3480
3481 if (array->rids == NULL)
3482 return NT_STATUS_NO_MEMORY;
3483
3484 for (i=0; i<count; i++) {
3485 struct dom_sid *group_sid;
3486
3487 group_sid = samdb_result_dom_sid(mem_ctx, res[i],
3488 "objectSid");
3489 if (group_sid == NULL) {
3490 DEBUG(0, ("Couldn't find objectSid attrib\n"));
3491 continue;
3492 }
3493
3494 array->rids[array->count].rid =
3495 group_sid->sub_auths[group_sid->num_auths-1];
3496 array->rids[array->count].attributes = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED;
3497 array->count += 1;
3498 }
3499 }
3500
3501 r->out.rids = array;
3502
3503 return NT_STATUS_OK;
3504 }
3505
3506
3507 /*
3508 samr_QueryDisplayInfo
3509 */
samr_QueryDisplayInfo(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_QueryDisplayInfo * r)3510 static NTSTATUS samr_QueryDisplayInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3511 struct samr_QueryDisplayInfo *r)
3512 {
3513 struct dcesrv_handle *h;
3514 struct samr_domain_state *d_state;
3515 struct ldb_message **res;
3516 int ldb_cnt, count, i;
3517 const char * const attrs[4] = { "objectSid", "sAMAccountName",
3518 "description", NULL };
3519 struct samr_DispEntryFull *entriesFull = NULL;
3520 struct samr_DispEntryAscii *entriesAscii = NULL;
3521 struct samr_DispEntryGeneral * entriesGeneral = NULL;
3522 const char *filter;
3523
3524 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3525
3526 d_state = h->data;
3527
3528 switch (r->in.level) {
3529 case 1:
3530 case 4:
3531 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3532 "(sAMAccountType=%u))",
3533 ATYPE_NORMAL_ACCOUNT);
3534 break;
3535 case 2:
3536 filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)"
3537 "(sAMAccountType=%u))",
3538 ATYPE_WORKSTATION_TRUST);
3539 break;
3540 case 3:
3541 case 5:
3542 filter = talloc_asprintf(mem_ctx, "(&(grouptype=%d)"
3543 "(objectclass=group))",
3544 GTYPE_SECURITY_GLOBAL_GROUP);
3545 break;
3546 default:
3547 return NT_STATUS_INVALID_INFO_CLASS;
3548 }
3549
3550 /* search for all requested objects in this domain. This could
3551 possibly be cached and resumed based on resume_key */
3552 ldb_cnt = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3553 d_state->domain_dn, &res, attrs,
3554 d_state->domain_sid, "%s", filter);
3555 if (ldb_cnt == -1) {
3556 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3557 }
3558 if (ldb_cnt == 0 || r->in.max_entries == 0) {
3559 return NT_STATUS_OK;
3560 }
3561
3562 switch (r->in.level) {
3563 case 1:
3564 entriesGeneral = talloc_array(mem_ctx,
3565 struct samr_DispEntryGeneral,
3566 ldb_cnt);
3567 break;
3568 case 2:
3569 case 3:
3570 entriesFull = talloc_array(mem_ctx,
3571 struct samr_DispEntryFull,
3572 ldb_cnt);
3573 break;
3574 case 4:
3575 case 5:
3576 entriesAscii = talloc_array(mem_ctx,
3577 struct samr_DispEntryAscii,
3578 ldb_cnt);
3579 break;
3580 }
3581
3582 if ((entriesGeneral == NULL) && (entriesFull == NULL) &&
3583 (entriesAscii == NULL))
3584 return NT_STATUS_NO_MEMORY;
3585
3586 count = 0;
3587
3588 for (i=0; i<ldb_cnt; i++) {
3589 struct dom_sid *objectsid;
3590
3591 objectsid = samdb_result_dom_sid(mem_ctx, res[i],
3592 "objectSid");
3593 if (objectsid == NULL)
3594 continue;
3595
3596 switch(r->in.level) {
3597 case 1:
3598 entriesGeneral[count].idx = count + 1;
3599 entriesGeneral[count].rid =
3600 objectsid->sub_auths[objectsid->num_auths-1];
3601 entriesGeneral[count].acct_flags =
3602 samdb_result_acct_flags(res[i],
3603 "userAccountControl");
3604 entriesGeneral[count].account_name.string =
3605 samdb_result_string(res[i],
3606 "sAMAccountName", "");
3607 entriesGeneral[count].full_name.string =
3608 samdb_result_string(res[i], "displayName", "");
3609 entriesGeneral[count].description.string =
3610 samdb_result_string(res[i], "description", "");
3611 break;
3612 case 2:
3613 case 3:
3614 entriesFull[count].idx = count + 1;
3615 entriesFull[count].rid =
3616 objectsid->sub_auths[objectsid->num_auths-1];
3617 entriesFull[count].acct_flags =
3618 samdb_result_acct_flags(res[i],
3619 "userAccountControl");
3620 if (r->in.level == 3) {
3621 /* We get a "7" here for groups */
3622 entriesFull[count].acct_flags = 7;
3623 }
3624 entriesFull[count].account_name.string =
3625 samdb_result_string(res[i], "sAMAccountName",
3626 "");
3627 entriesFull[count].description.string =
3628 samdb_result_string(res[i], "description", "");
3629 break;
3630 case 4:
3631 case 5:
3632 entriesAscii[count].idx = count + 1;
3633 entriesAscii[count].account_name.string =
3634 samdb_result_string(res[i], "sAMAccountName",
3635 "");
3636 break;
3637 }
3638
3639 count += 1;
3640 }
3641
3642 r->out.total_size = count;
3643
3644 if (r->in.start_idx >= count) {
3645 r->out.returned_size = 0;
3646 switch(r->in.level) {
3647 case 1:
3648 r->out.info.info1.count = r->out.returned_size;
3649 r->out.info.info1.entries = NULL;
3650 break;
3651 case 2:
3652 r->out.info.info2.count = r->out.returned_size;
3653 r->out.info.info2.entries = NULL;
3654 break;
3655 case 3:
3656 r->out.info.info3.count = r->out.returned_size;
3657 r->out.info.info3.entries = NULL;
3658 break;
3659 case 4:
3660 r->out.info.info4.count = r->out.returned_size;
3661 r->out.info.info4.entries = NULL;
3662 break;
3663 case 5:
3664 r->out.info.info5.count = r->out.returned_size;
3665 r->out.info.info5.entries = NULL;
3666 break;
3667 }
3668 } else {
3669 r->out.returned_size = MIN(count - r->in.start_idx,
3670 r->in.max_entries);
3671 switch(r->in.level) {
3672 case 1:
3673 r->out.info.info1.count = r->out.returned_size;
3674 r->out.info.info1.entries =
3675 &(entriesGeneral[r->in.start_idx]);
3676 break;
3677 case 2:
3678 r->out.info.info2.count = r->out.returned_size;
3679 r->out.info.info2.entries =
3680 &(entriesFull[r->in.start_idx]);
3681 break;
3682 case 3:
3683 r->out.info.info3.count = r->out.returned_size;
3684 r->out.info.info3.entries =
3685 &(entriesFull[r->in.start_idx]);
3686 break;
3687 case 4:
3688 r->out.info.info4.count = r->out.returned_size;
3689 r->out.info.info4.entries =
3690 &(entriesAscii[r->in.start_idx]);
3691 break;
3692 case 5:
3693 r->out.info.info5.count = r->out.returned_size;
3694 r->out.info.info5.entries =
3695 &(entriesAscii[r->in.start_idx]);
3696 break;
3697 }
3698 }
3699
3700 return (r->out.returned_size < (count - r->in.start_idx)) ?
3701 STATUS_MORE_ENTRIES : NT_STATUS_OK;
3702 }
3703
3704
3705 /*
3706 samr_GetDisplayEnumerationIndex
3707 */
samr_GetDisplayEnumerationIndex(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_GetDisplayEnumerationIndex * r)3708 static NTSTATUS samr_GetDisplayEnumerationIndex(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3709 struct samr_GetDisplayEnumerationIndex *r)
3710 {
3711 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3712 }
3713
3714
3715 /*
3716 samr_TestPrivateFunctionsDomain
3717 */
samr_TestPrivateFunctionsDomain(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_TestPrivateFunctionsDomain * r)3718 static NTSTATUS samr_TestPrivateFunctionsDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3719 struct samr_TestPrivateFunctionsDomain *r)
3720 {
3721 return NT_STATUS_NOT_IMPLEMENTED;
3722 }
3723
3724
3725 /*
3726 samr_TestPrivateFunctionsUser
3727 */
samr_TestPrivateFunctionsUser(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_TestPrivateFunctionsUser * r)3728 static NTSTATUS samr_TestPrivateFunctionsUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3729 struct samr_TestPrivateFunctionsUser *r)
3730 {
3731 return NT_STATUS_NOT_IMPLEMENTED;
3732 }
3733
3734
3735 /*
3736 samr_GetUserPwInfo
3737 */
samr_GetUserPwInfo(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_GetUserPwInfo * r)3738 static NTSTATUS samr_GetUserPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3739 struct samr_GetUserPwInfo *r)
3740 {
3741 struct dcesrv_handle *h;
3742 struct samr_account_state *a_state;
3743
3744 ZERO_STRUCT(r->out.info);
3745
3746 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
3747
3748 a_state = h->data;
3749
3750 r->out.info.min_password_length = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0,
3751 a_state->domain_state->domain_dn, "minPwdLength",
3752 NULL);
3753 r->out.info.password_properties = samdb_search_uint(a_state->sam_ctx, mem_ctx, 0,
3754 a_state->account_dn,
3755 "pwdProperties", NULL);
3756 return NT_STATUS_OK;
3757 }
3758
3759
3760 /*
3761 samr_RemoveMemberFromForeignDomain
3762 */
samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_RemoveMemberFromForeignDomain * r)3763 static NTSTATUS samr_RemoveMemberFromForeignDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3764 struct samr_RemoveMemberFromForeignDomain *r)
3765 {
3766 struct dcesrv_handle *h;
3767 struct samr_domain_state *d_state;
3768 const char *memberdn;
3769 struct ldb_message **res;
3770 const char * const attrs[3] = { "distinguishedName", "objectSid", NULL };
3771 int i, count;
3772
3773 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
3774
3775 d_state = h->data;
3776
3777 memberdn = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
3778 "distinguishedName", "(objectSid=%s)",
3779 ldap_encode_ndr_dom_sid(mem_ctx, r->in.sid));
3780 /* Nothing to do */
3781 if (memberdn == NULL) {
3782 return NT_STATUS_OK;
3783 }
3784
3785 /* TODO: Does this call only remove alias members, or does it do this
3786 * for domain groups as well? */
3787
3788 count = samdb_search_domain(d_state->sam_ctx, mem_ctx,
3789 d_state->domain_dn, &res, attrs,
3790 d_state->domain_sid,
3791 "(&(member=%s)(objectClass=group)"
3792 "(|(groupType=%d)(groupType=%d)))",
3793 memberdn,
3794 GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
3795 GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
3796
3797 if (count < 0)
3798 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3799
3800 for (i=0; i<count; i++) {
3801 struct ldb_message *mod;
3802
3803 mod = ldb_msg_new(mem_ctx);
3804 if (mod == NULL) {
3805 return NT_STATUS_NO_MEMORY;
3806 }
3807
3808 mod->dn = samdb_result_dn(d_state->sam_ctx, mod, res[i], "distinguishedName", NULL);
3809 if (mod->dn == NULL) {
3810 talloc_free(mod);
3811 continue;
3812 }
3813
3814 if (samdb_msg_add_delval(d_state->sam_ctx, mem_ctx, mod,
3815 "member", memberdn) != 0)
3816 return NT_STATUS_NO_MEMORY;
3817
3818 if (samdb_modify(d_state->sam_ctx, mem_ctx, mod) != 0)
3819 return NT_STATUS_UNSUCCESSFUL;
3820
3821 talloc_free(mod);
3822 }
3823
3824 return NT_STATUS_OK;
3825 }
3826
3827
3828 /*
3829 samr_QueryDomainInfo2
3830
3831 just an alias for samr_QueryDomainInfo
3832 */
samr_QueryDomainInfo2(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_QueryDomainInfo2 * r)3833 static NTSTATUS samr_QueryDomainInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3834 struct samr_QueryDomainInfo2 *r)
3835 {
3836 struct samr_QueryDomainInfo r1;
3837 NTSTATUS status;
3838
3839 ZERO_STRUCT(r1.out);
3840 r1.in.domain_handle = r->in.domain_handle;
3841 r1.in.level = r->in.level;
3842
3843 status = samr_QueryDomainInfo(dce_call, mem_ctx, &r1);
3844
3845 r->out.info = r1.out.info;
3846
3847 return status;
3848 }
3849
3850
3851 /*
3852 samr_QueryUserInfo2
3853
3854 just an alias for samr_QueryUserInfo
3855 */
samr_QueryUserInfo2(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_QueryUserInfo2 * r)3856 static NTSTATUS samr_QueryUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3857 struct samr_QueryUserInfo2 *r)
3858 {
3859 struct samr_QueryUserInfo r1;
3860 NTSTATUS status;
3861
3862 ZERO_STRUCT(r1.out);
3863 r1.in.user_handle = r->in.user_handle;
3864 r1.in.level = r->in.level;
3865
3866 status = samr_QueryUserInfo(dce_call, mem_ctx, &r1);
3867
3868 r->out.info = r1.out.info;
3869
3870 return status;
3871 }
3872
3873
3874 /*
3875 samr_QueryDisplayInfo2
3876 */
samr_QueryDisplayInfo2(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_QueryDisplayInfo2 * r)3877 static NTSTATUS samr_QueryDisplayInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3878 struct samr_QueryDisplayInfo2 *r)
3879 {
3880 struct samr_QueryDisplayInfo q;
3881 NTSTATUS result;
3882
3883 q.in.domain_handle = r->in.domain_handle;
3884 q.in.level = r->in.level;
3885 q.in.start_idx = r->in.start_idx;
3886 q.in.max_entries = r->in.max_entries;
3887 q.in.buf_size = r->in.buf_size;
3888 ZERO_STRUCT(q.out);
3889
3890 result = samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
3891
3892 r->out.total_size = q.out.total_size;
3893 r->out.returned_size = q.out.returned_size;
3894 r->out.info = q.out.info;
3895
3896 return result;
3897 }
3898
3899
3900 /*
3901 samr_GetDisplayEnumerationIndex2
3902 */
samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_GetDisplayEnumerationIndex2 * r)3903 static NTSTATUS samr_GetDisplayEnumerationIndex2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3904 struct samr_GetDisplayEnumerationIndex2 *r)
3905 {
3906 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3907 }
3908
3909
3910 /*
3911 samr_QueryDisplayInfo3
3912 */
samr_QueryDisplayInfo3(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_QueryDisplayInfo3 * r)3913 static NTSTATUS samr_QueryDisplayInfo3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3914 struct samr_QueryDisplayInfo3 *r)
3915 {
3916 struct samr_QueryDisplayInfo q;
3917 NTSTATUS result;
3918
3919 q.in.domain_handle = r->in.domain_handle;
3920 q.in.level = r->in.level;
3921 q.in.start_idx = r->in.start_idx;
3922 q.in.max_entries = r->in.max_entries;
3923 q.in.buf_size = r->in.buf_size;
3924 ZERO_STRUCT(q.out);
3925
3926 result = samr_QueryDisplayInfo(dce_call, mem_ctx, &q);
3927
3928 r->out.total_size = q.out.total_size;
3929 r->out.returned_size = q.out.returned_size;
3930 r->out.info = q.out.info;
3931
3932 return result;
3933 }
3934
3935
3936 /*
3937 samr_AddMultipleMembersToAlias
3938 */
samr_AddMultipleMembersToAlias(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_AddMultipleMembersToAlias * r)3939 static NTSTATUS samr_AddMultipleMembersToAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3940 struct samr_AddMultipleMembersToAlias *r)
3941 {
3942 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3943 }
3944
3945
3946 /*
3947 samr_RemoveMultipleMembersFromAlias
3948 */
samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_RemoveMultipleMembersFromAlias * r)3949 static NTSTATUS samr_RemoveMultipleMembersFromAlias(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3950 struct samr_RemoveMultipleMembersFromAlias *r)
3951 {
3952 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
3953 }
3954
3955
3956 /*
3957 samr_GetDomPwInfo
3958
3959 this fetches the default password properties for a domain
3960
3961 note that w2k3 completely ignores the domain name in this call, and
3962 always returns the information for the servers primary domain
3963 */
samr_GetDomPwInfo(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_GetDomPwInfo * r)3964 static NTSTATUS samr_GetDomPwInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
3965 struct samr_GetDomPwInfo *r)
3966 {
3967 struct ldb_message **msgs;
3968 int ret;
3969 const char * const attrs[] = {"minPwdLength", "pwdProperties", NULL };
3970 struct ldb_context *sam_ctx;
3971
3972 ZERO_STRUCT(r->out.info);
3973
3974 sam_ctx = samdb_connect(mem_ctx, dce_call->conn->auth_state.session_info);
3975 if (sam_ctx == NULL) {
3976 return NT_STATUS_INVALID_SYSTEM_SERVICE;
3977 }
3978
3979 /* The domain name in this call is ignored */
3980 ret = gendb_search_dn(sam_ctx,
3981 mem_ctx, NULL, &msgs, attrs);
3982 if (ret <= 0) {
3983 return NT_STATUS_NO_SUCH_DOMAIN;
3984 }
3985 if (ret > 1) {
3986 talloc_free(msgs);
3987 return NT_STATUS_INTERNAL_DB_CORRUPTION;
3988 }
3989
3990 r->out.info.min_password_length = samdb_result_uint(msgs[0], "minPwdLength", 0);
3991 r->out.info.password_properties = samdb_result_uint(msgs[0], "pwdProperties", 1);
3992
3993 talloc_free(msgs);
3994
3995 talloc_free(sam_ctx);
3996 return NT_STATUS_OK;
3997 }
3998
3999
4000 /*
4001 samr_Connect2
4002 */
samr_Connect2(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_Connect2 * r)4003 static NTSTATUS samr_Connect2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4004 struct samr_Connect2 *r)
4005 {
4006 struct samr_Connect c;
4007
4008 c.in.system_name = NULL;
4009 c.in.access_mask = r->in.access_mask;
4010 c.out.connect_handle = r->out.connect_handle;
4011
4012 return samr_Connect(dce_call, mem_ctx, &c);
4013 }
4014
4015
4016 /*
4017 samr_SetUserInfo2
4018
4019 just an alias for samr_SetUserInfo
4020 */
samr_SetUserInfo2(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_SetUserInfo2 * r)4021 static NTSTATUS samr_SetUserInfo2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4022 struct samr_SetUserInfo2 *r)
4023 {
4024 struct samr_SetUserInfo r2;
4025
4026 r2.in.user_handle = r->in.user_handle;
4027 r2.in.level = r->in.level;
4028 r2.in.info = r->in.info;
4029
4030 return samr_SetUserInfo(dce_call, mem_ctx, &r2);
4031 }
4032
4033
4034 /*
4035 samr_SetBootKeyInformation
4036 */
samr_SetBootKeyInformation(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_SetBootKeyInformation * r)4037 static NTSTATUS samr_SetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4038 struct samr_SetBootKeyInformation *r)
4039 {
4040 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4041 }
4042
4043
4044 /*
4045 samr_GetBootKeyInformation
4046 */
samr_GetBootKeyInformation(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_GetBootKeyInformation * r)4047 static NTSTATUS samr_GetBootKeyInformation(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4048 struct samr_GetBootKeyInformation *r)
4049 {
4050 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4051 }
4052
4053
4054 /*
4055 samr_Connect3
4056 */
samr_Connect3(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_Connect3 * r)4057 static NTSTATUS samr_Connect3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4058 struct samr_Connect3 *r)
4059 {
4060 struct samr_Connect c;
4061
4062 c.in.system_name = NULL;
4063 c.in.access_mask = r->in.access_mask;
4064 c.out.connect_handle = r->out.connect_handle;
4065
4066 return samr_Connect(dce_call, mem_ctx, &c);
4067 }
4068
4069
4070 /*
4071 samr_Connect4
4072 */
samr_Connect4(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_Connect4 * r)4073 static NTSTATUS samr_Connect4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4074 struct samr_Connect4 *r)
4075 {
4076 struct samr_Connect c;
4077
4078 c.in.system_name = NULL;
4079 c.in.access_mask = r->in.access_mask;
4080 c.out.connect_handle = r->out.connect_handle;
4081
4082 return samr_Connect(dce_call, mem_ctx, &c);
4083 }
4084
4085
4086 /*
4087 samr_Connect5
4088 */
samr_Connect5(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_Connect5 * r)4089 static NTSTATUS samr_Connect5(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4090 struct samr_Connect5 *r)
4091 {
4092 struct samr_Connect c;
4093 NTSTATUS status;
4094
4095 c.in.system_name = NULL;
4096 c.in.access_mask = r->in.access_mask;
4097 c.out.connect_handle = r->out.connect_handle;
4098
4099 status = samr_Connect(dce_call, mem_ctx, &c);
4100
4101 r->out.info->info1.unknown1 = 3;
4102 r->out.info->info1.unknown2 = 0;
4103 r->out.level = r->in.level;
4104
4105 return status;
4106 }
4107
4108
4109 /*
4110 samr_RidToSid
4111 */
samr_RidToSid(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_RidToSid * r)4112 static NTSTATUS samr_RidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4113 struct samr_RidToSid *r)
4114 {
4115 struct samr_domain_state *d_state;
4116 struct dcesrv_handle *h;
4117
4118 DCESRV_PULL_HANDLE(h, r->in.domain_handle, SAMR_HANDLE_DOMAIN);
4119
4120 d_state = h->data;
4121
4122 /* form the users SID */
4123 r->out.sid = dom_sid_add_rid(mem_ctx, d_state->domain_sid, r->in.rid);
4124 if (!r->out.sid) {
4125 return NT_STATUS_NO_MEMORY;
4126 }
4127
4128 return NT_STATUS_OK;
4129 }
4130
4131
4132 /*
4133 samr_SetDsrmPassword
4134 */
samr_SetDsrmPassword(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_SetDsrmPassword * r)4135 static NTSTATUS samr_SetDsrmPassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4136 struct samr_SetDsrmPassword *r)
4137 {
4138 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4139 }
4140
4141
4142 /*
4143 samr_ValidatePassword
4144 */
samr_ValidatePassword(struct dcesrv_call_state * dce_call,TALLOC_CTX * mem_ctx,struct samr_ValidatePassword * r)4145 static NTSTATUS samr_ValidatePassword(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
4146 struct samr_ValidatePassword *r)
4147 {
4148 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
4149 }
4150
4151
4152 /* include the generated boilerplate */
4153 #include "librpc/gen_ndr/ndr_samr_s.c"
4154