static gboolean
proppatch_sd (E2kContext *ctx,
              ExchangeDelegatesFolder *folder)
{
	GByteArray *binsd;
	E2kProperties *props;
	const gchar *href = "";
	E2kResultIter *iter;
	E2kResult *result;
	E2kHTTPStatus status;

	binsd = e2k_security_descriptor_to_binary (folder->sd);
	if (!binsd)
		return FALSE;

	props = e2k_properties_new ();
	e2k_properties_set_binary (props, E2K_PR_EXCHANGE_SD_BINARY, binsd);

	iter = e2k_context_bproppatch_start (ctx, NULL, folder->uri,
					     &href, 1, props, FALSE);
	e2k_properties_free (props);

	result = e2k_result_iter_next (iter);
	if (result) {
		status = result->status;
		e2k_result_iter_free (iter);
	} else
		status = e2k_result_iter_free (iter);

	return E2K_HTTP_STATUS_IS_SUCCESSFUL (status);
}
/* Fetch the list of delegates from the freebusy message. */
static gboolean
get_user_list (ExchangeDelegates *delegates)
{
	E2kContext *ctx;
	E2kResultIter *iter;
	E2kResult *result;
	GPtrArray *display_names, *entryids, *privflags;
	GByteArray *entryid;
	ExchangeDelegatesUser *user;
	gint i;

	ctx = exchange_account_get_context (delegates->account);
	iter = e2k_context_bpropfind_start (ctx, NULL,
					    delegates->account->home_uri,
					    &exchange_localfreebusy_path, 1,
					    delegation_props,
					    G_N_ELEMENTS (delegation_props));
	result = e2k_result_iter_next (iter);
	if (!result || !E2K_HTTP_STATUS_IS_SUCCESSFUL (result->status)) {
		e2k_result_iter_free (iter);
		return FALSE;
	}

	delegates->users = g_ptr_array_new ();
	delegates->added_users = g_ptr_array_new ();
	delegates->removed_users = g_ptr_array_new ();

	display_names = e2k_properties_get_prop (result->props, PR_DELEGATES_DISPLAY_NAMES);
	entryids      = e2k_properties_get_prop (result->props, PR_DELEGATES_ENTRYIDS);
	privflags     = e2k_properties_get_prop (result->props, PR_DELEGATES_SEE_PRIVATE);

	entryid       = e2k_properties_get_prop (result->props, PR_CREATOR_ENTRYID);
	delegates->creator_entryid = g_byte_array_new ();
	g_byte_array_append (delegates->creator_entryid, entryid->data, entryid->len);

	if (!display_names || !entryids || !privflags) {
		e2k_result_iter_free (iter);
		return TRUE;
	}

	for (i = 0; i < display_names->len && i < entryids->len && i < privflags->len; i++) {
		user = exchange_delegates_user_new (display_names->pdata[i]);
		user->see_private  = privflags->pdata[i] && atoi (privflags->pdata[i]);
		entryid            = entryids->pdata[i];
		user->entryid      = g_byte_array_new ();
		g_byte_array_append (user->entryid, entryid->data, entryid->len);

		g_signal_connect (user, "edited", G_CALLBACK (set_perms_for_user), delegates);

		g_ptr_array_add (delegates->users, user);
	}

	e2k_result_iter_free (iter);
	return TRUE;
}
Exemple #3
0
/**
 * e2k_freebusy_add_from_calendar_uri:
 * @fb: an #E2kFreebusy
 * @uri: the URI of a calendar folder
 * @start_tt: start of the range to add
 * @end_tt: end of the range to add
 *
 * This queries the server for events between @start_tt and @end_tt in
 * the calendar at @uri (which the caller must have permission to
 * read) and adds them @fb. Any previously-existing events during that
 * range are removed.
 *
 * Return value: an HTTP status code.
 **/
E2kHTTPStatus
e2k_freebusy_add_from_calendar_uri (E2kFreebusy *fb, const char *uri,
				    time_t start_tt, time_t end_tt)
{
	char *start, *end, *busystatus;
	E2kBusyStatus busy;
	E2kRestriction *rn;
	E2kResultIter *iter;
	E2kResult *result;

	e2k_freebusy_clear_interval (fb, start_tt, end_tt);

	start = e2k_make_timestamp (start_tt);
	end = e2k_make_timestamp (end_tt);

	rn = e2k_restriction_andv (
		e2k_restriction_prop_string (E2K_PR_DAV_CONTENT_CLASS,
					     E2K_RELOP_EQ,
					     "urn:content-classes:appointment"),
		e2k_restriction_prop_date (E2K_PR_CALENDAR_DTEND,
					   E2K_RELOP_GT, start),
		e2k_restriction_prop_date (E2K_PR_CALENDAR_DTSTART,
					   E2K_RELOP_LT, end),
		e2k_restriction_prop_string (E2K_PR_CALENDAR_BUSY_STATUS,
					     E2K_RELOP_NE, "FREE"),
		NULL);

	iter = e2k_context_search_start (fb->ctx, NULL, uri,
					 freebusy_props, n_freebusy_props,
					 rn, NULL, TRUE);
	e2k_restriction_unref (rn);
	g_free (start);
	g_free (end);

	while ((result = e2k_result_iter_next (iter))) {
		start = e2k_properties_get_prop (result->props,
						 E2K_PR_CALENDAR_DTSTART);
		end = e2k_properties_get_prop (result->props,
					       E2K_PR_CALENDAR_DTEND);
		busystatus = e2k_properties_get_prop (result->props,
						      E2K_PR_CALENDAR_BUSY_STATUS);
		if (!start || !end || !busystatus)
			continue;

		if (!strcmp (busystatus, "TENTATIVE"))
			busy = E2K_BUSYSTATUS_TENTATIVE;
		else if (!strcmp (busystatus, "OUTOFOFFICE"))
			busy = E2K_BUSYSTATUS_OOF;
		else
			busy = E2K_BUSYSTATUS_BUSY;

		e2k_freebusy_add_interval (fb, busy,
					   e2k_parse_timestamp (start),
					   e2k_parse_timestamp (end));

	}

	return e2k_result_iter_free (iter);
}
static void
delegates_apply (ExchangeDelegates *delegates)
{
	ExchangeDelegatesUser *user;
	E2kGlobalCatalog *gc;
	E2kContext *ctx;
	GPtrArray *display_names, *entryids, *privflags;
	GByteArray *entryid_dup;
	gchar *error = NULL;
	E2kProperties *props;
	gint i;
	E2kGlobalCatalogStatus status;

	if (!delegates->loaded_folders)
		return;

	/* We can't do this atomically/transactionally, so we need to
	 * make sure that if we fail at any step, things are still in
	 * a semi-consistent state. So we do:
	 *
	 *   1. Remove old delegates from AD
	 *   2. Update LocalFreebusy.EML (the canonical list of delegates)
	 *   3. Add new delegates to AD
	 *   4. Update security descriptors
	 *
	 * If step 1 fails, nothing is changed.
	 *
	 * If step 2 fails, delegates who should have been removed
	 * will have been removed from AD but nothing else, so they
	 * will still show up as being delegates and the user can try
	 * to remove them again later.
	 *
	 * If step 3 fails, delegates who should have been added will
	 * not be in AD, but will be listed as delegates, so the user
	 * can remove them and try adding them again later.
	 *
	 * If step 4 fails, the user can still correct the folder
	 * permissions by hand.
	 */

	gc = exchange_account_get_global_catalog (delegates->account);
	if (!gc) {
		error = g_strdup (_("Could not access Active Directory"));
		goto done;
	}

	if ((delegates->removed_users || delegates->added_users) && !delegates->self_dn) {
		E2kGlobalCatalogEntry *entry;

		status = e2k_global_catalog_lookup (
			gc, NULL, /* FIXME: cancellable */
			E2K_GLOBAL_CATALOG_LOOKUP_BY_LEGACY_EXCHANGE_DN,
			delegates->account->legacy_exchange_dn, 0, &entry);
		if (status != E2K_GLOBAL_CATALOG_OK) {
			error = g_strdup (_("Could not find self in Active Directory"));
			goto done;
		}

		delegates->self_dn = g_strdup (entry->dn);
		e2k_global_catalog_entry_free (gc, entry);
	}

	/* 1. Remove old delegates from AD */
	while (delegates->removed_users && delegates->removed_users->len) {
		user = delegates->removed_users->pdata[0];
		if (!user->dn && !get_user_dn (gc, user)) {
			error = g_strdup_printf (
				_("Could not find delegate %s in Active Directory"),
				user->display_name);
			goto done;
		}

		/* FIXME: cancellable */
		status = e2k_global_catalog_remove_delegate (gc, NULL,
							     delegates->self_dn,
							     user->dn);
		if (status != E2K_GLOBAL_CATALOG_OK &&
		    status != E2K_GLOBAL_CATALOG_NO_DATA) {
			error = g_strdup_printf (
				_("Could not remove delegate %s"),
				user->display_name);
			goto done;
		}

		g_object_unref (user);
		g_ptr_array_remove_index_fast (delegates->removed_users, 0);
	}

	/* 2. Update LocalFreebusy.EML */
	ctx = exchange_account_get_context (delegates->account);

	if (delegates->users->len) {
		display_names = g_ptr_array_new ();
		entryids = g_ptr_array_new ();
		privflags = g_ptr_array_new ();

		for (i = 0; i < delegates->users->len; i++) {
			user = delegates->users->pdata[i];
			g_ptr_array_add (display_names, g_strdup (user->display_name));
			entryid_dup = g_byte_array_new ();
			g_byte_array_append (entryid_dup, user->entryid->data,
					     user->entryid->len);
			g_ptr_array_add (entryids, entryid_dup);
			g_ptr_array_add (privflags, g_strdup_printf ("%d", user->see_private));
		}

		props = e2k_properties_new ();
		e2k_properties_set_string_array (
			props, PR_DELEGATES_DISPLAY_NAMES, display_names);
		e2k_properties_set_binary_array (
			props, PR_DELEGATES_ENTRYIDS, entryids);
		e2k_properties_set_int_array (
			props, PR_DELEGATES_SEE_PRIVATE, privflags);
	} else if (delegates->removed_users) {
		props = e2k_properties_new ();
		e2k_properties_remove (props, PR_DELEGATES_DISPLAY_NAMES);
		e2k_properties_remove (props, PR_DELEGATES_ENTRYIDS);
		e2k_properties_remove (props, PR_DELEGATES_SEE_PRIVATE);
	} else
		props = NULL;

	if (props) {
		E2kResultIter *iter;
		E2kResult *result;

		iter = e2k_context_bproppatch_start (
			ctx, NULL, delegates->account->home_uri,
			&exchange_localfreebusy_path, 1,
			props, FALSE);
		e2k_properties_free (props);

		result = e2k_result_iter_next (iter);
		if (result) {
			status = result->status;
			e2k_result_iter_free (iter);
		} else
			status = e2k_result_iter_free (iter);

		if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) {
			error = g_strdup (_("Could not update list of delegates."));
			goto done;
		}
	}

	/* 3. Add new delegates to AD */
	while (delegates->added_users && delegates->added_users->len) {
		user = delegates->added_users->pdata[0];
		/* An added user must have come from the GC so
		 * we know user->dn is set.
		 */
		/* FIXME: cancellable */
		status = e2k_global_catalog_add_delegate (gc, NULL,
							  delegates->self_dn,
							  user->dn);
		if (status != E2K_GLOBAL_CATALOG_OK &&
		    status != E2K_GLOBAL_CATALOG_EXISTS) {
			error = g_strdup_printf (
				_("Could not add delegate %s"),
				user->display_name);
			goto done;
		}
		g_ptr_array_remove_index_fast (delegates->added_users, 0);
		g_object_unref (user);
	}

	/* 4. Update security descriptors */
	for (i = 0; i < EXCHANGE_DELEGATES_LAST; i++)
		proppatch_sd (ctx, &delegates->folder[i]);
	proppatch_sd (ctx, &delegates->freebusy_folder);

 done:
	if (error) {
		e_alert_run_dialog_for_args (GTK_WINDOW (delegates->table), ERROR_DOMAIN ":delegate-fail-error", error, NULL);
		g_free (error);
	}
}
/* Read the folder security descriptors and match them up with the
 * list of delegates.
 */
static gboolean
get_folder_security (ExchangeDelegates *delegates)
{
	GPtrArray *hrefs;
	E2kContext *ctx;
	E2kHTTPStatus status;
	E2kResultIter *iter;
	E2kResult *result;
	xmlNode *xml_form;
	GByteArray *binary_form;
	ExchangeDelegatesUser *user;
	guint32 perms;
	gint i, u;

	/* If we've been here before, just return the success or
	 * failure result from last time.
	 */
	if (delegates->freebusy_folder.uri)
		return delegates->loaded_folders;

	if (!exchange_account_get_global_catalog (delegates->account)) {
		e_alert_run_dialog_for_args (GTK_WINDOW (delegates->table), ERROR_DOMAIN ":delegates-no-gcs-error",
			     NULL);
		return FALSE;
	}

	ctx = exchange_account_get_context (delegates->account);

	hrefs = g_ptr_array_new ();
	for (i = 0; i < EXCHANGE_DELEGATES_LAST; i++) {
		delegates->folder[i].uri = exchange_account_get_standard_uri (
			delegates->account, exchange_delegates_user_folder_names[i]);
		if (delegates->folder[i].uri) {
			g_ptr_array_add (hrefs, (gchar *) e2k_uri_relative (
						 delegates->account->home_uri,
						 delegates->folder[i].uri));
		}
	}
	g_ptr_array_add (hrefs, (gchar *) exchange_localfreebusy_path);

	iter = e2k_context_bpropfind_start (
		ctx, NULL, delegates->account->home_uri,
		(const gchar **) hrefs->pdata, hrefs->len,
		sd_props, G_N_ELEMENTS (sd_props));
	g_ptr_array_free (hrefs, TRUE);

	while ((result = e2k_result_iter_next (iter))) {
		xml_form = e2k_properties_get_prop (result->props,
						    E2K_PR_EXCHANGE_SD_XML);
		binary_form = e2k_properties_get_prop (result->props,
						       E2K_PR_EXCHANGE_SD_BINARY);

		if (xml_form && binary_form) {
			set_sd_for_href (delegates, result->href,
					 e2k_security_descriptor_new (xml_form, binary_form));
		}
	}
	status = e2k_result_iter_free (iter);

	if (!E2K_HTTP_STATUS_IS_SUCCESSFUL (status)) {
		e_alert_run_dialog_for_args (GTK_WINDOW (delegates->table), ERROR_DOMAIN ":delegates-perm-read-error",
			     NULL);
		return FALSE;
	}

	if (!fill_in_sids (delegates)) {
		delegates->loaded_folders = FALSE;
		e_alert_run_dialog_for_args (GTK_WINDOW (delegates->table), ERROR_DOMAIN ":perm-deter-error", NULL);
		return FALSE;
	}

	/* Fill in delegate structures from the security descriptors */
	for (i = 0; i < EXCHANGE_DELEGATES_LAST; i++) {
		for (u = 0; u < delegates->users->len; u++) {
			user = delegates->users->pdata[u];
			perms = e2k_security_descriptor_get_permissions (
				delegates->folder[i].sd, user->sid);
			user->role[i] = e2k_permissions_role_find (perms);
		}
	}

	delegates->loaded_folders = TRUE;
	return TRUE;
}