Пример #1
0
static bool swap_sid_in_acl( struct security_descriptor *sd, struct dom_sid *s1, struct dom_sid *s2 )
{
	struct security_acl *theacl;
	int i;
	bool update = False;

	verbose_output("  Owner SID: %s\n", sid_string_tos(sd->owner_sid));
	if ( dom_sid_equal( sd->owner_sid, s1 ) ) {
		sid_copy( sd->owner_sid, s2 );
		update = True;
		verbose_output("  New Owner SID: %s\n",
			sid_string_tos(sd->owner_sid));

	}

	verbose_output("  Group SID: %s\n", sid_string_tos(sd->group_sid));
	if ( dom_sid_equal( sd->group_sid, s1 ) ) {
		sid_copy( sd->group_sid, s2 );
		update = True;
		verbose_output("  New Group SID: %s\n",
			sid_string_tos(sd->group_sid));
	}

	theacl = sd->dacl;
	verbose_output("  DACL: %d entries:\n", theacl->num_aces);
	for ( i=0; i<theacl->num_aces; i++ ) {
		verbose_output("    Trustee SID: %s\n",
			sid_string_tos(&theacl->aces[i].trustee));
		if ( dom_sid_equal( &theacl->aces[i].trustee, s1 ) ) {
			sid_copy( &theacl->aces[i].trustee, s2 );
			update = True;
			verbose_output("    New Trustee SID: %s\n",
				sid_string_tos(&theacl->aces[i].trustee));
		}
	}

#if 0
	theacl = sd->sacl;
	verbose_output("  SACL: %d entries: \n", theacl->num_aces);
	for ( i=0; i<theacl->num_aces; i++ ) {
		verbose_output("    Trustee SID: %s\n",
			sid_string_tos(&theacl->aces[i].trustee));
		if ( dom_sid_equal( &theacl->aces[i].trustee, s1 ) ) {
			sid_copy( &theacl->aces[i].trustee, s2 );
			update = True;
			verbose_output("    New Trustee SID: %s\n",
				sid_string_tos(&theacl->aces[i].trustee));
		}
	}
#endif
	return update;
}
static void init_domain_recv_queryinfo(struct tevent_req *subreq)
{
	struct init_domain_state *state =
		tevent_req_callback_data(subreq,
		struct init_domain_state);
	struct lsa_DomainInfo *dominfo;
	struct composite_context *ctx;
	uint32_t lflags;

	state->ctx->status = dcerpc_lsa_QueryInfoPolicy_r_recv(subreq, state);
	TALLOC_FREE(subreq);
	if (!composite_is_ok(state->ctx)) return;
	state->ctx->status = state->queryinfo.out.result;
	if (!composite_is_ok(state->ctx)) return;

	if (!dom_sid_equal(state->domain->info->sid, &global_sid_Builtin)) {
		dominfo = &(*state->queryinfo.out.info)->account_domain;
		
		if (strcasecmp(state->domain->info->name, dominfo->name.string) != 0) {
			DEBUG(2, ("Expected domain name %s, DC %s said %s\n",
				  state->domain->info->name,
				  dcerpc_server_name(state->domain->libnet_ctx->lsa.pipe),
				  dominfo->name.string));
			composite_error(state->ctx, NT_STATUS_INVALID_DOMAIN_STATE);
			return;
		}
		
		if (!dom_sid_equal(state->domain->info->sid, dominfo->sid)) {
			DEBUG(2, ("Expected domain sid %s, DC %s said %s\n",
				  dom_sid_string(state, state->domain->info->sid),
				  dcerpc_server_name(state->domain->libnet_ctx->lsa.pipe),
				  dom_sid_string(state, dominfo->sid)));
			composite_error(state->ctx, NT_STATUS_INVALID_DOMAIN_STATE);
			return;
		}
	}

	state->domain->samr_binding = init_domain_binding(state, &ndr_table_samr);

	/* We want to use the same flags as the LSA pipe did (so, if
	 * it needed schannel, then we need that here too) */
	lflags = dcerpc_binding_get_flags(state->domain->lsa_binding);
	state->ctx->status = dcerpc_binding_set_flags(state->domain->samr_binding,
						      lflags, 0);
	if (!composite_is_ok(state->ctx)) return;

	state->domain->libnet_ctx->samr.pipe = NULL;
	state->domain->libnet_ctx->samr.samr_handle = NULL;

	ctx = wb_connect_samr_send(state, state->domain);
	composite_continue(state->ctx, ctx, init_domain_recv_samr, state);
}
Пример #3
0
bool non_mappable_sid(struct dom_sid *sid)
{
	struct dom_sid dom;

	sid_copy(&dom, sid);
	sid_split_rid(&dom, NULL);

	if (dom_sid_equal(&dom, &global_sid_Builtin))
		return True;

	if (dom_sid_equal(&dom, &global_sid_NT_Authority))
		return True;

	return False;
}
Пример #4
0
static bool desc_ace_has_generic(TALLOC_CTX *mem_ctx,
			     struct security_ace *ace)
{
	struct dom_sid *co, *cg;
	co = dom_sid_parse_talloc(mem_ctx,  SID_CREATOR_OWNER);
	cg = dom_sid_parse_talloc(mem_ctx,  SID_CREATOR_GROUP);
	if (ace->access_mask & SEC_GENERIC_ALL || ace->access_mask & SEC_GENERIC_READ ||
	    ace->access_mask & SEC_GENERIC_WRITE || ace->access_mask & SEC_GENERIC_EXECUTE) {
		return true;
	}
	if (dom_sid_equal(&ace->trustee, co) || dom_sid_equal(&ace->trustee, cg)) {
		return true;
	}
	return false;
}
Пример #5
0
bool security_token_is_sid(const struct security_token *token, const struct dom_sid *sid)
{
	if (dom_sid_equal(token->user_sid, sid)) {
		return true;
	}
	return false;
}
Пример #6
0
static void desc_expand_generic(TALLOC_CTX *mem_ctx,
				struct security_ace *new_ace,
				struct dom_sid *owner,
				struct dom_sid *group)
{
	struct dom_sid *co, *cg;
	co = dom_sid_parse_talloc(mem_ctx,  SID_CREATOR_OWNER);
	cg = dom_sid_parse_talloc(mem_ctx,  SID_CREATOR_GROUP);
	new_ace->access_mask = map_generic_rights_ds(new_ace->access_mask);
	if (dom_sid_equal(&new_ace->trustee, co)) {
		new_ace->trustee = *owner;
	}
	if (dom_sid_equal(&new_ace->trustee, cg)) {
		new_ace->trustee = *group;
	}
	new_ace->flags = 0x0;
}
Пример #7
0
bool security_token_has_sid(const struct security_token *token, const struct dom_sid *sid)
{
	int i;
	for (i = 0; i < token->num_sids; i++) {
		if (dom_sid_equal(token->sids[i], sid)) {
			return true;
		}
	}
	return false;
}
Пример #8
0
bool token_sid_in_ace(const struct security_token *token, const struct security_ace *ace)
{
	size_t i;

	for (i = 0; i < token->num_sids; i++) {
		if (dom_sid_equal(&ace->trustee, &token->sids[i]))
			return true;
	}

	return false;
}
Пример #9
0
/* This function tests if a SID structure "sids" contains the SID "sid" */
static bool sids_contains_sid(const struct dom_sid *sids,
			      const unsigned int num_sids,
			      const struct dom_sid *sid)
{
	unsigned int i;

	for (i = 0; i < num_sids; i++) {
		if (dom_sid_equal(&sids[i], sid))
			return true;
	}
	return false;
}
Пример #10
0
bool nt_token_check_sid( const struct dom_sid *sid, const NT_USER_TOKEN *token)
{
	int i;

	if (!sid || !token) {
		return false;
	}

	if (dom_sid_equal(sid, token->user_sid)) {
		return true;
	}
	if (dom_sid_equal(sid, token->group_sid)) {
		return true;
	}
	for (i = 0; i < token->num_sids; i++) {
		if (dom_sid_equal(sid, token->sids[i])) {
			return true;
		}
	}

	return false;
}
Пример #11
0
/*
  see if any SIDs in list1 are in list2
 */
bool sid_list_match(const struct dom_sid **list1, const struct dom_sid **list2)
{
	unsigned int i, j;
	/* do we ever have enough SIDs here to worry about O(n^2) ? */
	for (i=0; list1[i]; i++) {
		for (j=0; list2[j]; j++) {
			if (dom_sid_equal(list1[i], list2[j])) {
				return true;
			}
		}
	}
	return false;
}
Пример #12
0
bool sid_check_is_wellknown_domain(const struct dom_sid *sid, const char **name)
{
	int i;

	for (i=0; special_domains[i].sid != NULL; i++) {
		if (dom_sid_equal(sid, special_domains[i].sid)) {
			if (name != NULL) {
				*name = special_domains[i].name;
			}
			return True;
		}
	}
	return False;
}
Пример #13
0
static struct wbsrv_domain *find_domain_from_sid(struct wbsrv_service *service,
						 const struct dom_sid *sid)
{
	struct wbsrv_domain *domain;

	for (domain = service->domains; domain!=NULL; domain = domain->next) {
		if (dom_sid_equal(domain->info->sid, sid)) {
			break;
		}
		if (dom_sid_in_domain(domain->info->sid, sid)) {
			break;
		}
	}
	return domain;
}
Пример #14
0
/**
 * Helper for sids_to_unix_ids: find entry by SID in mapping array,
 * search up to IDMAP_AD_MAX_IDS entries
 */
struct id_map *idmap_find_map_by_sid(struct id_map **maps, struct dom_sid *sid)
{
	int i;

	for (i = 0; i < IDMAP_LDAP_MAX_IDS; i++) {
		if (maps[i] == NULL) { /* end of the run */
			return NULL;
		}
		if (dom_sid_equal(maps[i]->sid, sid)) {
			return maps[i];
		}
	}

	return NULL;
}
Пример #15
0
static void init_domain_recv_queryinfo(struct rpc_request *req)
{
	struct init_domain_state *state =
		talloc_get_type(req->async.private_data, struct init_domain_state);
	struct lsa_DomainInfo *dominfo;
	struct composite_context *ctx;

	state->ctx->status = dcerpc_ndr_request_recv(req);
	if (!composite_is_ok(state->ctx)) return;
	state->ctx->status = state->queryinfo.out.result;
	if (!composite_is_ok(state->ctx)) return;

	dominfo = &state->queryinfo.out.info->account_domain;

	if (strcasecmp(state->domain->info->name, dominfo->name.string) != 0) {
		DEBUG(2, ("Expected domain name %s, DC %s said %s\n",
			  state->domain->info->name,
			  dcerpc_server_name(state->domain->lsa_pipe),
			  dominfo->name.string));
		composite_error(state->ctx, NT_STATUS_INVALID_DOMAIN_STATE);
		return;
	}

	if (!dom_sid_equal(state->domain->info->sid, dominfo->sid)) {
		DEBUG(2, ("Expected domain sid %s, DC %s said %s\n",
			  dom_sid_string(state, state->domain->info->sid),
			  dcerpc_server_name(state->domain->lsa_pipe),
			  dom_sid_string(state, dominfo->sid)));
		composite_error(state->ctx, NT_STATUS_INVALID_DOMAIN_STATE);
		return;
	}

	state->domain->samr_binding = init_domain_binding(state, &dcerpc_table_samr);

	/* We want to use the same flags as the LSA pipe did (so, if
	 * it needed schannel, then we need that here too) */
	state->domain->samr_binding->flags = state->domain->lsa_binding->flags;

	state->domain->samr_pipe = NULL;

	ctx = wb_connect_samr_send(state, state->domain);
	composite_continue(state->ctx, ctx, init_domain_recv_samr, state);
}
static struct dcerpc_binding *init_domain_binding(struct init_domain_state *state, 
						  const struct ndr_interface_table *table) 
{
	struct dcerpc_binding *binding;
	enum dcerpc_transport_t transport;
	char *s;
	NTSTATUS status;

	/* Make a binding string */
	if ((lpcfg_server_role(state->service->task->lp_ctx) != ROLE_DOMAIN_MEMBER) &&
	    dom_sid_equal(state->domain->info->sid, state->service->primary_sid) &&
	    state->service->sec_channel_type != SEC_CHAN_RODC) {
		s = talloc_asprintf(state, "ncalrpc:%s[target_hostname=%s]",
				    state->domain->dc_address,
				    state->domain->dc_name);
		if (s == NULL) return NULL;
	} else {
		s = talloc_asprintf(state, "ncacn_np:%s[target_hostname=%s]",
				    state->domain->dc_address,
				    state->domain->dc_name);
		if (s == NULL) return NULL;

	}
	status = dcerpc_parse_binding(state, s, &binding);
	talloc_free(s);
	if (!NT_STATUS_IS_OK(status)) {
		return NULL;
	}

	transport = dcerpc_binding_get_transport(binding);
	if (transport == NCALRPC) {
		return binding;
	}

	/* This shouldn't make a network call, as the mappings for named pipes are well known */
	status = dcerpc_epm_map_binding(binding, binding, table, state->service->task->event_ctx,
					state->service->task->lp_ctx);
	if (!NT_STATUS_IS_OK(status)) {
		return NULL;
	}

	return binding;
}
Пример #17
0
/**
  find an internal handle given a wire handle. If the wire handle is NULL then
  allocate a new handle
*/
_PUBLIC_ struct dcesrv_handle *dcesrv_handle_fetch(
					  struct dcesrv_connection_context *context, 
					  struct policy_handle *p,
					  uint8_t handle_type)
{
	struct dcesrv_handle *h;
	struct dom_sid *sid;

	sid = context->conn->auth_state.session_info->security_token->user_sid;

	if (policy_handle_empty(p)) {
		/* TODO: we should probably return a NULL handle here */
		return dcesrv_handle_new(context, handle_type);
	}

	for (h=context->assoc_group->handles; h; h=h->next) {
		if (h->wire_handle.handle_type == p->handle_type &&
		    GUID_equal(&p->uuid, &h->wire_handle.uuid)) {
			if (handle_type != DCESRV_HANDLE_ANY &&
			    p->handle_type != handle_type) {
				DEBUG(0,("client gave us the wrong handle type (%d should be %d)\n",
					 p->handle_type, handle_type));
				return NULL;
			}
			if (!dom_sid_equal(h->sid, sid)) {
				DEBUG(0,(__location__ ": Attempt to use invalid sid %s - %s\n",
					 dom_sid_string(context, h->sid),
					 dom_sid_string(context, sid)));
				return NULL;
			}
			if (h->iface != context->iface) {
				DEBUG(0,(__location__ ": Attempt to use invalid iface\n"));
				return NULL;
			}
			return h;
		}
	}

	return NULL;
}
Пример #18
0
bool lookup_wellknown_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
			  const char **domain, const char **name)
{
	int i;
	struct dom_sid dom_sid;
	uint32_t rid;
	const struct rid_name_map *users = NULL;

	sid_copy(&dom_sid, sid);
	if (!sid_split_rid(&dom_sid, &rid)) {
		DEBUG(2, ("Could not split rid from SID\n"));
		return False;
	}

	for (i=0; special_domains[i].sid != NULL; i++) {
		if (dom_sid_equal(&dom_sid, special_domains[i].sid)) {
			*domain = talloc_strdup(mem_ctx,
						special_domains[i].name);
			users = special_domains[i].known_users;
			break;
		}
	}

	if (users == NULL) {
		DEBUG(10, ("SID %s is no special sid\n", sid_string_dbg(sid)));
		return False;
	}

	for (i=0; users[i].name != NULL; i++) {
		if (rid == users[i].rid) {
			*name = talloc_strdup(mem_ctx, users[i].name);
			return True;
		}
	}

	DEBUG(10, ("RID of special SID %s not found\n", sid_string_dbg(sid)));

	return False;
}
Пример #19
0
enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
							struct winbindd_cli_state *state)
{
	int i;
	int extra_data_len = 0;
	char *extra_data;
	NTSTATUS result;
	bool have_own_domain = False;
	struct netr_DomainTrustList trusts;

	DEBUG(3, ("[%5lu]: list trusted domains\n",
		  (unsigned long)state->pid));

	result = domain->methods->trusted_domains(domain, state->mem_ctx,
						  &trusts);

	if (!NT_STATUS_IS_OK(result)) {
		DEBUG(3, ("winbindd_dual_list_trusted_domains: trusted_domains returned %s\n",
			nt_errstr(result) ));
		return WINBINDD_ERROR;
	}

	extra_data = talloc_strdup(state->mem_ctx, "");

	for (i=0; i<trusts.count; i++) {

		if (trusts.array[i].sid == NULL) {
			continue;
		}
		if (dom_sid_equal(trusts.array[i].sid, &global_sid_NULL)) {
			continue;
		}

		extra_data = talloc_asprintf_append_buffer(
		    extra_data, "%s\\%s\\%s\\%u\\%u\\%u\n",
		    trusts.array[i].netbios_name, trusts.array[i].dns_name,
		    sid_string_talloc(state->mem_ctx, trusts.array[i].sid),
		    trusts.array[i].trust_flags,
		    (uint32_t)trusts.array[i].trust_type,
		    trusts.array[i].trust_attributes);
	}

	/* add our primary domain */

	for (i=0; i<trusts.count; i++) {
		if (strequal(trusts.array[i].netbios_name, domain->name)) {
			have_own_domain = True;
			break;
		}
	}

	if (state->request->data.list_all_domains && !have_own_domain) {
		extra_data = talloc_asprintf_append_buffer(
			extra_data, "%s\\%s\\%s\n", domain->name,
			domain->alt_name != NULL ?
				domain->alt_name :
				domain->name,
			sid_string_talloc(state->mem_ctx, &domain->sid));
	}

	extra_data_len = strlen(extra_data);
	if (extra_data_len > 0) {

		/* Strip the last \n */
		extra_data[extra_data_len-1] = '\0';

		state->response->extra_data.data = extra_data;
		state->response->length += extra_data_len;
	}

	return WINBINDD_OK;
}
/* Add a trusted domain to our list of domains */
static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
						  struct winbindd_methods *methods,
						  const struct dom_sid *sid)
{
	struct winbindd_domain *domain;
	const char *alternative_name = NULL;
	char *idmap_config_option;
	const char *param;
	const char **ignored_domains, **dom;

	ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
	for (dom=ignored_domains; dom && *dom; dom++) {
		if (gen_fnmatch(*dom, domain_name) == 0) {
			DEBUG(2,("Ignoring domain '%s'\n", domain_name));
			return NULL;
		}
	}

	/* use alt_name if available to allow DNS lookups */

	if (alt_name && *alt_name) {
		alternative_name = alt_name;
	}

	/* We can't call domain_list() as this function is called from
	   init_domain_list() and we'll get stuck in a loop. */
	for (domain = _domain_list; domain; domain = domain->next) {
		if (strequal(domain_name, domain->name) ||
		    strequal(domain_name, domain->alt_name))
		{
			break;
		}

		if (alternative_name && *alternative_name)
		{
			if (strequal(alternative_name, domain->name) ||
			    strequal(alternative_name, domain->alt_name))
			{
				break;
			}
		}

		if (sid)
		{
			if (is_null_sid(sid)) {
				continue;
			}

			if (dom_sid_equal(sid, &domain->sid)) {
				break;
			}
		}
	}

	if (domain != NULL) {
		/*
		 * We found a match. Possibly update the SID
		 */
		if ((sid != NULL)
		    && dom_sid_equal(&domain->sid, &global_sid_NULL)) {
			sid_copy( &domain->sid, sid );
		}
		return domain;
	}

	/* Create new domain entry */
	domain = talloc_zero(NULL, struct winbindd_domain);
	if (domain == NULL) {
		return NULL;
	}

	domain->children = talloc_zero_array(domain,
					     struct winbindd_child,
					     lp_winbind_max_domain_connections());
	if (domain->children == NULL) {
		TALLOC_FREE(domain);
		return NULL;
	}

	domain->name = talloc_strdup(domain, domain_name);
	if (domain->name == NULL) {
		TALLOC_FREE(domain);
		return NULL;
	}

	if (alternative_name) {
		domain->alt_name = talloc_strdup(domain, alternative_name);
		if (domain->alt_name == NULL) {
			TALLOC_FREE(domain);
			return NULL;
		}
	}

	domain->methods = methods;
	domain->backend = NULL;
	domain->internal = is_internal_domain(sid);
	domain->sequence_number = DOM_SEQUENCE_NONE;
	domain->last_seq_check = 0;
	domain->initialized = False;
	domain->online = is_internal_domain(sid);
	domain->check_online_timeout = 0;
	domain->dc_probe_pid = (pid_t)-1;
	if (sid) {
		sid_copy(&domain->sid, sid);
	}

	/* Link to domain list */
	DLIST_ADD_END(_domain_list, domain, struct winbindd_domain *);

	wcache_tdc_add_domain( domain );

	idmap_config_option = talloc_asprintf(talloc_tos(), "idmap config %s",
					      domain->name);
	if (idmap_config_option == NULL) {
		DEBUG(0, ("talloc failed, not looking for idmap config\n"));
		goto done;
	}

	param = lp_parm_const_string(-1, idmap_config_option, "range", NULL);

	DEBUG(10, ("%s : range = %s\n", idmap_config_option,
		   param ? param : "not defined"));

	if (param != NULL) {
		unsigned low_id, high_id;
		if (sscanf(param, "%u - %u", &low_id, &high_id) != 2) {
			DEBUG(1, ("invalid range syntax in %s: %s\n",
				  idmap_config_option, param));
			goto done;
		}
		if (low_id > high_id) {
			DEBUG(1, ("invalid range in %s: %s\n",
				  idmap_config_option, param));
			goto done;
		}
		domain->have_idmap_config = true;
		domain->id_range_low = low_id;
		domain->id_range_high = high_id;
	}

done:

	DEBUG(2,("Added domain %s %s %s\n",
		 domain->name, domain->alt_name,
		 &domain->sid?sid_string_dbg(&domain->sid):""));

	return domain;
}
Пример #21
0
/* Add a trusted domain out of a trusted domain cache
   entry
*/
static struct winbindd_domain *
add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
{
	struct winbindd_domain *domain;
	const char *alternative_name = NULL;
	const char **ignored_domains, **dom;
	int role = lp_server_role();
	const char *domain_name = tdc->domain_name;
	const struct dom_sid *sid = &tdc->sid;

	if (is_null_sid(sid)) {
		sid = NULL;
	}

	ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
	for (dom=ignored_domains; dom && *dom; dom++) {
		if (gen_fnmatch(*dom, domain_name) == 0) {
			DEBUG(2,("Ignoring domain '%s'\n", domain_name));
			return NULL;
		}
	}

	/* use alt_name if available to allow DNS lookups */

	if (tdc->dns_name && *tdc->dns_name) {
		alternative_name = tdc->dns_name;
	}

	/* We can't call domain_list() as this function is called from
	   init_domain_list() and we'll get stuck in a loop. */
	for (domain = _domain_list; domain; domain = domain->next) {
		if (strequal(domain_name, domain->name) ||
		    strequal(domain_name, domain->alt_name))
		{
			break;
		}

		if (alternative_name) {
			if (strequal(alternative_name, domain->name) ||
			    strequal(alternative_name, domain->alt_name))
			{
				break;
			}
		}

		if (sid != NULL) {
			if (dom_sid_equal(sid, &domain->sid)) {
				break;
			}
		}
	}

	if (domain != NULL) {
		/*
		 * We found a match on domain->name or
		 * domain->alt_name. Possibly update the SID
		 * if the stored SID was the NULL SID
		 * and return the matching entry.
		 */
		if ((sid != NULL)
		    && dom_sid_equal(&domain->sid, &global_sid_NULL)) {
			sid_copy( &domain->sid, sid );
		}
		return domain;
	}

	/* Create new domain entry */
	domain = talloc_zero(NULL, struct winbindd_domain);
	if (domain == NULL) {
		return NULL;
	}

	domain->children = talloc_zero_array(domain,
					     struct winbindd_child,
					     lp_winbind_max_domain_connections());
	if (domain->children == NULL) {
		TALLOC_FREE(domain);
		return NULL;
	}

	domain->name = talloc_strdup(domain, domain_name);
	if (domain->name == NULL) {
		TALLOC_FREE(domain);
		return NULL;
	}

	if (alternative_name) {
		domain->alt_name = talloc_strdup(domain, alternative_name);
		if (domain->alt_name == NULL) {
			TALLOC_FREE(domain);
			return NULL;
		}
	}

	domain->backend = NULL;
	domain->internal = is_internal_domain(sid);
	domain->sequence_number = DOM_SEQUENCE_NONE;
	domain->last_seq_check = 0;
	domain->initialized = false;
	domain->online = is_internal_domain(sid);
	domain->check_online_timeout = 0;
	domain->dc_probe_pid = (pid_t)-1;
	if (sid != NULL) {
		sid_copy(&domain->sid, sid);
	}
	domain->domain_flags = tdc->trust_flags;
	domain->domain_type = tdc->trust_type;
	domain->domain_trust_attribs = tdc->trust_attribs;

	/* Is this our primary domain ? */
	if (strequal(domain_name, get_global_sam_name()) &&
			(role != ROLE_DOMAIN_MEMBER)) {
		domain->primary = true;
	} else if (strequal(domain_name, lp_workgroup()) &&
			(role == ROLE_DOMAIN_MEMBER)) {
		domain->primary = true;
	}

	if (domain->primary) {
		if (role == ROLE_ACTIVE_DIRECTORY_DC) {
			domain->active_directory = true;
		}
		if (lp_security() == SEC_ADS) {
			domain->active_directory = true;
		}
	} else if (!domain->internal) {
		if (domain->domain_type == LSA_TRUST_TYPE_UPLEVEL) {
			domain->active_directory = true;
		}
	}

	/* Link to domain list */
	DLIST_ADD_END(_domain_list, domain);

	wcache_tdc_add_domain( domain );

	setup_domain_child(domain);

	DEBUG(2,
	      ("Added domain %s %s %s\n", domain->name, domain->alt_name,
	       !is_null_sid(&domain->sid) ? sid_string_dbg(&domain->sid) : ""));

	return domain;
}
/*
  The main entry point for access checking. If returning ACCESS_DENIED
  this function returns the denied bits in the uint32_t pointed
  to by the access_granted pointer.
*/
NTSTATUS se_access_check(const struct security_descriptor *sd,
			  const struct security_token *token,
			  uint32_t access_desired,
			  uint32_t *access_granted)
{
	uint32_t i;
	uint32_t bits_remaining;
	uint32_t explicitly_denied_bits = 0;
	/*
	 * Up until Windows Server 2008, owner always had these rights. Now
	 * we have to use Owner Rights perms if they are on the file.
	 *
	 * In addition we have to accumulate these bits and apply them
	 * correctly. See bug #8795
	 */
	uint32_t owner_rights_allowed = 0;
	uint32_t owner_rights_denied = 0;
	bool owner_rights_default = true;

	*access_granted = access_desired;
	bits_remaining = access_desired;

	/* handle the maximum allowed flag */
	if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) {
		uint32_t orig_access_desired = access_desired;

		access_desired |= access_check_max_allowed(sd, token);
		access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED;
		*access_granted = access_desired;
		bits_remaining = access_desired;

		DEBUG(10,("se_access_check: MAX desired = 0x%x, granted = 0x%x, remaining = 0x%x\n",
			orig_access_desired,
			*access_granted,
			bits_remaining));
	}

	/* a NULL dacl allows access */
	if ((sd->type & SEC_DESC_DACL_PRESENT) && sd->dacl == NULL) {
		*access_granted = access_desired;
		return NT_STATUS_OK;
	}

	if (sd->dacl == NULL) {
		goto done;
	}

	/* check each ace in turn. */
	for (i=0; bits_remaining && i < sd->dacl->num_aces; i++) {
		struct security_ace *ace = &sd->dacl->aces[i];

		if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
			continue;
		}

		/*
		 * We need the Owner Rights permissions to ensure we
		 * give or deny the correct permissions to the owner. Replace
		 * owner_rights with the perms here if it is present.
		 *
		 * We don't care if we are not the owner because that is taken
		 * care of below when we check if our token has the owner SID.
		 *
		 */
		if (dom_sid_equal(&ace->trustee, &global_sid_Owner_Rights)) {
			if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED) {
				owner_rights_allowed |= ace->access_mask;
				owner_rights_default = false;
			} else if (ace->type == SEC_ACE_TYPE_ACCESS_DENIED) {
				owner_rights_denied |= ace->access_mask;
				owner_rights_default = false;
			}
			continue;
		}

		if (!security_token_has_sid(token, &ace->trustee)) {
			continue;
		}

		switch (ace->type) {
		case SEC_ACE_TYPE_ACCESS_ALLOWED:
			bits_remaining &= ~ace->access_mask;
			break;
		case SEC_ACE_TYPE_ACCESS_DENIED:
		case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
			explicitly_denied_bits |= (bits_remaining & ace->access_mask);
			break;
		default:	/* Other ACE types not handled/supported */
			break;
		}
	}

	/* Explicitly denied bits always override */
	bits_remaining |= explicitly_denied_bits;

	/* The owner always gets owner rights as defined above. */
	if (security_token_has_sid(token, sd->owner_sid)) {
		if (owner_rights_default) {
			/*
			 * Just remove them, no need to check if they are
			 * there.
			 */
			bits_remaining &= ~(SEC_STD_WRITE_DAC |
						SEC_STD_READ_CONTROL);
		} else {
			bits_remaining &= ~owner_rights_allowed;
			bits_remaining |= owner_rights_denied;
		}
	}

	/*
	 * We check privileges here because they override even DENY entries.
	 */

	/* Does the user have the privilege to gain SEC_PRIV_SECURITY? */
	if (bits_remaining & SEC_FLAG_SYSTEM_SECURITY) {
		if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
			bits_remaining &= ~SEC_FLAG_SYSTEM_SECURITY;
		} else {
			return NT_STATUS_PRIVILEGE_NOT_HELD;
		}
	}

	if ((bits_remaining & SEC_STD_WRITE_OWNER) &&
	     security_token_has_privilege(token, SEC_PRIV_TAKE_OWNERSHIP)) {
		bits_remaining &= ~(SEC_STD_WRITE_OWNER);
	}

done:
	if (bits_remaining != 0) {
		*access_granted = bits_remaining;
		return NT_STATUS_ACCESS_DENIED;
	}

	return NT_STATUS_OK;
}
Пример #23
0
_PUBLIC_ NTSTATUS auth_generate_session_info(TALLOC_CTX *mem_ctx,
        struct loadparm_context *lp_ctx, /* Optional, if you don't want privilages */
        struct ldb_context *sam_ctx, /* Optional, if you don't want local groups */
        struct auth_user_info_dc *user_info_dc,
        uint32_t session_info_flags,
        struct auth_session_info **_session_info)
{
    struct auth_session_info *session_info;
    NTSTATUS nt_status;
    unsigned int i, num_sids = 0;

    const char *filter;

    struct dom_sid *sids = NULL;
    const struct dom_sid *anonymous_sid, *system_sid;

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

    session_info = talloc_zero(tmp_ctx, struct auth_session_info);
    NT_STATUS_HAVE_NO_MEMORY_AND_FREE(session_info, tmp_ctx);

    session_info->info = talloc_reference(session_info, user_info_dc->info);

    session_info->torture = talloc_zero(session_info, struct auth_user_info_torture);
    NT_STATUS_HAVE_NO_MEMORY_AND_FREE(session_info->torture, tmp_ctx);
    session_info->torture->num_dc_sids = user_info_dc->num_sids;
    session_info->torture->dc_sids = talloc_reference(session_info, user_info_dc->sids);
    NT_STATUS_HAVE_NO_MEMORY_AND_FREE(session_info->torture->dc_sids, tmp_ctx);

    /* unless set otherwise, the session key is the user session
     * key from the auth subsystem */
    session_info->session_key = data_blob_talloc(session_info, user_info_dc->user_session_key.data, user_info_dc->user_session_key.length);
    if (!session_info->session_key.data && session_info->session_key.length) {
        NT_STATUS_HAVE_NO_MEMORY_AND_FREE(session_info->session_key.data, tmp_ctx);
    }

    anonymous_sid = dom_sid_parse_talloc(tmp_ctx, SID_NT_ANONYMOUS);
    NT_STATUS_HAVE_NO_MEMORY_AND_FREE(anonymous_sid, tmp_ctx);

    system_sid = dom_sid_parse_talloc(tmp_ctx, SID_NT_SYSTEM);
    NT_STATUS_HAVE_NO_MEMORY_AND_FREE(system_sid, tmp_ctx);

    sids = talloc_array(tmp_ctx, struct dom_sid, user_info_dc->num_sids);
    NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sids, tmp_ctx);
    if (!sids) {
        talloc_free(tmp_ctx);
        return NT_STATUS_NO_MEMORY;
    }

    num_sids = user_info_dc->num_sids;

    for (i=0; i < user_info_dc->num_sids; i++) {
        sids[i] = user_info_dc->sids[i];
    }

    if (user_info_dc->num_sids > PRIMARY_USER_SID_INDEX && dom_sid_equal(anonymous_sid, &user_info_dc->sids[PRIMARY_USER_SID_INDEX])) {
        /* Don't expand nested groups of system, anonymous etc*/
    } else if (user_info_dc->num_sids > PRIMARY_USER_SID_INDEX && dom_sid_equal(system_sid, &user_info_dc->sids[PRIMARY_USER_SID_INDEX])) {
        /* Don't expand nested groups of system, anonymous etc*/
    } else if (sam_ctx) {
        filter = talloc_asprintf(tmp_ctx, "(&(objectClass=group)(groupType:1.2.840.113556.1.4.803:=%u))",
                                 GROUP_TYPE_BUILTIN_LOCAL_GROUP);

        /* Search for each group in the token */
        for (i = 0; i < user_info_dc->num_sids; i++) {
            char *sid_string;
            const char *sid_dn;
            DATA_BLOB sid_blob;

            sid_string = dom_sid_string(tmp_ctx,
                                        &user_info_dc->sids[i]);
            NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sid_string, user_info_dc);

            sid_dn = talloc_asprintf(tmp_ctx, "<SID=%s>", sid_string);
            talloc_free(sid_string);
            NT_STATUS_HAVE_NO_MEMORY_AND_FREE(sid_dn, user_info_dc);
            sid_blob = data_blob_string_const(sid_dn);

            /* This function takes in memberOf values and expands
             * them, as long as they meet the filter - so only
             * builtin groups
             *
             * We already have the SID in the token, so set
             * 'only childs' flag to true */
            nt_status = dsdb_expand_nested_groups(sam_ctx, &sid_blob, true, filter,
                                                  tmp_ctx, &sids, &num_sids);
            if (!NT_STATUS_IS_OK(nt_status)) {
                talloc_free(tmp_ctx);
                return nt_status;
            }
        }
    }

    nt_status = security_token_create(session_info,
                                      lp_ctx,
                                      num_sids,
                                      sids,
                                      session_info_flags,
                                      &session_info->security_token);
    NT_STATUS_NOT_OK_RETURN_AND_FREE(nt_status, tmp_ctx);

    session_info->credentials = NULL;

    talloc_steal(mem_ctx, session_info);
    *_session_info = session_info;
    talloc_free(tmp_ctx);
    return NT_STATUS_OK;
}
/*
  lookup a name for 1 SID
*/
static NTSTATUS dcesrv_lsa_lookup_sid(struct lsa_policy_state *state, TALLOC_CTX *mem_ctx,
				      struct dom_sid *sid, const char *sid_str,
				      const char **authority_name, 
				      const char **name, enum lsa_SidType *rtype)
{
	NTSTATUS status;
	int ret;
	uint32_t atype;
	struct ldb_message **res;
	struct ldb_dn *domain_dn;
	const char * const attrs[] = { "sAMAccountName", "sAMAccountType", "cn", NULL};

	status = lookup_well_known_sids(mem_ctx, sid_str, authority_name, name, rtype);
	if (NT_STATUS_IS_OK(status)) {
		return status;
	}

	if (dom_sid_equal(state->domain_sid, sid)) {
		*authority_name = talloc_strdup(mem_ctx, state->domain_name);
		if (*authority_name == NULL) {
			return NT_STATUS_NO_MEMORY;
		}
		*name = NULL;
		*rtype = SID_NAME_DOMAIN;
		return NT_STATUS_OK;
	}

	if (dom_sid_in_domain(state->domain_sid, sid)) {
		*authority_name = talloc_strdup(mem_ctx, state->domain_name);
		if (*authority_name == NULL) {
			return NT_STATUS_NO_MEMORY;
		}
		domain_dn = state->domain_dn;
	} else if (dom_sid_in_domain(state->builtin_sid, sid)) {
		*authority_name = NAME_BUILTIN;
		domain_dn = state->builtin_dn;
	} else {
		/* Not well known, our domain or built in */

		/* In future, we must look at SID histories, and at trusted domains via winbind */

		return NT_STATUS_NOT_FOUND;
	}

	/* need to re-add a check for an allocated sid */

	ret = gendb_search(state->sam_ldb, mem_ctx, domain_dn, &res, attrs, 
			   "objectSid=%s", ldap_encode_ndr_dom_sid(mem_ctx, sid));
	if ((ret < 0) || (ret > 1)) {
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}
	if (ret == 0) {
		return NT_STATUS_NOT_FOUND;
	}

	*name = ldb_msg_find_attr_as_string(res[0], "sAMAccountName", NULL);
	if (!*name) {
		*name = ldb_msg_find_attr_as_string(res[0], "cn", NULL);
		if (!*name) {
			*name = talloc_strdup(mem_ctx, sid_str);
			NT_STATUS_HAVE_NO_MEMORY(*name);
		}
	}

	atype = ldb_msg_find_attr_as_uint(res[0], "sAMAccountType", 0);
	*rtype = ds_atype_map(atype);

	return NT_STATUS_OK;
}
NTSTATUS sec_access_check_ds(const struct security_descriptor *sd,
			     const struct security_token *token,
			     uint32_t access_desired,
			     uint32_t *access_granted,
			     struct object_tree *tree,
			     struct dom_sid *replace_sid)
{
	uint32_t i;
	uint32_t bits_remaining;
	struct object_tree *node;
	const struct GUID *type;
	struct dom_sid self_sid;

	dom_sid_parse(SID_NT_SELF, &self_sid);

	*access_granted = access_desired;
	bits_remaining = access_desired;

	/* handle the maximum allowed flag */
	if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) {
		access_desired |= access_check_max_allowed(sd, token);
		access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED;
		*access_granted = access_desired;
		bits_remaining = access_desired;
	}

	if (access_desired & SEC_FLAG_SYSTEM_SECURITY) {
		if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
			bits_remaining &= ~SEC_FLAG_SYSTEM_SECURITY;
		} else {
			return NT_STATUS_PRIVILEGE_NOT_HELD;
		}
	}

	/* the owner always gets SEC_STD_WRITE_DAC and SEC_STD_READ_CONTROL */
	if ((bits_remaining & (SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL)) &&
	    security_token_has_sid(token, sd->owner_sid)) {
		bits_remaining &= ~(SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL);
	}

	/* TODO: remove this, as it is file server specific */
	if ((bits_remaining & SEC_RIGHTS_PRIV_RESTORE) &&
	    security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
		bits_remaining &= ~(SEC_RIGHTS_PRIV_RESTORE);
	}
	if ((bits_remaining & SEC_RIGHTS_PRIV_BACKUP) &&
	    security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
		bits_remaining &= ~(SEC_RIGHTS_PRIV_BACKUP);
	}

	/* a NULL dacl allows access */
	if ((sd->type & SEC_DESC_DACL_PRESENT) && sd->dacl == NULL) {
		*access_granted = access_desired;
		return NT_STATUS_OK;
	}

	if (sd->dacl == NULL) {
		goto done;
	}

	/* check each ace in turn. */
	for (i=0; bits_remaining && i < sd->dacl->num_aces; i++) {
		struct dom_sid *trustee;
		struct security_ace *ace = &sd->dacl->aces[i];

		if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
			continue;
		}

		if (dom_sid_equal(&ace->trustee, &self_sid) && replace_sid) {
			trustee = replace_sid;
		} else {
			trustee = &ace->trustee;
		}

		if (!security_token_has_sid(token, trustee)) {
			continue;
		}

		switch (ace->type) {
		case SEC_ACE_TYPE_ACCESS_ALLOWED:
			if (tree) {
				object_tree_modify_access(tree, ace->access_mask);
			}

			bits_remaining &= ~ace->access_mask;
			break;
		case SEC_ACE_TYPE_ACCESS_DENIED:
			if (bits_remaining & ace->access_mask) {
				return NT_STATUS_ACCESS_DENIED;
			}
			break;
		case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
		case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT:
			/*
			 * check only in case we have provided a tree,
			 * the ACE has an object type and that type
			 * is in the tree
			 */
			type = get_ace_object_type(ace);

			if (!tree) {
				continue;
			}

			if (!type) {
				node = tree;
			} else {
				if (!(node = get_object_tree_by_GUID(tree, type))) {
					continue;
				}
			}

			if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT) {
				object_tree_modify_access(node, ace->access_mask);
				if (node->remaining_access == 0) {
					return NT_STATUS_OK;
				}
			} else {
				if (node->remaining_access & ace->access_mask){
					return NT_STATUS_ACCESS_DENIED;
				}
			}
			break;
		default:	/* Other ACE types not handled/supported */
			break;
		}
	}

done:
	if (bits_remaining != 0) {
		return NT_STATUS_ACCESS_DENIED;
	}

	return NT_STATUS_OK;
}
Пример #26
0
static WERROR NetLocalGroupModifyMembers_r(struct libnetapi_ctx *ctx,
					   struct NetLocalGroupAddMembers *add,
					   struct NetLocalGroupDelMembers *del,
					   struct NetLocalGroupSetMembers *set)
{
	struct NetLocalGroupAddMembers *r = NULL;

	struct rpc_pipe_client *pipe_cli = NULL;
	struct rpc_pipe_client *lsa_pipe = NULL;
	NTSTATUS status, result;
	WERROR werr;
	struct lsa_String lsa_account_name;
	struct policy_handle connect_handle, domain_handle, builtin_handle, alias_handle;
	struct dom_sid2 *domain_sid = NULL;
	struct dom_sid *member_sids = NULL;
	int i = 0, k = 0;

	struct LOCALGROUP_MEMBERS_INFO_0 *info0 = NULL;
	struct LOCALGROUP_MEMBERS_INFO_3 *info3 = NULL;

	struct dom_sid *add_sids = NULL;
	struct dom_sid *del_sids = NULL;
	uint32_t num_add_sids = 0;
	uint32_t num_del_sids = 0;
	struct dcerpc_binding_handle *b = NULL;

	if ((!add && !del && !set) || (add && del && set)) {
		return WERR_INVALID_PARAM;
	}

	if (add) {
		r = add;
	}

	if (del) {
		r = (struct NetLocalGroupAddMembers *)del;
	}

	if (set) {
		r = (struct NetLocalGroupAddMembers *)set;
	}

	if (!r->in.group_name) {
		return WERR_INVALID_PARAM;
	}

	switch (r->in.level) {
		case 0:
		case 3:
			break;
		default:
			return WERR_UNKNOWN_LEVEL;
	}

	if (r->in.total_entries == 0 || !r->in.buffer) {
		return WERR_INVALID_PARAM;
	}

	ZERO_STRUCT(connect_handle);
	ZERO_STRUCT(builtin_handle);
	ZERO_STRUCT(domain_handle);
	ZERO_STRUCT(alias_handle);

	member_sids = talloc_zero_array(ctx, struct dom_sid,
					r->in.total_entries);
	W_ERROR_HAVE_NO_MEMORY(member_sids);

	switch (r->in.level) {
		case 0:
			info0 = (struct LOCALGROUP_MEMBERS_INFO_0 *)r->in.buffer;
			for (i=0; i < r->in.total_entries; i++) {
				sid_copy(&member_sids[i], (struct dom_sid *)info0[i].lgrmi0_sid);
			}
			break;
		case 3:
			info3 = (struct LOCALGROUP_MEMBERS_INFO_3 *)r->in.buffer;
			break;
		default:
			break;
	}

	if (r->in.level == 3) {
		werr = libnetapi_open_pipe(ctx, r->in.server_name,
					   &ndr_table_lsarpc,
					   &lsa_pipe);
		if (!W_ERROR_IS_OK(werr)) {
			goto done;
		}

		for (i=0; i < r->in.total_entries; i++) {
			status = libnetapi_lsa_lookup_names3(ctx, lsa_pipe,
							     info3[i].lgrmi3_domainandname,
							     &member_sids[i]);
			if (!NT_STATUS_IS_OK(status)) {
				werr = ntstatus_to_werror(status);
				goto done;
			}
		}
		TALLOC_FREE(lsa_pipe);
	}

	werr = libnetapi_open_pipe(ctx, r->in.server_name,
				   &ndr_table_samr,
				   &pipe_cli);
	if (!W_ERROR_IS_OK(werr)) {
		goto done;
	}

	b = pipe_cli->binding_handle;

	werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
						  SAMR_ACCESS_LOOKUP_DOMAIN |
						  SAMR_ACCESS_ENUM_DOMAINS,
						  SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
						  &connect_handle,
						  &builtin_handle);
	if (!W_ERROR_IS_OK(werr)) {
		goto done;
	}

	init_lsa_String(&lsa_account_name, r->in.group_name);

	status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
						      &builtin_handle,
						      r->in.group_name,
						      SAMR_ALIAS_ACCESS_ADD_MEMBER |
						      SAMR_ALIAS_ACCESS_REMOVE_MEMBER |
						      SAMR_ALIAS_ACCESS_GET_MEMBERS |
						      SAMR_ALIAS_ACCESS_LOOKUP_INFO,
						      &alias_handle);

	if (ctx->disable_policy_handle_cache) {
		libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
	}

	if (NT_STATUS_IS_OK(status)) {
		goto modify_membership;
	}

	werr = libnetapi_samr_open_domain(ctx, pipe_cli,
					  SAMR_ACCESS_ENUM_DOMAINS |
					  SAMR_ACCESS_LOOKUP_DOMAIN,
					  SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
					  &connect_handle,
					  &domain_handle,
					  &domain_sid);
	if (!W_ERROR_IS_OK(werr)) {
		goto done;
	}

	status = libnetapi_samr_lookup_and_open_alias(ctx, pipe_cli,
						      &domain_handle,
						      r->in.group_name,
						      SAMR_ALIAS_ACCESS_ADD_MEMBER |
						      SAMR_ALIAS_ACCESS_REMOVE_MEMBER |
						      SAMR_ALIAS_ACCESS_GET_MEMBERS |
						      SAMR_ALIAS_ACCESS_LOOKUP_INFO,
						      &alias_handle);
	if (!NT_STATUS_IS_OK(status)) {
		werr = ntstatus_to_werror(status);
		goto done;
	}

	if (ctx->disable_policy_handle_cache) {
		libnetapi_samr_close_domain_handle(ctx, &domain_handle);
	}

 modify_membership:

	if (add) {
		for (i=0; i < r->in.total_entries; i++) {
			status = add_sid_to_array_unique(ctx, &member_sids[i],
							 &add_sids,
							 &num_add_sids);
			if (!NT_STATUS_IS_OK(status)) {
				werr = ntstatus_to_werror(status);
				goto done;
			}
		}
	}

	if (del) {
		for (i=0; i < r->in.total_entries; i++) {
			status = add_sid_to_array_unique(ctx, &member_sids[i],
							 &del_sids,
							 &num_del_sids);
			if (!NT_STATUS_IS_OK(status)) {
				werr = ntstatus_to_werror(status);
				goto done;
			}
		}
	}

	if (set) {

		struct lsa_SidArray current_sids;

		status = dcerpc_samr_GetMembersInAlias(b, talloc_tos(),
						       &alias_handle,
						       &current_sids,
						       &result);
		if (!NT_STATUS_IS_OK(status)) {
			werr = ntstatus_to_werror(status);
			goto done;
		}
		if (!NT_STATUS_IS_OK(result)) {
			werr = ntstatus_to_werror(result);
			goto done;
		}

		/* add list */

		for (i=0; i < r->in.total_entries; i++) {
			bool already_member = false;
			for (k=0; k < current_sids.num_sids; k++) {
				if (dom_sid_equal(&member_sids[i],
					      current_sids.sids[k].sid)) {
					already_member = true;
					break;
				}
			}
			if (!already_member) {
				status = add_sid_to_array_unique(ctx,
					&member_sids[i],
					&add_sids, &num_add_sids);
				if (!NT_STATUS_IS_OK(status)) {
					werr = ntstatus_to_werror(status);
					goto done;
				}
			}
		}

		/* del list */

		for (k=0; k < current_sids.num_sids; k++) {
			bool keep_member = false;
			for (i=0; i < r->in.total_entries; i++) {
				if (dom_sid_equal(&member_sids[i],
					      current_sids.sids[k].sid)) {
					keep_member = true;
					break;
				}
			}
			if (!keep_member) {
				status = add_sid_to_array_unique(ctx,
						current_sids.sids[k].sid,
						&del_sids, &num_del_sids);
				if (!NT_STATUS_IS_OK(status)) {
					werr = ntstatus_to_werror(status);
					goto done;
				}
			}
		}
	}

	/* add list */

	for (i=0; i < num_add_sids; i++) {
		status = dcerpc_samr_AddAliasMember(b, talloc_tos(),
						    &alias_handle,
						    &add_sids[i],
						    &result);
		if (!NT_STATUS_IS_OK(status)) {
			werr = ntstatus_to_werror(status);
			goto done;
		}
		if (!NT_STATUS_IS_OK(result)) {
			werr = ntstatus_to_werror(result);
			goto done;
		}
	}

	/* del list */

	for (i=0; i < num_del_sids; i++) {
		status = dcerpc_samr_DeleteAliasMember(b, talloc_tos(),
						       &alias_handle,
						       &del_sids[i],
						       &result);
		if (!NT_STATUS_IS_OK(status)) {
			werr = ntstatus_to_werror(status);
			goto done;
		}
		if (!NT_STATUS_IS_OK(result)) {
			werr = ntstatus_to_werror(result);
			goto done;
		}
	}

	werr = WERR_OK;

 done:
	if (b && is_valid_policy_hnd(&alias_handle)) {
		dcerpc_samr_Close(b, talloc_tos(), &alias_handle, &result);
	}

	if (ctx->disable_policy_handle_cache) {
		libnetapi_samr_close_domain_handle(ctx, &domain_handle);
		libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
		libnetapi_samr_close_connect_handle(ctx, &connect_handle);
	}

	return werr;
}
Пример #27
0
static struct dom_sid *pdb_generate_sam_sid(void)
{
    struct dom_sid domain_sid;
    char *fname = NULL;
    struct dom_sid *sam_sid;

    if(!(sam_sid=SMB_MALLOC_P(struct dom_sid)))
        return NULL;

    if ( IS_DC ) {
        if (secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
            sid_copy(sam_sid, &domain_sid);
            return sam_sid;
        }
    }

    if (secrets_fetch_domain_sid(lp_netbios_name(), sam_sid)) {

        /* We got our sid. If not a pdc/bdc, we're done. */
        if ( !IS_DC )
            return sam_sid;

        if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {

            /* No domain sid and we're a pdc/bdc. Store it */

            if (!secrets_store_domain_sid(lp_workgroup(), sam_sid)) {
                DEBUG(0,("pdb_generate_sam_sid: Can't store domain SID as a pdc/bdc.\n"));
                SAFE_FREE(sam_sid);
                return NULL;
            }
            return sam_sid;
        }

        if (!dom_sid_equal(&domain_sid, sam_sid)) {

            /* Domain name sid doesn't match global sam sid. Re-store domain sid as 'local' sid. */

            DEBUG(0,("pdb_generate_sam_sid: Mismatched SIDs as a pdc/bdc.\n"));
            if (!secrets_store_domain_sid(lp_netbios_name(), &domain_sid)) {
                DEBUG(0,("pdb_generate_sam_sid: Can't re-store domain SID for local sid as PDC/BDC.\n"));
                SAFE_FREE(sam_sid);
                return NULL;
            }
            return sam_sid;
        }

        return sam_sid;
    }

    /* check for an old MACHINE.SID file for backwards compatibility */
    if (asprintf(&fname, "%s/MACHINE.SID", lp_private_dir()) == -1) {
        SAFE_FREE(sam_sid);
        return NULL;
    }

    if (read_sid_from_file(fname, sam_sid)) {
        /* remember it for future reference and unlink the old MACHINE.SID */
        if (!secrets_store_domain_sid(lp_netbios_name(), sam_sid)) {
            DEBUG(0,("pdb_generate_sam_sid: Failed to store SID from file.\n"));
            SAFE_FREE(fname);
            SAFE_FREE(sam_sid);
            return NULL;
        }
        unlink(fname);
        if ( !IS_DC ) {
            if (!secrets_store_domain_sid(lp_workgroup(), sam_sid)) {
                DEBUG(0,("pdb_generate_sam_sid: Failed to store domain SID from file.\n"));
                SAFE_FREE(fname);
                SAFE_FREE(sam_sid);
                return NULL;
            }
        }

        /* Stored the old sid from MACHINE.SID successfully.*/
        SAFE_FREE(fname);
        return sam_sid;
    }

    SAFE_FREE(fname);

    /* we don't have the SID in secrets.tdb, we will need to
           generate one and save it */
    generate_random_sid(sam_sid);

    if (!secrets_store_domain_sid(lp_netbios_name(), sam_sid)) {
        DEBUG(0,("pdb_generate_sam_sid: Failed to store generated machine SID.\n"));
        SAFE_FREE(sam_sid);
        return NULL;
    }
    if ( IS_DC ) {
        if (!secrets_store_domain_sid(lp_workgroup(), sam_sid)) {
            DEBUG(0,("pdb_generate_sam_sid: Failed to store generated domain SID.\n"));
            SAFE_FREE(sam_sid);
            return NULL;
        }
    }

    return sam_sid;
}
Пример #28
0
bool sid_check_is_domain(const struct dom_sid *sid)
{
    return dom_sid_equal(sid, get_global_sam_sid());
}
Пример #29
0
static bool torture_pac_self_check(struct torture_context *tctx)
{
	NTSTATUS nt_status;
	DATA_BLOB tmp_blob;
	struct PAC_DATA *pac_data;
	struct PAC_LOGON_INFO *logon_info;
	union netr_Validation validation;

	/* Generate a nice, arbitary keyblock */
	uint8_t server_bytes[16];
	uint8_t krbtgt_bytes[16];
	krb5_keyblock server_keyblock;
	krb5_keyblock krbtgt_keyblock;
	
	krb5_error_code ret;

	struct smb_krb5_context *smb_krb5_context;

	struct auth_serversupplied_info *server_info;
	struct auth_serversupplied_info *server_info_out;

	krb5_principal client_principal;
	time_t logon_time = time(NULL);

	TALLOC_CTX *mem_ctx = tctx;

	torture_assert(tctx, 0 == smb_krb5_init_context(mem_ctx, 
							NULL,
							tctx->lp_ctx,
							&smb_krb5_context), 
		       "smb_krb5_init_context");

	generate_random_buffer(server_bytes, 16);
	generate_random_buffer(krbtgt_bytes, 16);

	ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
				 ENCTYPE_ARCFOUR_HMAC,
				 server_bytes, sizeof(server_bytes),
				 &server_keyblock);
	torture_assert(tctx, !ret, talloc_asprintf(tctx, 
						   "(self test) Server Keyblock encoding failed: %s", 
						   smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
									      ret, mem_ctx)));

	ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
				 ENCTYPE_ARCFOUR_HMAC,
				 krbtgt_bytes, sizeof(krbtgt_bytes),
				 &krbtgt_keyblock);
	if (ret) {
		char *err = smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
						       ret, mem_ctx);
	
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);

		torture_fail(tctx, talloc_asprintf(tctx, 
						   "(self test) KRBTGT Keyblock encoding failed: %s", err));
	}

	/* We need an input, and this one requires no underlying database */
	nt_status = auth_anonymous_server_info(mem_ctx, lp_netbios_name(tctx->lp_ctx), &server_info);

	if (!NT_STATUS_IS_OK(nt_status)) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &krbtgt_keyblock);
		torture_fail(tctx, "auth_anonymous_server_info");
	}

	ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, 
				    server_info->account_name, 
				    KRB5_PRINCIPAL_PARSE_NO_REALM, 
				    &client_principal);
	if (ret) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &krbtgt_keyblock);
		torture_fail(tctx, "krb5_parse_name_flags(norealm)");
	}

	/* OK, go ahead and make a PAC */
	ret = kerberos_create_pac(mem_ctx, 
				  lp_iconv_convenience(tctx->lp_ctx),
				  server_info, 
				  smb_krb5_context->krb5_context,  
				  &krbtgt_keyblock,
				  &server_keyblock,
				  client_principal,
				  logon_time,
				  &tmp_blob);
	
	if (ret) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &krbtgt_keyblock);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_principal(smb_krb5_context->krb5_context, 
				    client_principal);

		torture_fail(tctx, talloc_asprintf(tctx,
						   "(self test) PAC encoding failed: %s", 
						   smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
									      ret, mem_ctx)));
	}

	dump_data(10,tmp_blob.data,tmp_blob.length);

	/* Now check that we can read it back (using full decode and validate) */
	nt_status = kerberos_decode_pac(mem_ctx, 
					lp_iconv_convenience(tctx->lp_ctx),
					&pac_data,
					tmp_blob,
					smb_krb5_context->krb5_context,
					&krbtgt_keyblock,
					&server_keyblock,
					client_principal, 
					logon_time, NULL);

	if (!NT_STATUS_IS_OK(nt_status)) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &krbtgt_keyblock);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_principal(smb_krb5_context->krb5_context, 
				    client_principal);

		torture_fail(tctx, talloc_asprintf(tctx,
						   "(self test) PAC decoding failed: %s", 
						   nt_errstr(nt_status)));
	}

	/* Now check we can read it back (using Heimdal's pac parsing) */
	nt_status = kerberos_pac_blob_to_server_info(mem_ctx, 
						     lp_iconv_convenience(tctx->lp_ctx),
						     tmp_blob, 
						     smb_krb5_context->krb5_context,
						     &server_info_out);

	if (!dom_sid_equal(server_info->account_sid, 
			   server_info_out->account_sid)) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &krbtgt_keyblock);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_principal(smb_krb5_context->krb5_context, 
				    client_principal);

		torture_fail(tctx,  
			     talloc_asprintf(tctx, 
					     "(self test) PAC Decode resulted in *different* domain SID: %s != %s",
					     dom_sid_string(mem_ctx, server_info->account_sid), 
					     dom_sid_string(mem_ctx, server_info_out->account_sid)));
	}
	talloc_free(server_info_out);

	/* Now check that we can read it back (yet again) */
	nt_status = kerberos_pac_logon_info(mem_ctx, 
					    lp_iconv_convenience(tctx->lp_ctx),
					    &logon_info,
					    tmp_blob,
					    smb_krb5_context->krb5_context,
					    &krbtgt_keyblock,
					    &server_keyblock,
					    client_principal, 
					    logon_time, 
					    NULL);
	
	if (!NT_STATUS_IS_OK(nt_status)) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &krbtgt_keyblock);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_principal(smb_krb5_context->krb5_context, 
				    client_principal);
		
		torture_fail(tctx,  
			     talloc_asprintf(tctx, 
					     "(self test) PAC decoding (for logon info) failed: %s", 
					     nt_errstr(nt_status)));
	}
	
	krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
				    &krbtgt_keyblock);
	krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
				    &server_keyblock);
	krb5_free_principal(smb_krb5_context->krb5_context, 
			    client_principal);

	/* And make a server info from the samba-parsed PAC */
	validation.sam3 = &logon_info->info3;
	nt_status = make_server_info_netlogon_validation(mem_ctx,
							 "",
							 3, &validation,
							 &server_info_out); 
	if (!NT_STATUS_IS_OK(nt_status)) {
		torture_fail(tctx, 
			     talloc_asprintf(tctx, 
					     "(self test) PAC decoding (make server info) failed: %s", 
					     nt_errstr(nt_status)));
	}
	
	if (!dom_sid_equal(server_info->account_sid, 
			   server_info_out->account_sid)) {
		torture_fail(tctx,  
			     talloc_asprintf(tctx, 
					     "(self test) PAC Decode resulted in *different* domain SID: %s != %s",
					     dom_sid_string(mem_ctx, server_info->account_sid), 
					     dom_sid_string(mem_ctx, server_info_out->account_sid)));
	}
	return true;
}
Пример #30
0
/* Check with a known 'well formed' PAC, from my test server */
static bool torture_pac_saved_check(struct torture_context *tctx)
{
	NTSTATUS nt_status;
	enum ndr_err_code ndr_err;
	DATA_BLOB tmp_blob, validate_blob;
	struct PAC_DATA *pac_data, pac_data2;
	struct PAC_LOGON_INFO *logon_info;
	union netr_Validation validation;
	const char *pac_file, *pac_kdc_key, *pac_member_key;
	struct auth_serversupplied_info *server_info_out;

	krb5_keyblock server_keyblock;
	krb5_keyblock krbtgt_keyblock, *krbtgt_keyblock_p;
	struct samr_Password *krbtgt_bytes, *krbsrv_bytes;
	
	krb5_error_code ret;
	struct smb_krb5_context *smb_krb5_context;

	const char *principal_string;
	char *broken_principal_string;
	krb5_principal client_principal;
	const char *authtime_string;
	time_t authtime;
	TALLOC_CTX *mem_ctx = tctx;

	torture_assert(tctx, 0 == smb_krb5_init_context(mem_ctx, NULL,
							tctx->lp_ctx,
							&smb_krb5_context),
		       "smb_krb5_init_context");

	pac_kdc_key = torture_setting_string(tctx, "pac_kdc_key", 
					     "B286757148AF7FD252C53603A150B7E7");

	pac_member_key = torture_setting_string(tctx, "pac_member_key", 
						"D217FAEAE5E6B5F95CCC94077AB8A5FC");

	torture_comment(tctx, "Using pac_kdc_key '%s'\n", pac_kdc_key);
	torture_comment(tctx, "Using pac_member_key '%s'\n", pac_member_key);

	/* The krbtgt key in use when the above PAC was generated.
	 * This is an arcfour-hmac-md5 key, extracted with our 'net
	 * samdump' tool. */
	if (*pac_kdc_key == 0) {
		krbtgt_bytes = NULL;
	} else {
		krbtgt_bytes = smbpasswd_gethexpwd(mem_ctx, pac_kdc_key);
		if (!krbtgt_bytes) {
			torture_fail(tctx, "(saved test) Could not interpret krbtgt key");
		}
	}

	krbsrv_bytes = smbpasswd_gethexpwd(mem_ctx, pac_member_key);
	if (!krbsrv_bytes) {
		torture_fail(tctx, "(saved test) Could not interpret krbsrv key");
	}

	ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
				 ENCTYPE_ARCFOUR_HMAC,
				 krbsrv_bytes->hash, sizeof(krbsrv_bytes->hash),
				 &server_keyblock);
	torture_assert(tctx, !ret,
		       talloc_asprintf(tctx,
				       "(saved test) Server Keyblock encoding failed: %s", 
				       smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
								  ret, mem_ctx)));

	if (krbtgt_bytes) {
		ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
					 ENCTYPE_ARCFOUR_HMAC,
					 krbtgt_bytes->hash, sizeof(krbtgt_bytes->hash),
					 &krbtgt_keyblock);
		if (ret) {
			krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
						    &server_keyblock);
			torture_fail(tctx, 
				     talloc_asprintf(tctx, 
						     "(saved test) Server Keyblock encoding failed: %s", 
						     smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
										ret, mem_ctx)));
		}
		krbtgt_keyblock_p = &krbtgt_keyblock;
	} else {
		krbtgt_keyblock_p = NULL;
	}

	pac_file = torture_setting_string(tctx, "pac_file", NULL);
	if (pac_file) {
		tmp_blob.data = (uint8_t *)file_load(pac_file, &tmp_blob.length, 0, mem_ctx);
		torture_comment(tctx, "(saved test) Loaded pac of size %ld from %s\n", (long)tmp_blob.length, pac_file);
	} else {
		tmp_blob = data_blob_talloc(mem_ctx, saved_pac, sizeof(saved_pac));
	}
	
	dump_data(10,tmp_blob.data,tmp_blob.length);

	principal_string = torture_setting_string(tctx, "pac_client_principal", 
						  "[email protected]");

	authtime_string = torture_setting_string(tctx, "pac_authtime", "1120440609");
	authtime = strtoull(authtime_string, NULL, 0);

	ret = krb5_parse_name(smb_krb5_context->krb5_context, principal_string, 
			      &client_principal);
	if (ret) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    krbtgt_keyblock_p);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		torture_fail(tctx,  
			     talloc_asprintf(tctx, 
					     "(saved test) parsing of client principal [%s] failed: %s", 
					     principal_string, 
					     smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)));
	}

	/* Decode and verify the signaure on the PAC */
	nt_status = kerberos_decode_pac(mem_ctx, 
					lp_iconv_convenience(tctx->lp_ctx),
					&pac_data,
					tmp_blob,
					smb_krb5_context->krb5_context,
					krbtgt_keyblock_p,
					&server_keyblock, 
					client_principal, authtime, NULL);
	if (!NT_STATUS_IS_OK(nt_status)) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    krbtgt_keyblock_p);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
		
		torture_fail(tctx, talloc_asprintf(tctx, 
						   "(saved test) PAC decoding failed: %s", 
						   nt_errstr(nt_status)));
	}

	/* Now check we can read it back (using Heimdal's pac parsing) */
	nt_status = kerberos_pac_blob_to_server_info(mem_ctx, 
						     lp_iconv_convenience(tctx->lp_ctx),
						     tmp_blob, 
						     smb_krb5_context->krb5_context,
						     &server_info_out);

	if (!NT_STATUS_IS_OK(nt_status)) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    krbtgt_keyblock_p);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
		
		torture_fail(tctx, talloc_asprintf(tctx, 
						   "(saved test) Heimdal PAC decoding failed: %s", 
						   nt_errstr(nt_status)));
	}

	if (!pac_file &&
	    !dom_sid_equal(dom_sid_parse_talloc(mem_ctx, 
						"S-1-5-21-3048156945-3961193616-3706469200-1005"), 
			   server_info_out->account_sid)) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    krbtgt_keyblock_p);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);

		torture_fail(tctx,  
			     talloc_asprintf(tctx, 
					     "(saved test) Heimdal PAC Decode resulted in *different* domain SID: %s != %s",
					     "S-1-5-21-3048156945-3961193616-3706469200-1005", 
					     dom_sid_string(mem_ctx, server_info_out->account_sid)));
	}

	talloc_free(server_info_out);

	/* Parse the PAC again, for the logon info this time (using Samba4's parsing) */
	nt_status = kerberos_pac_logon_info(mem_ctx, 
					    lp_iconv_convenience(tctx->lp_ctx),
					    &logon_info,
					    tmp_blob,
					    smb_krb5_context->krb5_context,
					    krbtgt_keyblock_p,
					    &server_keyblock,
					    client_principal, authtime, NULL);

	if (!NT_STATUS_IS_OK(nt_status)) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    krbtgt_keyblock_p);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
	
		torture_fail(tctx,  
			     talloc_asprintf(tctx, 
					     "(saved test) PAC decoding (for logon info) failed: %s", 
					     nt_errstr(nt_status)));
	}

	validation.sam3 = &logon_info->info3;
	nt_status = make_server_info_netlogon_validation(mem_ctx,
							 "",
							 3, &validation,
							 &server_info_out); 
	if (!NT_STATUS_IS_OK(nt_status)) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    krbtgt_keyblock_p);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);

		torture_fail(tctx,  
			     talloc_asprintf(tctx, 
					     "(saved test) PAC decoding (make server info) failed: %s", 
					     nt_errstr(nt_status)));
	}

	if (!pac_file &&
	    !dom_sid_equal(dom_sid_parse_talloc(mem_ctx, 
						"S-1-5-21-3048156945-3961193616-3706469200-1005"), 
			   server_info_out->account_sid)) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    krbtgt_keyblock_p);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);

		torture_fail(tctx,  
			     talloc_asprintf(tctx, 
					     "(saved test) PAC Decode resulted in *different* domain SID: %s != %s",
					     "S-1-5-21-3048156945-3961193616-3706469200-1005", 
					     dom_sid_string(mem_ctx, server_info_out->account_sid)));
	}

	if (krbtgt_bytes == NULL) {
		torture_comment(tctx, "skipping PAC encoding tests as non kdc key\n");
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
		return true;
	}

	ret = kerberos_encode_pac(mem_ctx, 
				  lp_iconv_convenience(tctx->lp_ctx),
				  pac_data,
				  smb_krb5_context->krb5_context,
				  krbtgt_keyblock_p,
				  &server_keyblock,
				  &validate_blob);

	if (ret != 0) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    krbtgt_keyblock_p);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);

		torture_fail(tctx, "(saved test) PAC push failed");
	}

	dump_data(10, validate_blob.data, validate_blob.length);

	/* compare both the length and the data bytes after a
	 * pull/push cycle.  This ensures we use the exact same
	 * pointer, padding etc algorithms as win2k3.
	 */
	if (tmp_blob.length != validate_blob.length) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    krbtgt_keyblock_p);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);

		torture_fail(tctx, 
			     talloc_asprintf(tctx, 
					     "(saved test) PAC push failed: original buffer length[%u] != created buffer length[%u]",
					     (unsigned)tmp_blob.length, (unsigned)validate_blob.length));
	}

	if (memcmp(tmp_blob.data, validate_blob.data, tmp_blob.length) != 0) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    krbtgt_keyblock_p);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);

		DEBUG(0, ("tmp_data:\n"));
		dump_data(0, tmp_blob.data, tmp_blob.length);
		DEBUG(0, ("validate_blob:\n"));
		dump_data(0, validate_blob.data, validate_blob.length);

		torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC push failed: length[%u] matches, but data does not", (unsigned)tmp_blob.length));
	}

	ret = kerberos_create_pac(mem_ctx, 
				  lp_iconv_convenience(tctx->lp_ctx),
				  server_info_out,
				  smb_krb5_context->krb5_context,
				  krbtgt_keyblock_p,
				  &server_keyblock,
				  client_principal, authtime,
				  &validate_blob);

	if (ret != 0) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    krbtgt_keyblock_p);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);

		torture_fail(tctx, "(saved test) regnerated PAC create failed");
	}

	dump_data(10,validate_blob.data,validate_blob.length);

	/* compare both the length and the data bytes after a
	 * pull/push cycle.  This ensures we use the exact same
	 * pointer, padding etc algorithms as win2k3.
	 */
	if (tmp_blob.length != validate_blob.length) {
		ndr_err = ndr_pull_struct_blob(&validate_blob, mem_ctx, 
					       lp_iconv_convenience(tctx->lp_ctx), &pac_data2,
					       (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
		nt_status = ndr_map_error2ntstatus(ndr_err);
		torture_assert_ntstatus_ok(tctx, nt_status, "can't parse the PAC");
		
		NDR_PRINT_DEBUG(PAC_DATA, pac_data);

		NDR_PRINT_DEBUG(PAC_DATA, &pac_data2);

		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    krbtgt_keyblock_p);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);

		torture_fail(tctx, talloc_asprintf(tctx, 
						   "(saved test) PAC regenerate failed: original buffer length[%u] != created buffer length[%u]",
						   (unsigned)tmp_blob.length, (unsigned)validate_blob.length));
	}

	if (memcmp(tmp_blob.data, validate_blob.data, tmp_blob.length) != 0) {
		ndr_err = ndr_pull_struct_blob(&validate_blob, mem_ctx, 
					       lp_iconv_convenience(tctx->lp_ctx), &pac_data2,
					       (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
		nt_status = ndr_map_error2ntstatus(ndr_err);
		torture_assert_ntstatus_ok(tctx, nt_status, "can't parse the PAC");
		
		NDR_PRINT_DEBUG(PAC_DATA, pac_data);

		NDR_PRINT_DEBUG(PAC_DATA, &pac_data2);

		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    krbtgt_keyblock_p);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);

		DEBUG(0, ("tmp_data:\n"));
		dump_data(0, tmp_blob.data, tmp_blob.length);
		DEBUG(0, ("validate_blob:\n"));
		dump_data(0, validate_blob.data, validate_blob.length);

		torture_fail(tctx, talloc_asprintf(tctx, 
						   "(saved test) PAC regenerate failed: length[%u] matches, but data does not", (unsigned)tmp_blob.length));
	}

	/* Break the auth time, to ensure we check this vital detail (not setting this caused all the pain in the first place... */
	nt_status = kerberos_decode_pac(mem_ctx, 
					lp_iconv_convenience(tctx->lp_ctx),
					&pac_data,
					tmp_blob,
					smb_krb5_context->krb5_context,
					krbtgt_keyblock_p,
					&server_keyblock,
					client_principal, 
					authtime + 1, NULL);
	if (NT_STATUS_IS_OK(nt_status)) {

		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    krbtgt_keyblock_p);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		krb5_free_principal(smb_krb5_context->krb5_context, client_principal);
		torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on broken auth time (time + 1)");
	}

	/* Break the client principal */
	krb5_free_principal(smb_krb5_context->krb5_context, client_principal);

	broken_principal_string = talloc_strdup(mem_ctx, principal_string);
	broken_principal_string[0]++;

	ret = krb5_parse_name(smb_krb5_context->krb5_context,
			      broken_principal_string, &client_principal);
	if (ret) {

		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    krbtgt_keyblock_p);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		torture_fail(tctx, talloc_asprintf(tctx, 
						   "(saved test) parsing of broken client principal failed: %s", 
						   smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx)));
	}

	nt_status = kerberos_decode_pac(mem_ctx, 
					lp_iconv_convenience(tctx->lp_ctx),
					&pac_data,
					tmp_blob,
					smb_krb5_context->krb5_context,
					krbtgt_keyblock_p,
					&server_keyblock,
					client_principal, 
					authtime, NULL);
	if (NT_STATUS_IS_OK(nt_status)) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    krbtgt_keyblock_p);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on modified principal");
	}

	/* Finally...  Bugger up the signature, and check we fail the checksum */
	tmp_blob.data[tmp_blob.length - 2]++;

	nt_status = kerberos_decode_pac(mem_ctx, 
					lp_iconv_convenience(tctx->lp_ctx),
					&pac_data,
					tmp_blob,
					smb_krb5_context->krb5_context,
					krbtgt_keyblock_p,
					&server_keyblock,
					client_principal, 
					authtime, NULL);
	if (NT_STATUS_IS_OK(nt_status)) {
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    krbtgt_keyblock_p);
		krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
					    &server_keyblock);
		torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on broken checksum");
	}

	krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
				    krbtgt_keyblock_p);
	krb5_free_keyblock_contents(smb_krb5_context->krb5_context, 
				    &server_keyblock);
	return true;
}