예제 #1
0
static WERROR sptr_SetPrintServerForm(struct ntptr_GenericHandle *server, TALLOC_CTX *mem_ctx,
				      struct spoolss_SetForm *r)
{
	struct ldb_context *sptr_db = talloc_get_type(server->ntptr->private_data, struct ldb_context);
	struct ldb_message *msg,**msgs;
	const char * const attrs[] = { "flags", NULL};
	int count, ret;
	enum spoolss_FormFlags flags;

	/* TODO: do checks access here
	 * if (!(server->access_mask & desired_access)) {
	 *	return WERR_FOOBAR;
	 * }
	 */

	switch (r->in.level) {
	case 1:
		if (!r->in.info.info1) {
			return WERR_FOOBAR;
		}

		count = sptr_db_search(sptr_db, mem_ctx,
				       ldb_dn_new(mem_ctx, sptr_db, "CN=Forms,CN=PrintServer"),
				       &msgs, attrs, "(&(form-name=%s)(objectClass=form))",
				       r->in.info.info1->form_name);

		if (count == 0) return WERR_FOOBAR;
		if (count > 1) return WERR_FOOBAR;
		if (count < 0) return WERR_GENERAL_FAILURE;

		flags = ldb_msg_find_attr_as_uint(msgs[0], "flags", SPOOLSS_FORM_BUILTIN);
		if (flags != SPOOLSS_FORM_USER) {
			return WERR_FOOBAR;
		}

		msg = ldb_msg_new(mem_ctx);
		W_ERROR_HAVE_NO_MEMORY(msg);

		/* add core elements to the ldb_message for the user */
		msg->dn = msgs[0]->dn;

		SET_UINT(sptr_db, msg, "flags", r->in.info.info1->flags);

		SET_STRING(sptr_db, msg, "form-name", r->in.info.info1->form_name);

		SET_UINT(sptr_db, msg, "size-width", r->in.info.info1->size.width);
		SET_UINT(sptr_db, msg, "size-height", r->in.info.info1->size.height);

		SET_UINT(sptr_db, msg, "area-left", r->in.info.info1->area.left);
		SET_UINT(sptr_db, msg, "area-top", r->in.info.info1->area.top);
		SET_UINT(sptr_db, msg, "area-right", r->in.info.info1->area.right);
		SET_UINT(sptr_db, msg, "area-bottom", r->in.info.info1->area.bottom);
		break;
	default:
		return WERR_UNKNOWN_LEVEL;
	}

	ret = dsdb_replace(sptr_db, msg, 0);
	if (ret != 0) {
		return WERR_FOOBAR;
	}

	return WERR_OK;
}
예제 #2
0
파일: schema_set.c 프로젝트: sprymak/samba
static int dsdb_schema_set_attributes(struct ldb_context *ldb, struct dsdb_schema *schema, bool write_attributes)
{
	int ret = LDB_SUCCESS;
	struct ldb_result *res;
	struct ldb_result *res_idx;
	struct dsdb_attribute *attr;
	struct ldb_message *mod_msg;
	TALLOC_CTX *mem_ctx;
	struct ldb_message *msg;
	struct ldb_message *msg_idx;

	/* setup our own attribute name to schema handler */
	ldb_schema_attribute_set_override_handler(ldb, dsdb_attribute_handler_override, schema);

	if (!write_attributes) {
		return ret;
	}

	mem_ctx = talloc_new(ldb);
	if (!mem_ctx) {
		return ldb_oom(ldb);
	}

	msg = ldb_msg_new(mem_ctx);
	if (!msg) {
		ldb_oom(ldb);
		goto op_error;
	}
	msg_idx = ldb_msg_new(mem_ctx);
	if (!msg_idx) {
		ldb_oom(ldb);
		goto op_error;
	}
	msg->dn = ldb_dn_new(msg, ldb, "@ATTRIBUTES");
	if (!msg->dn) {
		ldb_oom(ldb);
		goto op_error;
	}
	msg_idx->dn = ldb_dn_new(msg_idx, ldb, "@INDEXLIST");
	if (!msg_idx->dn) {
		ldb_oom(ldb);
		goto op_error;
	}

	ret = ldb_msg_add_string(msg_idx, "@IDXONE", "1");
	if (ret != LDB_SUCCESS) {
		goto op_error;
	}


	ret = ldb_msg_add_string(msg_idx, "@IDXVERSION", SAMDB_INDEXING_VERSION);
	if (ret != LDB_SUCCESS) {
		goto op_error;
	}

	for (attr = schema->attributes; attr; attr = attr->next) {
		const char *syntax = attr->syntax->ldb_syntax;

		if (!syntax) {
			syntax = attr->syntax->ldap_oid;
		}

		/*
		 * Write out a rough approximation of the schema
		 * as an @ATTRIBUTES value, for bootstrapping
		 */
		if (strcmp(syntax, LDB_SYNTAX_INTEGER) == 0) {
			ret = ldb_msg_add_string(msg, attr->lDAPDisplayName, "INTEGER");
		} else if (strcmp(syntax, LDB_SYNTAX_DIRECTORY_STRING) == 0) {
			ret = ldb_msg_add_string(msg, attr->lDAPDisplayName, "CASE_INSENSITIVE");
		}
		if (ret != LDB_SUCCESS) {
			break;
		}

		if (attr->searchFlags & SEARCH_FLAG_ATTINDEX) {
			ret = ldb_msg_add_string(msg_idx, "@IDXATTR", attr->lDAPDisplayName);
			if (ret != LDB_SUCCESS) {
				break;
			}
		}
	}

	if (ret != LDB_SUCCESS) {
		talloc_free(mem_ctx);
		return ret;
	}

	/*
	 * Try to avoid churning the attributes too much,
	 * we only want to do this if they have changed
	 */
	ret = ldb_search(ldb, mem_ctx, &res, msg->dn, LDB_SCOPE_BASE, NULL,
			 NULL);
	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
		ret = ldb_add(ldb, msg);
	} else if (ret != LDB_SUCCESS) {
	} else if (res->count != 1) {
		ret = ldb_add(ldb, msg);
	} else {
		ret = LDB_SUCCESS;
		/* Annoyingly added to our search results */
		ldb_msg_remove_attr(res->msgs[0], "distinguishedName");

		ret = ldb_msg_difference(ldb, mem_ctx,
		                         res->msgs[0], msg, &mod_msg);
		if (ret != LDB_SUCCESS) {
			goto op_error;
		}
		if (mod_msg->num_elements > 0) {
			ret = dsdb_replace(ldb, mod_msg, 0);
		}
		talloc_free(mod_msg);
	}

	if (ret == LDB_ERR_OPERATIONS_ERROR || ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS || ret == LDB_ERR_INVALID_DN_SYNTAX) {
		/* We might be on a read-only DB or LDAP */
		ret = LDB_SUCCESS;
	}
	if (ret != LDB_SUCCESS) {
		talloc_free(mem_ctx);
		return ret;
	}

	/* Now write out the indexes, as found in the schema (if they have changed) */

	ret = ldb_search(ldb, mem_ctx, &res_idx, msg_idx->dn, LDB_SCOPE_BASE,
			 NULL, NULL);
	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
		ret = ldb_add(ldb, msg_idx);
	} else if (ret != LDB_SUCCESS) {
	} else if (res_idx->count != 1) {
		ret = ldb_add(ldb, msg_idx);
	} else {
		ret = LDB_SUCCESS;
		/* Annoyingly added to our search results */
		ldb_msg_remove_attr(res_idx->msgs[0], "distinguishedName");

		ret = ldb_msg_difference(ldb, mem_ctx,
		                         res_idx->msgs[0], msg_idx, &mod_msg);
		if (ret != LDB_SUCCESS) {
			goto op_error;
		}
		if (mod_msg->num_elements > 0) {
			ret = dsdb_replace(ldb, mod_msg, 0);
		}
		talloc_free(mod_msg);
	}
	if (ret == LDB_ERR_OPERATIONS_ERROR || ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS || ret == LDB_ERR_INVALID_DN_SYNTAX) {
		/* We might be on a read-only DB */
		ret = LDB_SUCCESS;
	}
	talloc_free(mem_ctx);
	return ret;

op_error:
	talloc_free(mem_ctx);
	return ldb_operr(ldb);
}
예제 #3
0
WERROR dsdb_write_prefixes_from_schema_to_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
					      const struct dsdb_schema *schema)
{
	WERROR status;
	int ldb_ret;
	struct ldb_message *msg;
	struct ldb_dn *schema_dn;
	struct prefixMapBlob pfm_blob;
	struct ldb_val ndr_blob;
	enum ndr_err_code ndr_err;
	TALLOC_CTX *temp_ctx;
	struct drsuapi_DsReplicaOIDMapping_Ctr *ctr;

	schema_dn = ldb_get_schema_basedn(ldb);
	if (!schema_dn) {
		DEBUG(0,("dsdb_write_prefixes_from_schema_to_ldb: no schema dn present\n"));
		return WERR_FOOBAR;
	}

	temp_ctx = talloc_new(mem_ctx);
	W_ERROR_HAVE_NO_MEMORY(temp_ctx);

	/* convert schema_prefixMap to prefixMap blob */
	status = dsdb_get_oid_mappings_drsuapi(schema, false, temp_ctx, &ctr);
	if (!W_ERROR_IS_OK(status)) {
		talloc_free(temp_ctx);
		return status;
	}

	pfm_blob.version	= PREFIX_MAP_VERSION_DSDB;
	pfm_blob.ctr.dsdb	= *ctr;

	ndr_err = ndr_push_struct_blob(&ndr_blob, temp_ctx,
				       &pfm_blob,
				       (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		talloc_free(temp_ctx);
		return WERR_FOOBAR;
	}
 
	/* write serialized prefixMap into LDB */
	msg = ldb_msg_new(temp_ctx);
	if (!msg) {
		talloc_free(temp_ctx);
		return WERR_NOMEM;
	}

	msg->dn = schema_dn;
	ldb_ret = ldb_msg_add_value(msg, "prefixMap", &ndr_blob, NULL);
	if (ldb_ret != 0) {
		talloc_free(temp_ctx);
		DEBUG(0,("dsdb_write_prefixes_from_schema_to_ldb: ldb_msg_add_value failed\n"));	
		return WERR_NOMEM;
 	}
 
	ldb_ret = dsdb_replace(ldb, msg, DSDB_FLAG_AS_SYSTEM);

	talloc_free(temp_ctx);

	if (ldb_ret != 0) {
		DEBUG(0,("dsdb_write_prefixes_from_schema_to_ldb: dsdb_replace failed\n"));
		return WERR_FOOBAR;
 	}
 
	return WERR_OK;
}
예제 #4
0
/*
 * complete a domain join, when joining to a AD domain:
 * 1.) connect and bind to the DRSUAPI pipe
 * 2.) do a DsCrackNames() to find the machine account dn
 * 3.) connect to LDAP
 * 4.) do an ldap search to find the "msDS-KeyVersionNumber" of the machine account
 * 5.) set the servicePrincipalName's of the machine account via LDAP, (maybe we should use DsWriteAccountSpn()...)
 * 6.) do a DsCrackNames() to find the domain dn
 * 7.) find out Site specific stuff, look at libnet_JoinSite() for details
 */
static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_JoinDomain *r)
{
	NTSTATUS status;

	TALLOC_CTX *tmp_ctx;

	const char *realm = r->out.realm;

	struct dcerpc_binding *samr_binding = r->out.samr_binding;

	struct dcerpc_pipe *drsuapi_pipe;
	struct dcerpc_binding *drsuapi_binding;
	struct drsuapi_DsBind r_drsuapi_bind;
	struct drsuapi_DsCrackNames r_crack_names;
	struct drsuapi_DsNameString names[1];
	struct policy_handle drsuapi_bind_handle;
	struct GUID drsuapi_bind_guid;

	struct ldb_context *remote_ldb;
	struct ldb_dn *account_dn;
	const char *account_dn_str;
	const char *remote_ldb_url;
	struct ldb_result *res;
	struct ldb_message *msg;

	int ret, rtn;

	const char * const attrs[] = {
		"msDS-KeyVersionNumber",
		"servicePrincipalName",
		"dNSHostName",
		"objectGUID",
		NULL,
	};

	r->out.error_string = NULL;
	
	/* We need to convert between a samAccountName and domain to a
	 * DN in the directory.  The correct way to do this is with
	 * DRSUAPI CrackNames */

	/* Fiddle with the bindings, so get to DRSUAPI on
	 * NCACN_IP_TCP, sealed */
	tmp_ctx = talloc_named(r, 0, "libnet_JoinADSDomain temp context");  
	if (!tmp_ctx) {
		r->out.error_string = NULL;
		return NT_STATUS_NO_MEMORY;
	}
	                                           
	drsuapi_binding = talloc_zero(tmp_ctx, struct dcerpc_binding);
	if (!drsuapi_binding) {
		r->out.error_string = NULL;
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}
	
	*drsuapi_binding = *samr_binding;

	/* DRSUAPI is only available on IP_TCP, and locally on NCALRPC */
	if (drsuapi_binding->transport != NCALRPC) {
		drsuapi_binding->transport = NCACN_IP_TCP;
	}
	drsuapi_binding->endpoint = NULL;
	drsuapi_binding->flags |= DCERPC_SEAL;

	status = dcerpc_pipe_connect_b(tmp_ctx, 
				       &drsuapi_pipe,
				       drsuapi_binding,
				       &ndr_table_drsuapi,
				       ctx->cred, 
				       ctx->event_ctx,
				       ctx->lp_ctx);
	if (!NT_STATUS_IS_OK(status)) {
		r->out.error_string = talloc_asprintf(r,
					"Connection to DRSUAPI pipe of PDC of domain '%s' failed: %s",
					r->out.domain_name,
					nt_errstr(status));
		talloc_free(tmp_ctx);
		return status;
	}

	/* get a DRSUAPI pipe handle */
	GUID_from_string(DRSUAPI_DS_BIND_GUID, &drsuapi_bind_guid);

	r_drsuapi_bind.in.bind_guid = &drsuapi_bind_guid;
	r_drsuapi_bind.in.bind_info = NULL;
	r_drsuapi_bind.out.bind_handle = &drsuapi_bind_handle;

	status = dcerpc_drsuapi_DsBind_r(drsuapi_pipe->binding_handle, tmp_ctx, &r_drsuapi_bind);
	if (!NT_STATUS_IS_OK(status)) {
		r->out.error_string
			= talloc_asprintf(r,
					  "dcerpc_drsuapi_DsBind failed - %s",
					  nt_errstr(status));
		talloc_free(tmp_ctx);
		return status;
	} else if (!W_ERROR_IS_OK(r_drsuapi_bind.out.result)) {
		r->out.error_string
				= talloc_asprintf(r,
						  "DsBind failed - %s", 
						  win_errstr(r_drsuapi_bind.out.result));
			talloc_free(tmp_ctx);
		return NT_STATUS_UNSUCCESSFUL;
	}

	/* Actually 'crack' the names */
	ZERO_STRUCT(r_crack_names);
	r_crack_names.in.bind_handle		= &drsuapi_bind_handle;
	r_crack_names.in.level			= 1;
	r_crack_names.in.req			= talloc(r, union drsuapi_DsNameRequest);
	if (!r_crack_names.in.req) {
		r->out.error_string = NULL;
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}
	r_crack_names.in.req->req1.codepage	= 1252; /* western european */
	r_crack_names.in.req->req1.language	= 0x00000407; /* german */
	r_crack_names.in.req->req1.count	= 1;
	r_crack_names.in.req->req1.names	= names;
	r_crack_names.in.req->req1.format_flags	= DRSUAPI_DS_NAME_FLAG_NO_FLAGS;
	r_crack_names.in.req->req1.format_offered = DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY;
	r_crack_names.in.req->req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
	names[0].str = dom_sid_string(tmp_ctx, r->out.account_sid);
	if (!names[0].str) {
		r->out.error_string = NULL;
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	r_crack_names.out.ctr			= talloc(r, union drsuapi_DsNameCtr);
	r_crack_names.out.level_out		= talloc(r, uint32_t);
	if (!r_crack_names.out.ctr || !r_crack_names.out.level_out) {
		r->out.error_string = NULL;
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	status = dcerpc_drsuapi_DsCrackNames_r(drsuapi_pipe->binding_handle, tmp_ctx, &r_crack_names);
	if (!NT_STATUS_IS_OK(status)) {
		r->out.error_string
			= talloc_asprintf(r,
					  "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s",
					  names[0].str,
					  nt_errstr(status));
		talloc_free(tmp_ctx);
		return status;
	} else if (!W_ERROR_IS_OK(r_crack_names.out.result)) {
		r->out.error_string
				= talloc_asprintf(r,
						  "DsCrackNames failed - %s", win_errstr(r_crack_names.out.result));
		talloc_free(tmp_ctx);
		return NT_STATUS_UNSUCCESSFUL;
	} else if (*r_crack_names.out.level_out != 1
		   || !r_crack_names.out.ctr->ctr1
		   || r_crack_names.out.ctr->ctr1->count != 1) {
		r->out.error_string = talloc_asprintf(r, "DsCrackNames failed");
		talloc_free(tmp_ctx);
		return NT_STATUS_INVALID_PARAMETER;
	} else if (r_crack_names.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
		r->out.error_string = talloc_asprintf(r, "DsCrackNames failed: %d", r_crack_names.out.ctr->ctr1->array[0].status);
		talloc_free(tmp_ctx);
		return NT_STATUS_UNSUCCESSFUL;
	} else if (r_crack_names.out.ctr->ctr1->array[0].result_name == NULL) {
		r->out.error_string = talloc_asprintf(r, "DsCrackNames failed: no result name");
		talloc_free(tmp_ctx);
		return NT_STATUS_INVALID_PARAMETER;
	}

	/* Store the DN of our machine account. */
	account_dn_str = r_crack_names.out.ctr->ctr1->array[0].result_name;

	/* Now we know the user's DN, open with LDAP, read and modify a few things */

	remote_ldb_url = talloc_asprintf(tmp_ctx, "ldap://%s", 
					 drsuapi_binding->target_hostname);
	if (!remote_ldb_url) {
		r->out.error_string = NULL;
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	remote_ldb = ldb_wrap_connect(tmp_ctx, ctx->event_ctx, ctx->lp_ctx,
				      remote_ldb_url, 
				      NULL, ctx->cred, 0);
	if (!remote_ldb) {
		r->out.error_string = NULL;
		talloc_free(tmp_ctx);
		return NT_STATUS_UNSUCCESSFUL;
	}

	account_dn = ldb_dn_new(tmp_ctx, remote_ldb, account_dn_str);
	if (account_dn == NULL) {
		r->out.error_string = talloc_asprintf(r, "Invalid account dn: %s",
						      account_dn_str);
		talloc_free(tmp_ctx);
		return NT_STATUS_UNSUCCESSFUL;
	}

	/* search for the user's record */
	ret = ldb_search(remote_ldb, tmp_ctx, &res,
			 account_dn, LDB_SCOPE_BASE, attrs, NULL);
	if (ret != LDB_SUCCESS) {
		r->out.error_string = talloc_asprintf(r, "ldb_search for %s failed - %s",
						      account_dn_str, ldb_errstring(remote_ldb));
		talloc_free(tmp_ctx);
		return NT_STATUS_UNSUCCESSFUL;
	}

	if (res->count != 1) {
		r->out.error_string = talloc_asprintf(r, "ldb_search for %s failed - found %d entries",
						      account_dn_str, res->count);
		talloc_free(tmp_ctx);
		return NT_STATUS_UNSUCCESSFUL;
	}

	/* Prepare a new message, for the modify */
	msg = ldb_msg_new(tmp_ctx);
	if (!msg) {
		r->out.error_string = NULL;
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}
	msg->dn = res->msgs[0]->dn;

	{
		unsigned int i;
		const char *service_principal_name[2];
		const char *dns_host_name = strlower_talloc(msg,
							    talloc_asprintf(msg, 
									    "%s.%s", 
									    r->in.netbios_name, 
									    realm));

		if (!dns_host_name) {
			r->out.error_string = NULL;
			talloc_free(tmp_ctx);
			return NT_STATUS_NO_MEMORY;
		}

		service_principal_name[0] = talloc_asprintf(msg, "HOST/%s",
							    dns_host_name);
		service_principal_name[1] = talloc_asprintf(msg, "HOST/%s",
							    r->in.netbios_name);
		
		for (i=0; i < ARRAY_SIZE(service_principal_name); i++) {
			if (!service_principal_name[i]) {
				r->out.error_string = NULL;
				talloc_free(tmp_ctx);
				return NT_STATUS_NO_MEMORY;
			}
			rtn = ldb_msg_add_string(msg, "servicePrincipalName",
						 service_principal_name[i]);
			if (rtn != LDB_SUCCESS) {
				r->out.error_string = NULL;
				talloc_free(tmp_ctx);
				return NT_STATUS_NO_MEMORY;
			}
		}

		rtn = ldb_msg_add_string(msg, "dNSHostName", dns_host_name);
		if (rtn != LDB_SUCCESS) {
			r->out.error_string = NULL;
			talloc_free(tmp_ctx);
			return NT_STATUS_NO_MEMORY;
		}

		rtn = dsdb_replace(remote_ldb, msg, 0);
		if (rtn != LDB_SUCCESS) {
			r->out.error_string
				= talloc_asprintf(r, 
						  "Failed to replace entries on %s", 
						  ldb_dn_get_linearized(msg->dn));
			talloc_free(tmp_ctx);
			return NT_STATUS_INTERNAL_DB_CORRUPTION;
		}
	}
				
	msg = ldb_msg_new(tmp_ctx);
	if (!msg) {
		r->out.error_string = NULL;
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}
	msg->dn = res->msgs[0]->dn;

	rtn = samdb_msg_add_uint(remote_ldb, msg, msg,
				 "msDS-SupportedEncryptionTypes", ENC_ALL_TYPES);
	if (rtn != LDB_SUCCESS) {
		r->out.error_string = NULL;
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	rtn = dsdb_replace(remote_ldb, msg, 0);
	/* The remote server may not support this attribute, if it
	 * isn't a modern schema */
	if (rtn != LDB_SUCCESS && rtn != LDB_ERR_NO_SUCH_ATTRIBUTE) {
		r->out.error_string
			= talloc_asprintf(r,
					  "Failed to replace msDS-SupportedEncryptionTypes on %s",
					  ldb_dn_get_linearized(msg->dn));
		talloc_free(tmp_ctx);
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}

	/* DsCrackNames to find out the DN of the domain. */
	r_crack_names.in.req->req1.format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;
	r_crack_names.in.req->req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
	names[0].str = talloc_asprintf(tmp_ctx, "%s\\", r->out.domain_name);
	if (!names[0].str) {
		r->out.error_string = NULL;
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	status = dcerpc_drsuapi_DsCrackNames_r(drsuapi_pipe->binding_handle, tmp_ctx, &r_crack_names);
	if (!NT_STATUS_IS_OK(status)) {
		r->out.error_string
			= talloc_asprintf(r,
					  "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s",
					  r->in.domain_name,
					  nt_errstr(status));
		talloc_free(tmp_ctx);
		return status;
	} else if (!W_ERROR_IS_OK(r_crack_names.out.result)) {
		r->out.error_string
			= talloc_asprintf(r,
					  "DsCrackNames failed - %s", win_errstr(r_crack_names.out.result));
		talloc_free(tmp_ctx);
		return NT_STATUS_UNSUCCESSFUL;
	} else if (*r_crack_names.out.level_out != 1
		   || !r_crack_names.out.ctr->ctr1
		   || r_crack_names.out.ctr->ctr1->count != 1
		   || !r_crack_names.out.ctr->ctr1->array[0].result_name
		   || r_crack_names.out.ctr->ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
		r->out.error_string = talloc_asprintf(r, "DsCrackNames failed");
		talloc_free(tmp_ctx);
		return NT_STATUS_UNSUCCESSFUL;
	}

	/* Store the account DN. */
	r->out.account_dn_str = account_dn_str;
	talloc_steal(r, account_dn_str);

	/* Store the domain DN. */
	r->out.domain_dn_str = r_crack_names.out.ctr->ctr1->array[0].result_name;
	talloc_steal(r, r_crack_names.out.ctr->ctr1->array[0].result_name);

	/* Store the KVNO of the account, critical for some kerberos
	 * operations */
	r->out.kvno = ldb_msg_find_attr_as_uint(res->msgs[0], "msDS-KeyVersionNumber", 0);

	/* Store the account GUID. */
	r->out.account_guid = samdb_result_guid(res->msgs[0], "objectGUID");

	if (r->in.acct_type == ACB_SVRTRUST) {
		status = libnet_JoinSite(ctx, remote_ldb, r);
	}
	talloc_free(tmp_ctx);

	return status;
}
예제 #5
0
파일: util_samr.c 프로젝트: Arkhont/samba
/* Add a user, SAMR style, including the correct transaction
 * semantics.  Used by the SAMR server and by pdb_samba4 */
NTSTATUS dsdb_add_user(struct ldb_context *ldb,
		       TALLOC_CTX *mem_ctx,
		       const char *account_name,
		       uint32_t acct_flags,
		       struct dom_sid **sid,
		       struct ldb_dn **dn)
{
	const char *name;
	struct ldb_message *msg;
	int ret;
	const char *container, *obj_class=NULL;
	char *cn_name;
	size_t cn_name_len;

	const char *attrs[] = {
		"objectSid",
		"userAccountControl",
		NULL
	};

	uint32_t user_account_control;
	struct ldb_dn *account_dn;
	struct dom_sid *account_sid;

	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
	NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);

	/*
	 * Start a transaction, so we can query and do a subsequent atomic
	 * modify
	 */

	ret = ldb_transaction_start(ldb);
	if (ret != LDB_SUCCESS) {
		DEBUG(0,("Failed to start a transaction for user creation: %s\n",
			 ldb_errstring(ldb)));
		talloc_free(tmp_ctx);
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}

	/* check if the user already exists */
	name = samdb_search_string(ldb, tmp_ctx, NULL,
				   "sAMAccountName",
				   "(&(sAMAccountName=%s)(objectclass=user))",
				   ldb_binary_encode_string(tmp_ctx, account_name));
	if (name != NULL) {
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);
		return NT_STATUS_USER_EXISTS;
	}

	cn_name = talloc_strdup(tmp_ctx, account_name);
	if (!cn_name) {
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	cn_name_len = strlen(cn_name);
	if (cn_name_len < 1) {
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);
		return NT_STATUS_INVALID_PARAMETER;
	}

	msg = ldb_msg_new(tmp_ctx);
	if (msg == NULL) {
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	/* This must be one of these values *only* */
	if (acct_flags == ACB_NORMAL) {
		container = "CN=Users";
		obj_class = "user";

	} else if (acct_flags == ACB_WSTRUST) {
		if (cn_name[cn_name_len - 1] != '$') {
			ldb_transaction_cancel(ldb);
			return NT_STATUS_FOOBAR;
		}
		cn_name[cn_name_len - 1] = '\0';
		container = "CN=Computers";
		obj_class = "computer";

	} else if (acct_flags == ACB_SVRTRUST) {
		if (cn_name[cn_name_len - 1] != '$') {
			ldb_transaction_cancel(ldb);
			return NT_STATUS_FOOBAR;
		}
		cn_name[cn_name_len - 1] = '\0';
		container = "OU=Domain Controllers";
		obj_class = "computer";
	} else {
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);
		return NT_STATUS_INVALID_PARAMETER;
	}

	/* add core elements to the ldb_message for the user */
	msg->dn = ldb_dn_copy(msg, ldb_get_default_basedn(ldb));
	if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s,%s", cn_name, container)) {
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);
		return NT_STATUS_FOOBAR;
	}

	ldb_msg_add_string(msg, "sAMAccountName", account_name);
	ldb_msg_add_string(msg, "objectClass", obj_class);

	/* create the user */
	ret = ldb_add(ldb, msg);
	switch (ret) {
	case LDB_SUCCESS:
		break;
	case LDB_ERR_ENTRY_ALREADY_EXISTS:
		ldb_transaction_cancel(ldb);
		DEBUG(0,("Failed to create user record %s: %s\n",
			 ldb_dn_get_linearized(msg->dn),
			 ldb_errstring(ldb)));
		talloc_free(tmp_ctx);
		return NT_STATUS_USER_EXISTS;
	case LDB_ERR_UNWILLING_TO_PERFORM:
	case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
		ldb_transaction_cancel(ldb);
		DEBUG(0,("Failed to create user record %s: %s\n",
			 ldb_dn_get_linearized(msg->dn),
			 ldb_errstring(ldb)));
		talloc_free(tmp_ctx);
		return NT_STATUS_ACCESS_DENIED;
	default:
		ldb_transaction_cancel(ldb);
		DEBUG(0,("Failed to create user record %s: %s\n",
			 ldb_dn_get_linearized(msg->dn),
			 ldb_errstring(ldb)));
		talloc_free(tmp_ctx);
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}

	account_dn = msg->dn;

	/* retrieve the sid and account control bits for the user just created */
	ret = dsdb_search_one(ldb, tmp_ctx, &msg,
			      account_dn, LDB_SCOPE_BASE, attrs, 0, NULL);

	if (ret != LDB_SUCCESS) {
		ldb_transaction_cancel(ldb);
		DEBUG(0,("Can't locate the account we just created %s: %s\n",
			 ldb_dn_get_linearized(account_dn), ldb_errstring(ldb)));
		talloc_free(tmp_ctx);
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}
	account_sid = samdb_result_dom_sid(tmp_ctx, msg, "objectSid");
	if (account_sid == NULL) {
		ldb_transaction_cancel(ldb);
		DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n",
			 ldb_dn_get_linearized(msg->dn)));
		talloc_free(tmp_ctx);
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}

	/* Change the account control to be the correct account type.
	 * The default is for a workstation account */
	user_account_control = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
	user_account_control = (user_account_control &
				~(UF_NORMAL_ACCOUNT |
				  UF_INTERDOMAIN_TRUST_ACCOUNT |
				  UF_WORKSTATION_TRUST_ACCOUNT |
				  UF_SERVER_TRUST_ACCOUNT));
	user_account_control |= ds_acb2uf(acct_flags);

	talloc_free(msg);
	msg = ldb_msg_new(tmp_ctx);
	if (msg == NULL) {
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	msg->dn = account_dn;

	if (samdb_msg_add_uint(ldb, tmp_ctx, msg,
			       "userAccountControl",
			       user_account_control) != LDB_SUCCESS) {
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	/* modify the samdb record */
	ret = dsdb_replace(ldb, msg, 0);
	if (ret != LDB_SUCCESS) {
		DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
			 ldb_dn_get_linearized(msg->dn),
			 ldb_errstring(ldb)));
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);

		/* we really need samdb.c to return NTSTATUS */
		return NT_STATUS_UNSUCCESSFUL;
	}

	ret = ldb_transaction_commit(ldb);
	if (ret != LDB_SUCCESS) {
		DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
			 ldb_dn_get_linearized(msg->dn),
			 ldb_errstring(ldb)));
		talloc_free(tmp_ctx);
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}
	*dn = talloc_steal(mem_ctx, account_dn);
	*sid = talloc_steal(mem_ctx, account_sid);
	talloc_free(tmp_ctx);
	return NT_STATUS_OK;
}