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