WHATSNEW: Update changes.
[Samba.git] / source4 / dsdb / common / util_samr.c
blob6a14f0a4f48488b037ac899924a3c8cdf24c1866
1 /*
2 Unix SMB/CIFS implementation.
4 Helpers to add users and groups to the DB
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Volker Lendecke 2004
8 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2010
9 Copyright (C) Matthias Dieter Wallnöfer 2009
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "includes.h"
26 #include "dsdb/samdb/samdb.h"
27 #include "dsdb/common/util.h"
28 #include "../libds/common/flags.h"
29 #include "libcli/security/dom_sid.h"
31 /* Add a user, SAMR style, including the correct transaction
32 * semantics. Used by the SAMR server and by pdb_samba4 */
33 NTSTATUS dsdb_add_user(struct ldb_context *ldb,
34 TALLOC_CTX *mem_ctx,
35 const char *account_name,
36 uint32_t acct_flags,
37 struct dom_sid **sid,
38 struct ldb_dn **dn)
40 const char *name;
41 struct ldb_message *msg;
42 int ret;
43 const char *container, *obj_class=NULL;
44 char *cn_name;
45 size_t cn_name_len;
47 const char *attrs[] = {
48 "objectSid",
49 "userAccountControl",
50 NULL
53 uint32_t user_account_control;
54 struct ldb_dn *account_dn;
55 struct dom_sid *account_sid;
57 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
58 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
61 * Start a transaction, so we can query and do a subsequent atomic
62 * modify
65 ret = ldb_transaction_start(ldb);
66 if (ret != LDB_SUCCESS) {
67 DEBUG(0,("Failed to start a transaction for user creation: %s\n",
68 ldb_errstring(ldb)));
69 talloc_free(tmp_ctx);
70 return NT_STATUS_INTERNAL_DB_CORRUPTION;
73 /* check if the user already exists */
74 name = samdb_search_string(ldb, tmp_ctx, NULL,
75 "sAMAccountName",
76 "(&(sAMAccountName=%s)(objectclass=user))",
77 ldb_binary_encode_string(tmp_ctx, account_name));
78 if (name != NULL) {
79 ldb_transaction_cancel(ldb);
80 talloc_free(tmp_ctx);
81 return NT_STATUS_USER_EXISTS;
84 cn_name = talloc_strdup(tmp_ctx, account_name);
85 if (!cn_name) {
86 ldb_transaction_cancel(ldb);
87 talloc_free(tmp_ctx);
88 return NT_STATUS_NO_MEMORY;
91 cn_name_len = strlen(cn_name);
92 if (cn_name_len < 1) {
93 ldb_transaction_cancel(ldb);
94 talloc_free(tmp_ctx);
95 return NT_STATUS_INVALID_PARAMETER;
98 msg = ldb_msg_new(tmp_ctx);
99 if (msg == NULL) {
100 ldb_transaction_cancel(ldb);
101 talloc_free(tmp_ctx);
102 return NT_STATUS_NO_MEMORY;
105 /* This must be one of these values *only* */
106 if (acct_flags == ACB_NORMAL) {
107 container = "CN=Users";
108 obj_class = "user";
110 } else if (acct_flags == ACB_WSTRUST) {
111 if (cn_name[cn_name_len - 1] != '$') {
112 ldb_transaction_cancel(ldb);
113 return NT_STATUS_FOOBAR;
115 cn_name[cn_name_len - 1] = '\0';
116 container = "CN=Computers";
117 obj_class = "computer";
118 samdb_msg_add_int(ldb, tmp_ctx, msg,
119 "primaryGroupID", DOMAIN_RID_DOMAIN_MEMBERS);
121 } else if (acct_flags == ACB_SVRTRUST) {
122 if (cn_name[cn_name_len - 1] != '$') {
123 ldb_transaction_cancel(ldb);
124 return NT_STATUS_FOOBAR;
126 cn_name[cn_name_len - 1] = '\0';
127 container = "OU=Domain Controllers";
128 obj_class = "computer";
129 samdb_msg_add_int(ldb, tmp_ctx, msg,
130 "primaryGroupID", DOMAIN_RID_DCS);
131 } else {
132 ldb_transaction_cancel(ldb);
133 talloc_free(tmp_ctx);
134 return NT_STATUS_INVALID_PARAMETER;
137 /* add core elements to the ldb_message for the user */
138 msg->dn = ldb_dn_copy(msg, ldb_get_default_basedn(ldb));
139 if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s,%s", cn_name, container)) {
140 ldb_transaction_cancel(ldb);
141 talloc_free(tmp_ctx);
142 return NT_STATUS_FOOBAR;
145 samdb_msg_add_string(ldb, tmp_ctx, msg, "sAMAccountName",
146 account_name);
147 samdb_msg_add_string(ldb, tmp_ctx, msg, "objectClass",
148 obj_class);
150 /* create the user */
151 ret = ldb_add(ldb, msg);
152 switch (ret) {
153 case LDB_SUCCESS:
154 break;
155 case LDB_ERR_ENTRY_ALREADY_EXISTS:
156 ldb_transaction_cancel(ldb);
157 DEBUG(0,("Failed to create user record %s: %s\n",
158 ldb_dn_get_linearized(msg->dn),
159 ldb_errstring(ldb)));
160 talloc_free(tmp_ctx);
161 return NT_STATUS_USER_EXISTS;
162 case LDB_ERR_UNWILLING_TO_PERFORM:
163 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
164 ldb_transaction_cancel(ldb);
165 DEBUG(0,("Failed to create user record %s: %s\n",
166 ldb_dn_get_linearized(msg->dn),
167 ldb_errstring(ldb)));
168 talloc_free(tmp_ctx);
169 return NT_STATUS_ACCESS_DENIED;
170 default:
171 ldb_transaction_cancel(ldb);
172 DEBUG(0,("Failed to create user record %s: %s\n",
173 ldb_dn_get_linearized(msg->dn),
174 ldb_errstring(ldb)));
175 talloc_free(tmp_ctx);
176 return NT_STATUS_INTERNAL_DB_CORRUPTION;
179 account_dn = msg->dn;
181 /* retrieve the sid and account control bits for the user just created */
182 ret = dsdb_search_one(ldb, tmp_ctx, &msg,
183 account_dn, LDB_SCOPE_BASE, attrs, 0, NULL);
185 if (ret != LDB_SUCCESS) {
186 ldb_transaction_cancel(ldb);
187 DEBUG(0,("Can't locate the account we just created %s: %s\n",
188 ldb_dn_get_linearized(account_dn), ldb_errstring(ldb)));
189 talloc_free(tmp_ctx);
190 return NT_STATUS_INTERNAL_DB_CORRUPTION;
192 account_sid = samdb_result_dom_sid(tmp_ctx, msg, "objectSid");
193 if (account_sid == NULL) {
194 ldb_transaction_cancel(ldb);
195 DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n",
196 ldb_dn_get_linearized(msg->dn)));
197 talloc_free(tmp_ctx);
198 return NT_STATUS_INTERNAL_DB_CORRUPTION;
201 /* Change the account control to be the correct account type.
202 * The default is for a workstation account */
203 user_account_control = samdb_result_uint(msg, "userAccountControl", 0);
204 user_account_control = (user_account_control &
205 ~(UF_NORMAL_ACCOUNT |
206 UF_INTERDOMAIN_TRUST_ACCOUNT |
207 UF_WORKSTATION_TRUST_ACCOUNT |
208 UF_SERVER_TRUST_ACCOUNT));
209 user_account_control |= ds_acb2uf(acct_flags);
211 talloc_free(msg);
212 msg = ldb_msg_new(tmp_ctx);
213 if (msg == NULL) {
214 ldb_transaction_cancel(ldb);
215 talloc_free(tmp_ctx);
216 return NT_STATUS_NO_MEMORY;
219 msg->dn = account_dn;
221 if (samdb_msg_add_uint(ldb, tmp_ctx, msg,
222 "userAccountControl",
223 user_account_control) != 0) {
224 ldb_transaction_cancel(ldb);
225 talloc_free(tmp_ctx);
226 return NT_STATUS_NO_MEMORY;
229 /* modify the samdb record */
230 ret = dsdb_replace(ldb, msg, 0);
231 if (ret != LDB_SUCCESS) {
232 DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
233 ldb_dn_get_linearized(msg->dn),
234 ldb_errstring(ldb)));
235 ldb_transaction_cancel(ldb);
236 talloc_free(tmp_ctx);
238 /* we really need samdb.c to return NTSTATUS */
239 return NT_STATUS_UNSUCCESSFUL;
242 ret = ldb_transaction_commit(ldb);
243 if (ret != LDB_SUCCESS) {
244 DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
245 ldb_dn_get_linearized(msg->dn),
246 ldb_errstring(ldb)));
247 talloc_free(tmp_ctx);
248 return NT_STATUS_INTERNAL_DB_CORRUPTION;
250 *dn = talloc_steal(mem_ctx, account_dn);
251 *sid = talloc_steal(mem_ctx, account_sid);
252 talloc_free(tmp_ctx);
253 return NT_STATUS_OK;
257 called by samr_CreateDomainGroup and pdb_samba4
259 NTSTATUS dsdb_add_domain_group(struct ldb_context *ldb,
260 TALLOC_CTX *mem_ctx,
261 const char *groupname,
262 struct dom_sid **sid,
263 struct ldb_dn **dn)
265 const char *name;
266 struct ldb_message *msg;
267 struct dom_sid *group_sid;
268 int ret;
270 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
271 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
273 /* check if the group already exists */
274 name = samdb_search_string(ldb, tmp_ctx, NULL,
275 "sAMAccountName",
276 "(&(sAMAccountName=%s)(objectclass=group))",
277 ldb_binary_encode_string(tmp_ctx, groupname));
278 if (name != NULL) {
279 return NT_STATUS_GROUP_EXISTS;
282 msg = ldb_msg_new(tmp_ctx);
283 if (msg == NULL) {
284 return NT_STATUS_NO_MEMORY;
287 /* add core elements to the ldb_message for the user */
288 msg->dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(ldb));
289 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", groupname);
290 if (!msg->dn) {
291 talloc_free(tmp_ctx);
292 return NT_STATUS_NO_MEMORY;
294 samdb_msg_add_string(ldb, tmp_ctx, msg, "sAMAccountName", groupname);
295 samdb_msg_add_string(ldb, tmp_ctx, msg, "objectClass", "group");
297 /* create the group */
298 ret = ldb_add(ldb, msg);
299 switch (ret) {
300 case LDB_SUCCESS:
301 break;
302 case LDB_ERR_ENTRY_ALREADY_EXISTS:
303 DEBUG(0,("Failed to create group record %s: %s\n",
304 ldb_dn_get_linearized(msg->dn),
305 ldb_errstring(ldb)));
306 talloc_free(tmp_ctx);
307 return NT_STATUS_GROUP_EXISTS;
308 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
309 DEBUG(0,("Failed to create group record %s: %s\n",
310 ldb_dn_get_linearized(msg->dn),
311 ldb_errstring(ldb)));
312 talloc_free(tmp_ctx);
313 return NT_STATUS_ACCESS_DENIED;
314 default:
315 DEBUG(0,("Failed to create group record %s: %s\n",
316 ldb_dn_get_linearized(msg->dn),
317 ldb_errstring(ldb)));
318 talloc_free(tmp_ctx);
319 return NT_STATUS_INTERNAL_DB_CORRUPTION;
322 /* retrieve the sid for the group just created */
323 group_sid = samdb_search_dom_sid(ldb, tmp_ctx,
324 msg->dn, "objectSid", NULL);
325 if (group_sid == NULL) {
326 return NT_STATUS_UNSUCCESSFUL;
329 *dn = talloc_steal(mem_ctx, msg->dn);
330 *sid = talloc_steal(mem_ctx, group_sid);
331 talloc_free(tmp_ctx);
332 return NT_STATUS_OK;
335 NTSTATUS dsdb_add_domain_alias(struct ldb_context *ldb,
336 TALLOC_CTX *mem_ctx,
337 const char *alias_name,
338 struct dom_sid **sid,
339 struct ldb_dn **dn)
341 const char *name;
342 struct ldb_message *msg;
343 struct dom_sid *alias_sid;
344 int ret;
346 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
347 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
349 /* Check if alias already exists */
350 name = samdb_search_string(ldb, tmp_ctx, NULL,
351 "sAMAccountName",
352 "(sAMAccountName=%s)(objectclass=group))",
353 ldb_binary_encode_string(mem_ctx, alias_name));
355 if (name != NULL) {
356 talloc_free(tmp_ctx);
357 return NT_STATUS_ALIAS_EXISTS;
360 msg = ldb_msg_new(tmp_ctx);
361 if (msg == NULL) {
362 talloc_free(tmp_ctx);
363 return NT_STATUS_NO_MEMORY;
366 /* add core elements to the ldb_message for the alias */
367 msg->dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(ldb));
368 ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", alias_name);
369 if (!msg->dn) {
370 talloc_free(tmp_ctx);
371 return NT_STATUS_NO_MEMORY;
374 samdb_msg_add_string(ldb, mem_ctx, msg, "sAMAccountName", alias_name);
375 samdb_msg_add_string(ldb, mem_ctx, msg, "objectClass", "group");
376 samdb_msg_add_int(ldb, mem_ctx, msg, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);
378 /* create the alias */
379 ret = ldb_add(ldb, msg);
380 switch (ret) {
381 case LDB_SUCCESS:
382 break;
383 case LDB_ERR_ENTRY_ALREADY_EXISTS:
384 talloc_free(tmp_ctx);
385 return NT_STATUS_ALIAS_EXISTS;
386 case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
387 talloc_free(tmp_ctx);
388 return NT_STATUS_ACCESS_DENIED;
389 default:
390 DEBUG(0,("Failed to create alias record %s: %s\n",
391 ldb_dn_get_linearized(msg->dn),
392 ldb_errstring(ldb)));
393 talloc_free(tmp_ctx);
394 return NT_STATUS_INTERNAL_DB_CORRUPTION;
397 /* retrieve the sid for the alias just created */
398 alias_sid = samdb_search_dom_sid(ldb, tmp_ctx,
399 msg->dn, "objectSid", NULL);
401 *dn = talloc_steal(mem_ctx, msg->dn);
402 *sid = talloc_steal(mem_ctx, alias_sid);
403 talloc_free(tmp_ctx);
405 return NT_STATUS_OK;
408 /* Return the members of this group (which may be a domain group or an alias) */
409 NTSTATUS dsdb_enum_group_mem(struct ldb_context *ldb,
410 TALLOC_CTX *mem_ctx,
411 struct ldb_dn *dn,
412 struct dom_sid **members_out,
413 unsigned int *pnum_members)
415 struct ldb_message *msg;
416 unsigned int i;
417 int ret;
418 struct dom_sid *members;
419 struct ldb_message_element *member_el;
420 const char *attrs[] = { "member", NULL };
421 NTSTATUS status;
422 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
423 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
425 ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE, attrs,
426 DSDB_SEARCH_SHOW_EXTENDED_DN, NULL);
427 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
428 talloc_free(tmp_ctx);
429 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
431 if (ret != LDB_SUCCESS) {
432 DEBUG(1, ("dsdb_enum_group_mem: dsdb_search for %s failed: %s\n",
433 ldb_dn_get_linearized(dn), ldb_errstring(ldb)));
434 return NT_STATUS_INTERNAL_DB_CORRUPTION;
437 member_el = ldb_msg_find_element(msg, "member");
438 if (!member_el) {
439 *members_out = NULL;
440 *pnum_members = 0;
441 talloc_free(tmp_ctx);
442 return NT_STATUS_OK;
445 members = talloc_array(mem_ctx, struct dom_sid, member_el->num_values);
446 if (members == NULL) {
447 return NT_STATUS_NO_MEMORY;
450 for (i=0; i <member_el->num_values; i++) {
451 struct ldb_dn *member_dn = ldb_dn_from_ldb_val(tmp_ctx, ldb,
452 &member_el->values[i]);
453 if (!member_dn || !ldb_dn_validate(member_dn)) {
454 DEBUG(1, ("Could not parse %*.*s as a DN\n",
455 (int)member_el->values[i].length,
456 (int)member_el->values[i].length,
457 (const char *)member_el->values[i].data));
458 talloc_free(tmp_ctx);
459 return NT_STATUS_INTERNAL_DB_CORRUPTION;
462 status = dsdb_get_extended_dn_sid(member_dn, &members[i], "SID");
463 if (!NT_STATUS_IS_OK(status)) {
464 DEBUG(1, ("Could find SID attribute on extended DN %s\n",
465 ldb_dn_get_extended_linearized(tmp_ctx, dn, 1)));
466 talloc_free(tmp_ctx);
467 return NT_STATUS_INTERNAL_DB_CORRUPTION;
471 *members_out = talloc_steal(mem_ctx, members);
472 *pnum_members = member_el->num_values;
473 talloc_free(tmp_ctx);
474 return NT_STATUS_OK;
477 NTSTATUS dsdb_lookup_rids(struct ldb_context *ldb,
478 TALLOC_CTX *mem_ctx,
479 const struct dom_sid *domain_sid,
480 unsigned int num_rids,
481 uint32_t *rids,
482 const char **names,
483 enum lsa_SidType *lsa_attrs)
485 const char *attrs[] = { "sAMAccountType", "sAMAccountName", NULL };
486 unsigned int i, num_mapped;
488 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
489 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
491 num_mapped = 0;
493 for (i=0; i<num_rids; i++) {
494 struct ldb_message *msg;
495 struct ldb_dn *dn;
496 uint32_t attr;
497 int rc;
499 lsa_attrs[i] = SID_NAME_UNKNOWN;
501 dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<SID=%s>",
502 dom_sid_string(tmp_ctx,
503 dom_sid_add_rid(tmp_ctx, domain_sid,
504 rids[i])));
505 if (!dn || !ldb_dn_validate(dn)) {
506 talloc_free(tmp_ctx);
507 return NT_STATUS_NO_MEMORY;
509 rc = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE, attrs, 0, "samAccountName=*");
510 if (rc == LDB_ERR_NO_SUCH_OBJECT) {
511 continue;
512 } else if (rc != LDB_SUCCESS) {
513 talloc_free(tmp_ctx);
514 return NT_STATUS_INTERNAL_DB_CORRUPTION;
517 names[i] = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);
518 if (names[i] == NULL) {
519 DEBUG(10, ("no samAccountName\n"));
520 continue;
522 talloc_steal(names, names[i]);
523 attr = ldb_msg_find_attr_as_uint(msg, "samAccountType", 0);
524 lsa_attrs[i] = ds_atype_map(attr);
525 if (lsa_attrs[i] == SID_NAME_UNKNOWN) {
526 continue;
528 num_mapped += 1;
530 talloc_free(tmp_ctx);
532 if (num_mapped == 0) {
533 return NT_STATUS_NONE_MAPPED;
535 if (num_mapped < num_rids) {
536 return STATUS_SOME_UNMAPPED;
538 return NT_STATUS_OK;