Beispiel #1
0
/**
 * e2k_security_descriptor_remove_sid:
 * @sd: a security descriptor
 * @sid: a SID
 *
 * Removes @sid from @sd. If @sid is a user, this means s/he will now
 * have only the default permissions on @sd (unless s/he is a member
 * of a group that is also present in @sd.)
 **/
void
e2k_security_descriptor_remove_sid (E2kSecurityDescriptor *sd,
				    E2kSid *sid)
{
	E2k_ACE *aces;
	int ace;

	g_return_if_fail (E2K_IS_SECURITY_DESCRIPTOR (sd));
	g_return_if_fail (E2K_IS_SID (sid));

	/* Canonicalize the SID */
	sid = g_hash_table_lookup (sd->priv->sids,
				   e2k_sid_get_binary_sid (sid));
	if (!sid)
		return;

	/* We can't actually remove all trace of the user, because if
	 * he is removed and then re-added without saving in between,
	 * then we need to keep the original AceFlags. So we just
	 * clear out all of the masks, which (assuming the user is
	 * not re-added) will result in him not being written out
	 * when sd is saved.
	 */

	aces = (E2k_ACE *)sd->priv->aces->data;
	for (ace = 0; ace < sd->priv->aces->len; ace++) {
		if (aces[ace].Sid == sid)
			aces[ace].Mask = 0;
	}
}
Beispiel #2
0
/**
 * e2k_security_descriptor_new:
 * @xml_form: the XML form of the folder's security descriptor
 * (The "http://schemas.microsoft.com/exchange/security/descriptor"
 * property, aka %E2K_PR_EXCHANGE_SD_XML)
 * @binary_form: the binary form of the folder's security descriptor
 * (The "http://schemas.microsoft.com/exchange/ntsecuritydescriptor"
 * property, aka %E2K_PR_EXCHANGE_SD_BINARY)
 *
 * Constructs an #E2kSecurityDescriptor from the data in @xml_form and
 * @binary_form.
 *
 * Return value: the security descriptor, or %NULL if the data could
 * not be parsed.
 **/
E2kSecurityDescriptor *
e2k_security_descriptor_new (xmlNodePtr xml_form, GByteArray *binary_form)
{
	E2kSecurityDescriptor *sd;
	E2k_SECURITY_DESCRIPTOR_RELATIVE sdbuf;
	guint16 off, header_len;

	g_return_val_if_fail (xml_form != NULL, NULL);
	g_return_val_if_fail (binary_form != NULL, NULL);

	if (binary_form->len < 2)
		return NULL;

	memcpy (&header_len, binary_form->data, 2);
	header_len = GUINT16_FROM_LE (header_len);
	if (header_len + sizeof (sdbuf) > binary_form->len)
		return NULL;

	memcpy (&sdbuf, binary_form->data + header_len, sizeof (sdbuf));
	if (sdbuf.Revision != E2K_SECURITY_DESCRIPTOR_REVISION)
		return NULL;
	if ((sdbuf.Control & (E2K_SE_DACL_PRESENT | E2K_SE_SACL_PRESENT)) !=
	    E2K_SE_DACL_PRESENT)
		return NULL;

	sd = g_object_new (E2K_TYPE_SECURITY_DESCRIPTOR, NULL);
	sd->priv->header = g_byte_array_new ();
	g_byte_array_append (sd->priv->header, binary_form->data, header_len);
	sd->priv->control_flags = sdbuf.Control;

	/* Create a SID for "Default" then extract remaining SIDs from
	 * the XML form since they have display names associated with
	 * them.
	 */
	sd->priv->default_sid =
		e2k_sid_new_from_string_sid (E2K_SID_TYPE_WELL_KNOWN_GROUP,
					     E2K_SID_WKS_EVERYONE, NULL);
	g_hash_table_insert (sd->priv->sids,
			     (char *)e2k_sid_get_binary_sid (sd->priv->default_sid),
			     sd->priv->default_sid);
	extract_sids (sd, xml_form);

	off = GUINT32_FROM_LE (sdbuf.Owner) + sd->priv->header->len;
	if (!parse_sid (sd, binary_form, &off, &sd->priv->owner))
		goto lose;
	off = GUINT32_FROM_LE (sdbuf.Group) + sd->priv->header->len;
	if (!parse_sid (sd, binary_form, &off, &sd->priv->group))
		goto lose;

	off = GUINT32_FROM_LE (sdbuf.Dacl) + sd->priv->header->len;
	if (!parse_acl (sd, binary_form, &off))
		goto lose;

	return sd;

 lose:
	g_object_unref (sd);
	return NULL;
}
Beispiel #3
0
static void
extract_sids (E2kSecurityDescriptor *sd, xmlNodePtr node)
{
	xmlNodePtr string_sid_node, type_node, display_name_node;
	char *string_sid, *content, *display_name;
	const guint8 *bsid;
	E2kSid *sid;
	E2kSidType type;

	for (; node; node = node->next) {
		if (strcmp (node->name, "sid") != 0) {
			if (node->xmlChildrenNode)
				extract_sids (sd, node->xmlChildrenNode);
			continue;
		}

		string_sid_node = find_child (node, "string_sid");
		type_node = find_child (node, "type");
		display_name_node = find_child (node, "display_name");
		if (!string_sid_node || !type_node)
			continue;

		string_sid = xmlNodeGetContent (string_sid_node);

		content = xmlNodeGetContent (type_node);
		if (!content || !strcmp (content, "user"))
			type = E2K_SID_TYPE_USER;
		else if (!strcmp (content, "group"))
			type = E2K_SID_TYPE_GROUP;
		else if (!strcmp (content, "well_known_group"))
			type = E2K_SID_TYPE_WELL_KNOWN_GROUP;
		else if (!strcmp (content, "alias"))
			type = E2K_SID_TYPE_ALIAS;
		else
			type = E2K_SID_TYPE_INVALID;
		xmlFree (content);

		if (display_name_node)
			display_name = xmlNodeGetContent (display_name_node);
		else
			display_name = NULL;

		sid = e2k_sid_new_from_string_sid (type, string_sid,
						   display_name);
		xmlFree (string_sid);
		if (display_name)
			xmlFree (display_name);

		bsid = e2k_sid_get_binary_sid (sid);
		if (g_hash_table_lookup (sd->priv->sids, bsid)) {
			g_object_unref (sid);
			continue;
		}

		g_hash_table_insert (sd->priv->sids, (char *)bsid, sid);
	}
}
/* Add or remove a delegate. Everyone must be in one of three states:
 *   1. only in users (because they started and ended there)
 *   2. in users and added_users (because they weren't in
 *      users to begin with, but got added)
 *   3. only in removed_users (because they were in users to
 *      begin with and got removed).
 * If you're added and then removed, or removed and then added, you have
 * to end up in state 1. That's what this is for.
 */
static void
add_remove_user (ExchangeDelegatesUser *user,
                 GPtrArray *to_array,
                 GPtrArray *from_array)
{
	ExchangeDelegatesUser *match;
	gint i;

	for (i = 0; i < from_array->len; i++) {
		match = from_array->pdata[i];
		if (e2k_sid_binary_sid_equal (e2k_sid_get_binary_sid (match->sid),
					      e2k_sid_get_binary_sid (user->sid))) {
			g_ptr_array_remove_index_fast (from_array, i);
			g_object_unref (match);
			return;
		}
	}

	g_ptr_array_add (to_array, user);
	g_object_ref (user);
}
Beispiel #5
0
/**
 * e2k_security_descriptor_get_permissions:
 * @sd: a security descriptor
 * @sid: a SID
 *
 * Computes the MAPI permissions associated with @sid. (Only the
 * permissions *directly* associated with @sid, not any acquired via
 * group memberships or the Default SID.)
 *
 * Return value: the MAPI permissions
 **/
guint32
e2k_security_descriptor_get_permissions (E2kSecurityDescriptor *sd,
					 E2kSid *sid)
{
	E2k_ACE *aces;
	guint32 mapi_perms, checkperm;
	int ace, map;

	g_return_val_if_fail (E2K_IS_SECURITY_DESCRIPTOR (sd), 0);
	g_return_val_if_fail (E2K_IS_SID (sid), 0);

	/* Canonicalize the SID */
	sid = g_hash_table_lookup (sd->priv->sids,
				   e2k_sid_get_binary_sid (sid));
	if (!sid)
		return 0;

	mapi_perms = 0;
	aces = (E2k_ACE *)sd->priv->aces->data;
	for (ace = 0; ace < sd->priv->aces->len; ace++) {
		if (aces[ace].Sid != sid)
			continue;
		if (aces[ace].Header.AceType == E2K_ACCESS_DENIED_ACE_TYPE)
			continue;

		for (map = 0; map < permissions_map_size; map++) {
			if (aces[ace].Header.AceFlags & E2K_OBJECT_INHERIT_ACE)
				checkperm = permissions_map[map].object_allowed;
			else
				checkperm = permissions_map[map].container_allowed;
			if (!checkperm)
				continue;

			if ((aces[ace].Mask & checkperm) == checkperm)
				mapi_perms |= permissions_map[map].mapi_permission;
		}
	}

	return mapi_perms;
}
static void
add_button_clicked_cb (GtkWidget *widget,
                       gpointer data)
{
	ExchangeDelegates *delegates = data;
	E2kGlobalCatalog *gc;
	GtkWidget *dialog, *parent_window;
	const gchar *delegate_exchange_dn;
	gchar *email;
	ExchangeDelegatesUser *user, *match;
	gint response, u;
	GtkTreeIter iter;

	if (!get_folder_security (delegates))
		return;

	gc = exchange_account_get_global_catalog (delegates->account);

	parent_window = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
	dialog = e2k_user_dialog_new (parent_window,
				      _("Delegate To:"), _("Delegate To"));
	response = gtk_dialog_run (GTK_DIALOG (dialog));
	if (response != GTK_RESPONSE_OK) {
		gtk_widget_destroy (dialog);
		return;
	}
	email = e2k_user_dialog_get_user (E2K_USER_DIALOG (dialog));
	gtk_widget_destroy (dialog);

	if (email == NULL)
		return;

	user = exchange_delegates_user_new_from_gc (gc, email,
						    delegates->creator_entryid);
	if (!user) {
		e_alert_run_dialog_for_args (GTK_WINDOW (parent_window), ERROR_DOMAIN ":delegate-error", email, NULL);
		g_free (email);
		return;
	}
	g_free (email);

	delegate_exchange_dn = e2k_entryid_to_dn (user->entryid);
	if (delegate_exchange_dn && !g_ascii_strcasecmp (delegate_exchange_dn, delegates->account->legacy_exchange_dn)) {
		g_object_unref (user);
		e_alert_run_dialog_for_args (GTK_WINDOW (parent_window), ERROR_DOMAIN ":delegate-own-error", NULL);
		return;
	}

	for (u = 0; u < delegates->users->len; u++) {
		match = delegates->users->pdata[u];
		if (e2k_sid_binary_sid_equal (e2k_sid_get_binary_sid (user->sid),
					      e2k_sid_get_binary_sid (match->sid))) {
			e_alert_run_dialog_for_args (GTK_WINDOW (parent_window), ERROR_DOMAIN ":delegate-existing",
				     user->display_name, NULL);
			g_object_unref (user);
			exchange_delegates_user_edit (delegates->account, match, parent_window);
			return;
		}
	}

	if (!exchange_delegates_user_edit (delegates->account, user, parent_window)) {
		g_object_unref (user);
		return;
	}
	set_perms_for_user (user, delegates);
	g_signal_connect (user, "edited",
			  G_CALLBACK (set_perms_for_user), delegates);

	add_remove_user (user, delegates->added_users, delegates->removed_users);
	g_ptr_array_add (delegates->users, user);

	/* Add the user to the table */
	gtk_list_store_append (delegates->model, &iter);
	gtk_list_store_set (delegates->model, &iter,
			    0, user->display_name,
			    -1);
}
Beispiel #7
0
/**
 * e2k_security_descriptor_set_permissions:
 * @sd: a security descriptor
 * @sid: a SID
 * @perms: the MAPI permissions
 *
 * Updates or sets @sid's permissions on @sd.
 **/
void
e2k_security_descriptor_set_permissions (E2kSecurityDescriptor *sd,
					 E2kSid *sid, guint32 perms)
{
	E2k_ACE ace;
	guint32 object_allowed, object_denied;
	guint32 container_allowed, container_denied;
	const guint8 *bsid;
	E2kSid *sid2;
	int map;

	g_return_if_fail (E2K_IS_SECURITY_DESCRIPTOR (sd));
	g_return_if_fail (E2K_IS_SID (sid));

	bsid = e2k_sid_get_binary_sid (sid);
	sid2 = g_hash_table_lookup (sd->priv->sids, bsid);
	if (!sid2) {
		int size = g_hash_table_size (sd->priv->sid_order);

		g_hash_table_insert (sd->priv->sids, (char *)bsid, sid);
		g_object_ref (sid);

		g_hash_table_insert (sd->priv->sid_order, sid,
				     GUINT_TO_POINTER (size + 1));
	} else
		sid = sid2;

	object_allowed    = 0;
	object_denied     = object_permissions_all;
	container_allowed = 0;
	container_denied  = container_permissions_all;

	for (map = 0; map < permissions_map_size; map++) {
		if (!(permissions_map[map].mapi_permission & perms))
			continue;

		object_allowed    |=  permissions_map[map].object_allowed;
		object_denied     &= ~permissions_map[map].object_not_denied;
		container_allowed |=  permissions_map[map].container_allowed;
		container_denied  &= ~permissions_map[map].container_not_denied;
	}

	ace.Sid = sid;
	ace.Header.AceSize = GUINT16_TO_LE (sizeof (ace.Header) +
					    sizeof (ace.Mask) +
					    E2K_SID_BINARY_SID_LEN (bsid));

	ace.Header.AceType  = E2K_ACCESS_ALLOWED_ACE_TYPE;
	ace.Header.AceFlags = E2K_OBJECT_INHERIT_ACE | E2K_INHERIT_ONLY_ACE;
	ace.Mask = object_allowed;
	set_ace (sd, &ace);
	if (sid != sd->priv->default_sid) {
		ace.Header.AceType  = E2K_ACCESS_DENIED_ACE_TYPE;
		ace.Header.AceFlags = E2K_OBJECT_INHERIT_ACE | E2K_INHERIT_ONLY_ACE;
		ace.Mask = object_denied;
		set_ace (sd, &ace);
	}

	ace.Header.AceType  = E2K_ACCESS_ALLOWED_ACE_TYPE;
	ace.Header.AceFlags = E2K_CONTAINER_INHERIT_ACE;
	ace.Mask = container_allowed;
	set_ace (sd, &ace);
	if (sid != sd->priv->default_sid) {
		ace.Header.AceType  = E2K_ACCESS_DENIED_ACE_TYPE;
		ace.Header.AceFlags = E2K_CONTAINER_INHERIT_ACE;
		ace.Mask = container_denied;
		set_ace (sd, &ace);
	}
}
Beispiel #8
0
/**
 * e2k_security_descriptor_to_binary:
 * @sd: an #E2kSecurityDescriptor
 *
 * Converts @sd back to binary (#E2K_PR_EXCHANGE_SD_BINARY) form
 * so it can be PROPPATCHed back to the server.
 *
 * Return value: the binary form of @sd.
 **/
GByteArray *
e2k_security_descriptor_to_binary (E2kSecurityDescriptor *sd)
{
	GByteArray *binsd;
	E2k_SECURITY_DESCRIPTOR_RELATIVE sdbuf;
	E2k_ACL aclbuf;
	E2k_ACE *aces;
	int off, ace, last_ace = -1, acl_size, ace_count;
	const guint8 *bsid;

	g_return_val_if_fail (E2K_IS_SECURITY_DESCRIPTOR (sd), NULL);

	aces = (E2k_ACE *)sd->priv->aces->data;

	/* Compute the length of the ACL first */
	acl_size = sizeof (E2k_ACL);
	for (ace = ace_count = 0; ace < sd->priv->aces->len; ace++) {
		if (aces[ace].Mask) {
			ace_count++;
			acl_size += GUINT16_FROM_LE (aces[ace].Header.AceSize);
		}
	}

	binsd = g_byte_array_new ();

	/* Exchange-specific header */
	g_byte_array_append (binsd, sd->priv->header->data,
			     sd->priv->header->len);

	/* SECURITY_DESCRIPTOR header */
	memset (&sdbuf, 0, sizeof (sdbuf));
	sdbuf.Revision = E2K_SECURITY_DESCRIPTOR_REVISION;
	sdbuf.Control = sd->priv->control_flags;
	off = sizeof (sdbuf);
	sdbuf.Dacl = GUINT32_TO_LE (off);
	off += acl_size;
	sdbuf.Owner = GUINT32_TO_LE (off);
	bsid = e2k_sid_get_binary_sid (sd->priv->owner);
	off += E2K_SID_BINARY_SID_LEN (bsid);
	sdbuf.Group = GUINT32_TO_LE (off);
	g_byte_array_append (binsd, (gpointer)&sdbuf, sizeof (sdbuf));

	/* ACL header */
	aclbuf.AclRevision = E2K_ACL_REVISION;
	aclbuf.Sbz1        = 0;
	aclbuf.AclSize     = GUINT16_TO_LE (acl_size);
	aclbuf.AceCount    = GUINT16_TO_LE (ace_count);
	aclbuf.Sbz2        = 0;
	g_byte_array_append (binsd, (gpointer)&aclbuf, sizeof (aclbuf));

	/* ACEs */
	for (ace = 0; ace < sd->priv->aces->len; ace++) {
		if (!aces[ace].Mask)
			continue;

		if (last_ace != -1) {
			if (ace_compar (&aces[last_ace], &aces[ace], sd) != -1) {
				g_warning ("ACE order mismatch at %d\n", ace);
				g_byte_array_free (binsd, TRUE);
				return NULL;
			}
		}

		g_byte_array_append (binsd, (gpointer)&aces[ace],
				     sizeof (aces[ace].Header) +
				     sizeof (aces[ace].Mask));
		bsid = e2k_sid_get_binary_sid (aces[ace].Sid);
		g_byte_array_append (binsd, bsid,
				     E2K_SID_BINARY_SID_LEN (bsid));
		last_ace = ace;
	}

	/* Owner and Group */
	bsid = e2k_sid_get_binary_sid (sd->priv->owner);
	g_byte_array_append (binsd, bsid, E2K_SID_BINARY_SID_LEN (bsid));
	bsid = e2k_sid_get_binary_sid (sd->priv->group);
	g_byte_array_append (binsd, bsid, E2K_SID_BINARY_SID_LEN (bsid));

	return binsd;
}