1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
3 /* Copyright (C) 2001-2004 Novell, Inc.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU Lesser General Public
7 * License as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
24 #include "e2k-security-descriptor.h"
29 #include <libxml/parser.h>
30 #include <libxml/tree.h>
31 #include <libxml/xmlmemory.h>
33 struct _E2kSecurityDescriptorPrivate {
35 guint16 control_flags;
38 E2kSid *default_sid, *owner, *group;
39 GHashTable *sids, *sid_order;
50 } E2k_SECURITY_DESCRIPTOR_RELATIVE;
52 #define E2K_SECURITY_DESCRIPTOR_REVISION 1
53 #define E2K_SE_DACL_PRESENT GUINT16_TO_LE(0x0004)
54 #define E2K_SE_SACL_PRESENT GUINT16_TO_LE(0x0010)
55 #define E2K_SE_DACL_PROTECTED GUINT16_TO_LE(0x1000)
65 #define E2K_ACL_REVISION 2
73 #define E2K_ACCESS_ALLOWED_ACE_TYPE (0x00)
74 #define E2K_ACCESS_DENIED_ACE_TYPE (0x01)
76 #define E2K_OBJECT_INHERIT_ACE (0x01)
77 #define E2K_CONTAINER_INHERIT_ACE (0x02)
78 #define E2K_INHERIT_ONLY_ACE (0x08)
81 E2k_ACE_HEADER Header;
87 guint32 mapi_permission;
88 guint32 container_allowed, container_not_denied;
89 guint32 object_allowed, object_not_denied;
92 /* The magic numbers are from the WSS SDK, except modified to match
95 #define LE(x) (GUINT32_TO_LE (x))
96 static E2kPermissionsMap permissions_map[] = {
97 { E2K_PERMISSION_READ_ANY,
98 LE(0x000000), LE(0x000000), LE(0x1208a9), LE(0x0008a9) },
99 { E2K_PERMISSION_CREATE,
100 LE(0x000002), LE(0x000002), LE(0x000000), LE(0x000000) },
101 { E2K_PERMISSION_CREATE_SUBFOLDER,
102 LE(0x000004), LE(0x000004), LE(0x000000), LE(0x000000) },
103 { E2K_PERMISSION_EDIT_OWNED,
104 LE(0x000000), LE(0x000000), LE(0x000200), LE(0x000000) },
105 { E2K_PERMISSION_DELETE_OWNED,
106 LE(0x000000), LE(0x000000), LE(0x000400), LE(0x000000) },
107 { E2K_PERMISSION_EDIT_ANY,
108 LE(0x000000), LE(0x000000), LE(0x0c0116), LE(0x1e0316) },
109 { E2K_PERMISSION_DELETE_ANY,
110 LE(0x000000), LE(0x000000), LE(0x010000), LE(0x010400) },
111 { E2K_PERMISSION_OWNER,
112 LE(0x0d4110), LE(0x0d4110), LE(0x000000), LE(0x000000) },
113 { E2K_PERMISSION_CONTACT,
114 LE(0x008000), LE(0x008000), LE(0x000000), LE(0x000000) },
115 { E2K_PERMISSION_FOLDER_VISIBLE,
116 LE(0x1208a9), LE(0x1200a9), LE(0x000000), LE(0x000000) }
118 static const int permissions_map_size =
119 sizeof (permissions_map) / sizeof (permissions_map[0]);
121 static const guint32 container_permissions_all = LE(0x1fc9bf);
122 static const guint32 object_permissions_all = LE(0x1f0fbf);
125 #define PARENT_TYPE G_TYPE_OBJECT
126 static GObjectClass *parent_class = NULL;
128 static void dispose (GObject *object);
131 class_init (GObjectClass *object_class)
133 parent_class = g_type_class_ref (PARENT_TYPE);
135 object_class->dispose = dispose;
139 init (E2kSecurityDescriptor *sd)
141 sd->priv = g_new0 (E2kSecurityDescriptorPrivate, 1);
143 sd->priv->sids = g_hash_table_new (e2k_sid_binary_sid_hash,
144 e2k_sid_binary_sid_equal);
145 sd->priv->sid_order = g_hash_table_new (NULL, NULL);
146 sd->priv->aces = g_array_new (FALSE, TRUE, sizeof (E2k_ACE));
150 free_sid (gpointer key, gpointer sid, gpointer data)
152 g_object_unref (sid);
156 dispose (GObject *object)
158 E2kSecurityDescriptor *sd = (E2kSecurityDescriptor *) object;
161 g_hash_table_foreach (sd->priv->sids, free_sid, NULL);
162 g_hash_table_destroy (sd->priv->sids);
163 g_hash_table_destroy (sd->priv->sid_order);
165 g_array_free (sd->priv->aces, TRUE);
167 if (sd->priv->header)
168 g_byte_array_free (sd->priv->header, TRUE);
174 G_OBJECT_CLASS (parent_class)->dispose (object);
177 E2K_MAKE_TYPE (e2k_security_descriptor, E2kSecurityDescriptor, class_init, init, PARENT_TYPE)
180 /* This determines the relative ordering of any two ACEs in a SID.
181 * See docs/security for details.
184 ace_compar (E2k_ACE *ace1, E2k_ACE *ace2, E2kSecurityDescriptor *sd)
193 /* Figure out which overall section the SID will go in and
194 * what its order within that group is.
196 if (ace1->Sid == sd->priv->default_sid)
197 t1 = E2K_SID_TYPE_GROUP;
199 t1 = e2k_sid_get_sid_type (ace1->Sid);
200 order1 = GPOINTER_TO_INT (g_hash_table_lookup (sd->priv->sid_order,
203 if (ace2->Sid == sd->priv->default_sid)
204 t2 = E2K_SID_TYPE_GROUP;
206 t2 = e2k_sid_get_sid_type (ace2->Sid);
207 order2 = GPOINTER_TO_INT (g_hash_table_lookup (sd->priv->sid_order,
211 if (t1 == E2K_SID_TYPE_USER)
213 else if (t2 == E2K_SID_TYPE_USER)
215 else if (t1 == E2K_SID_TYPE_GROUP)
217 else /* (t2 == E2K_SID_TYPE_GROUP) */
221 if (t1 != E2K_SID_TYPE_GROUP) {
222 /* Object-level ACEs go before Container-level ACEs */
223 if ((ace1->Header.AceFlags & E2K_OBJECT_INHERIT_ACE) &&
224 !(ace2->Header.AceFlags & E2K_OBJECT_INHERIT_ACE))
226 else if ((ace2->Header.AceFlags & E2K_OBJECT_INHERIT_ACE) &&
227 !(ace1->Header.AceFlags & E2K_OBJECT_INHERIT_ACE))
230 /* Compare SID order */
233 else if (order1 > order2)
236 /* Allowed ACEs for a given SID go before Denied ACEs */
237 if (ace1->Header.AceType == ace2->Header.AceType)
239 else if (ace1->Header.AceType == E2K_ACCESS_ALLOWED_ACE_TYPE)
244 /* For groups, object-level ACEs go after Container-level */
245 if ((ace1->Header.AceFlags & E2K_OBJECT_INHERIT_ACE) &&
246 !(ace2->Header.AceFlags & E2K_OBJECT_INHERIT_ACE))
248 else if ((ace2->Header.AceFlags & E2K_OBJECT_INHERIT_ACE) &&
249 !(ace1->Header.AceFlags & E2K_OBJECT_INHERIT_ACE))
252 /* Default comes after groups in each section */
253 if (ace1->Sid != ace2->Sid) {
254 if (ace1->Sid == sd->priv->default_sid)
256 else if (ace2->Sid == sd->priv->default_sid)
260 /* All Allowed ACEs go before all Denied ACEs */
261 if (ace1->Header.AceType == E2K_ACCESS_ALLOWED_ACE_TYPE &&
262 ace2->Header.AceType == E2K_ACCESS_DENIED_ACE_TYPE)
264 else if (ace1->Header.AceType == E2K_ACCESS_DENIED_ACE_TYPE &&
265 ace2->Header.AceType == E2K_ACCESS_ALLOWED_ACE_TYPE)
268 /* Compare SID order */
271 else if (order1 > order2)
280 find_child (xmlNode *node, const char *name)
282 for (node = node->xmlChildrenNode; node; node = node->next) {
283 if (node->name && !strcmp (node->name, name))
290 extract_sids (E2kSecurityDescriptor *sd, xmlNodePtr node)
292 xmlNodePtr string_sid_node, type_node, display_name_node;
293 char *string_sid, *content, *display_name;
298 for (; node; node = node->next) {
299 if (strcmp (node->name, "sid") != 0) {
300 if (node->xmlChildrenNode)
301 extract_sids (sd, node->xmlChildrenNode);
305 string_sid_node = find_child (node, "string_sid");
306 type_node = find_child (node, "type");
307 display_name_node = find_child (node, "display_name");
308 if (!string_sid_node || !type_node)
311 string_sid = xmlNodeGetContent (string_sid_node);
313 content = xmlNodeGetContent (type_node);
314 if (!content || !strcmp (content, "user"))
315 type = E2K_SID_TYPE_USER;
316 else if (!strcmp (content, "group"))
317 type = E2K_SID_TYPE_GROUP;
318 else if (!strcmp (content, "well_known_group"))
319 type = E2K_SID_TYPE_WELL_KNOWN_GROUP;
320 else if (!strcmp (content, "alias"))
321 type = E2K_SID_TYPE_ALIAS;
323 type = E2K_SID_TYPE_INVALID;
326 if (display_name_node)
327 display_name = xmlNodeGetContent (display_name_node);
331 sid = e2k_sid_new_from_string_sid (type, string_sid,
333 xmlFree (string_sid);
335 xmlFree (display_name);
337 bsid = e2k_sid_get_binary_sid (sid);
338 if (g_hash_table_lookup (sd->priv->sids, bsid)) {
339 g_object_unref (sid);
343 g_hash_table_insert (sd->priv->sids, (char *)bsid, sid);
348 parse_sid (E2kSecurityDescriptor *sd, GByteArray *binsd, guint16 *off,
353 if (binsd->len - *off < E2K_SID_BINARY_SID_MIN_LEN)
355 sid_len = E2K_SID_BINARY_SID_LEN (binsd->data + *off);
356 if (binsd->len - *off < sid_len)
359 *sid = g_hash_table_lookup (sd->priv->sids, binsd->data + *off);
366 parse_acl (E2kSecurityDescriptor *sd, GByteArray *binsd, guint16 *off)
372 if (binsd->len - *off < sizeof (E2k_ACL))
375 memcpy (&aclbuf, binsd->data + *off, sizeof (aclbuf));
376 if (*off + GUINT16_FROM_LE (aclbuf.AclSize) > binsd->len)
378 if (aclbuf.AclRevision != E2K_ACL_REVISION)
381 ace_count = GUINT16_FROM_LE (aclbuf.AceCount);
383 *off += sizeof (aclbuf);
384 for (i = 0; i < ace_count; i++) {
385 if (binsd->len - *off < sizeof (E2k_ACE))
388 memcpy (&acebuf, binsd->data + *off,
389 sizeof (acebuf.Header) + sizeof (acebuf.Mask));
390 *off += sizeof (acebuf.Header) + sizeof (acebuf.Mask);
392 /* If either of OBJECT_INHERIT_ACE or INHERIT_ONLY_ACE
393 * is set, both must be.
395 if (acebuf.Header.AceFlags & E2K_OBJECT_INHERIT_ACE) {
396 if (!(acebuf.Header.AceFlags & E2K_INHERIT_ONLY_ACE))
399 if (acebuf.Header.AceFlags & E2K_INHERIT_ONLY_ACE)
403 if (!parse_sid (sd, binsd, off, &acebuf.Sid))
406 if (!g_hash_table_lookup (sd->priv->sid_order, acebuf.Sid)) {
407 int size = g_hash_table_size (sd->priv->sid_order);
409 g_hash_table_insert (sd->priv->sid_order, acebuf.Sid,
410 GUINT_TO_POINTER (size + 1));
413 g_array_append_val (sd->priv->aces, acebuf);
420 * e2k_security_descriptor_new:
421 * @xml_form: the XML form of the folder's security descriptor
422 * (The "http://schemas.microsoft.com/exchange/security/descriptor"
423 * property, aka %E2K_PR_EXCHANGE_SD_XML)
424 * @binary_form: the binary form of the folder's security descriptor
425 * (The "http://schemas.microsoft.com/exchange/ntsecuritydescriptor"
426 * property, aka %E2K_PR_EXCHANGE_SD_BINARY)
428 * Constructs an #E2kSecurityDescriptor from the data in @xml_form and
431 * Return value: the security descriptor, or %NULL if the data could
434 E2kSecurityDescriptor *
435 e2k_security_descriptor_new (xmlNodePtr xml_form, GByteArray *binary_form)
437 E2kSecurityDescriptor *sd;
438 E2k_SECURITY_DESCRIPTOR_RELATIVE sdbuf;
439 guint16 off, header_len;
441 g_return_val_if_fail (xml_form != NULL, NULL);
442 g_return_val_if_fail (binary_form != NULL, NULL);
444 if (binary_form->len < 2)
447 memcpy (&header_len, binary_form->data, 2);
448 header_len = GUINT16_FROM_LE (header_len);
449 if (header_len + sizeof (sdbuf) > binary_form->len)
452 memcpy (&sdbuf, binary_form->data + header_len, sizeof (sdbuf));
453 if (sdbuf.Revision != E2K_SECURITY_DESCRIPTOR_REVISION)
455 if ((sdbuf.Control & (E2K_SE_DACL_PRESENT | E2K_SE_SACL_PRESENT)) !=
459 sd = g_object_new (E2K_TYPE_SECURITY_DESCRIPTOR, NULL);
460 sd->priv->header = g_byte_array_new ();
461 g_byte_array_append (sd->priv->header, binary_form->data, header_len);
462 sd->priv->control_flags = sdbuf.Control;
464 /* Create a SID for "Default" then extract remaining SIDs from
465 * the XML form since they have display names associated with
468 sd->priv->default_sid =
469 e2k_sid_new_from_string_sid (E2K_SID_TYPE_WELL_KNOWN_GROUP,
470 E2K_SID_WKS_EVERYONE, NULL);
471 g_hash_table_insert (sd->priv->sids,
472 (char *)e2k_sid_get_binary_sid (sd->priv->default_sid),
473 sd->priv->default_sid);
474 extract_sids (sd, xml_form);
476 off = GUINT32_FROM_LE (sdbuf.Owner) + sd->priv->header->len;
477 if (!parse_sid (sd, binary_form, &off, &sd->priv->owner))
479 off = GUINT32_FROM_LE (sdbuf.Group) + sd->priv->header->len;
480 if (!parse_sid (sd, binary_form, &off, &sd->priv->group))
483 off = GUINT32_FROM_LE (sdbuf.Dacl) + sd->priv->header->len;
484 if (!parse_acl (sd, binary_form, &off))
495 * e2k_security_descriptor_to_binary:
496 * @sd: an #E2kSecurityDescriptor
498 * Converts @sd back to binary (#E2K_PR_EXCHANGE_SD_BINARY) form
499 * so it can be PROPPATCHed back to the server.
501 * Return value: the binary form of @sd.
504 e2k_security_descriptor_to_binary (E2kSecurityDescriptor *sd)
507 E2k_SECURITY_DESCRIPTOR_RELATIVE sdbuf;
510 int off, ace, last_ace = -1, acl_size, ace_count;
513 g_return_val_if_fail (E2K_IS_SECURITY_DESCRIPTOR (sd), NULL);
515 aces = (E2k_ACE *)sd->priv->aces->data;
517 /* Compute the length of the ACL first */
518 acl_size = sizeof (E2k_ACL);
519 for (ace = ace_count = 0; ace < sd->priv->aces->len; ace++) {
520 if (aces[ace].Mask) {
522 acl_size += GUINT16_FROM_LE (aces[ace].Header.AceSize);
526 binsd = g_byte_array_new ();
528 /* Exchange-specific header */
529 g_byte_array_append (binsd, sd->priv->header->data,
530 sd->priv->header->len);
532 /* SECURITY_DESCRIPTOR header */
533 memset (&sdbuf, 0, sizeof (sdbuf));
534 sdbuf.Revision = E2K_SECURITY_DESCRIPTOR_REVISION;
535 sdbuf.Control = sd->priv->control_flags;
536 off = sizeof (sdbuf);
537 sdbuf.Dacl = GUINT32_TO_LE (off);
539 sdbuf.Owner = GUINT32_TO_LE (off);
540 bsid = e2k_sid_get_binary_sid (sd->priv->owner);
541 off += E2K_SID_BINARY_SID_LEN (bsid);
542 sdbuf.Group = GUINT32_TO_LE (off);
543 g_byte_array_append (binsd, (gpointer)&sdbuf, sizeof (sdbuf));
546 aclbuf.AclRevision = E2K_ACL_REVISION;
548 aclbuf.AclSize = GUINT16_TO_LE (acl_size);
549 aclbuf.AceCount = GUINT16_TO_LE (ace_count);
551 g_byte_array_append (binsd, (gpointer)&aclbuf, sizeof (aclbuf));
554 for (ace = 0; ace < sd->priv->aces->len; ace++) {
558 if (last_ace != -1) {
559 if (ace_compar (&aces[last_ace], &aces[ace], sd) != -1) {
560 g_warning ("ACE order mismatch at %d\n", ace);
561 g_byte_array_free (binsd, TRUE);
566 g_byte_array_append (binsd, (gpointer)&aces[ace],
567 sizeof (aces[ace].Header) +
568 sizeof (aces[ace].Mask));
569 bsid = e2k_sid_get_binary_sid (aces[ace].Sid);
570 g_byte_array_append (binsd, bsid,
571 E2K_SID_BINARY_SID_LEN (bsid));
575 /* Owner and Group */
576 bsid = e2k_sid_get_binary_sid (sd->priv->owner);
577 g_byte_array_append (binsd, bsid, E2K_SID_BINARY_SID_LEN (bsid));
578 bsid = e2k_sid_get_binary_sid (sd->priv->group);
579 g_byte_array_append (binsd, bsid, E2K_SID_BINARY_SID_LEN (bsid));
585 * e2k_security_descriptor_get_default:
586 * @sd: a security descriptor
588 * Returns an #E2kSid corresponding to the default permissions
589 * associated with @sd. You can pass this to
590 * e2k_security_descriptor_get_permissions() and
591 * e2k_security_descriptor_set_permissions().
593 * Return value: the "Default" SID
596 e2k_security_descriptor_get_default (E2kSecurityDescriptor *sd)
598 return sd->priv->default_sid;
602 * e2k_security_descriptor_get_sids:
603 * @sd: a security descriptor
605 * Returns a #GList containing the SIDs of each user or group
606 * represented in @sd. You can pass these SIDs to
607 * e2k_security_descriptor_get_permissions(),
608 * e2k_security_descriptor_set_permissions(), and
609 * e2k_security_descriptor_remove_sid().
611 * Return value: a list of SIDs. The caller must free the list
612 * with g_list_free(), but should not free the contents.
615 e2k_security_descriptor_get_sids (E2kSecurityDescriptor *sd)
618 GHashTable *added_sids;
622 g_return_val_if_fail (E2K_IS_SECURITY_DESCRIPTOR (sd), NULL);
624 added_sids = g_hash_table_new (NULL, NULL);
625 aces = (E2k_ACE *)sd->priv->aces->data;
626 for (ace = 0; ace < sd->priv->aces->len; ace++) {
627 if (!g_hash_table_lookup (added_sids, aces[ace].Sid)) {
628 g_hash_table_insert (added_sids, aces[ace].Sid,
630 sids = g_list_prepend (sids, aces[ace].Sid);
633 g_hash_table_destroy (added_sids);
639 * e2k_security_descriptor_remove_sid:
640 * @sd: a security descriptor
643 * Removes @sid from @sd. If @sid is a user, this means s/he will now
644 * have only the default permissions on @sd (unless s/he is a member
645 * of a group that is also present in @sd.)
648 e2k_security_descriptor_remove_sid (E2kSecurityDescriptor *sd,
654 g_return_if_fail (E2K_IS_SECURITY_DESCRIPTOR (sd));
655 g_return_if_fail (E2K_IS_SID (sid));
657 /* Canonicalize the SID */
658 sid = g_hash_table_lookup (sd->priv->sids,
659 e2k_sid_get_binary_sid (sid));
663 /* We can't actually remove all trace of the user, because if
664 * he is removed and then re-added without saving in between,
665 * then we need to keep the original AceFlags. So we just
666 * clear out all of the masks, which (assuming the user is
667 * not re-added) will result in him not being written out
671 aces = (E2k_ACE *)sd->priv->aces->data;
672 for (ace = 0; ace < sd->priv->aces->len; ace++) {
673 if (aces[ace].Sid == sid)
679 * e2k_security_descriptor_get_permissions:
680 * @sd: a security descriptor
683 * Computes the MAPI permissions associated with @sid. (Only the
684 * permissions *directly* associated with @sid, not any acquired via
685 * group memberships or the Default SID.)
687 * Return value: the MAPI permissions
690 e2k_security_descriptor_get_permissions (E2kSecurityDescriptor *sd,
694 guint32 mapi_perms, checkperm;
697 g_return_val_if_fail (E2K_IS_SECURITY_DESCRIPTOR (sd), 0);
698 g_return_val_if_fail (E2K_IS_SID (sid), 0);
700 /* Canonicalize the SID */
701 sid = g_hash_table_lookup (sd->priv->sids,
702 e2k_sid_get_binary_sid (sid));
707 aces = (E2k_ACE *)sd->priv->aces->data;
708 for (ace = 0; ace < sd->priv->aces->len; ace++) {
709 if (aces[ace].Sid != sid)
711 if (aces[ace].Header.AceType == E2K_ACCESS_DENIED_ACE_TYPE)
714 for (map = 0; map < permissions_map_size; map++) {
715 if (aces[ace].Header.AceFlags & E2K_OBJECT_INHERIT_ACE)
716 checkperm = permissions_map[map].object_allowed;
718 checkperm = permissions_map[map].container_allowed;
722 if ((aces[ace].Mask & checkperm) == checkperm)
723 mapi_perms |= permissions_map[map].mapi_permission;
730 /* Put @ace into @sd. If no ACE corresponding to @ace currently exists,
731 * it will be added in the right place. If it does already exist, its
732 * flags (in particular INHERITED_ACE) will be preserved and only the
733 * mask will be changed.
736 set_ace (E2kSecurityDescriptor *sd, E2k_ACE *ace)
738 E2k_ACE *aces = (E2k_ACE *)sd->priv->aces->data;
739 int low, mid = 0, high, cmp = -1;
742 high = sd->priv->aces->len - 1;
743 while (low <= high) {
744 mid = (low + high) / 2;
745 cmp = ace_compar (ace, &aces[mid], sd);
748 aces[mid].Mask = ace->Mask;
750 g_array_remove_index (sd->priv->aces, mid);
759 g_array_insert_vals (sd->priv->aces, cmp < 0 ? mid : mid + 1, ace, 1);
763 * e2k_security_descriptor_set_permissions:
764 * @sd: a security descriptor
766 * @perms: the MAPI permissions
768 * Updates or sets @sid's permissions on @sd.
771 e2k_security_descriptor_set_permissions (E2kSecurityDescriptor *sd,
772 E2kSid *sid, guint32 perms)
775 guint32 object_allowed, object_denied;
776 guint32 container_allowed, container_denied;
781 g_return_if_fail (E2K_IS_SECURITY_DESCRIPTOR (sd));
782 g_return_if_fail (E2K_IS_SID (sid));
784 bsid = e2k_sid_get_binary_sid (sid);
785 sid2 = g_hash_table_lookup (sd->priv->sids, bsid);
787 int size = g_hash_table_size (sd->priv->sid_order);
789 g_hash_table_insert (sd->priv->sids, (char *)bsid, sid);
792 g_hash_table_insert (sd->priv->sid_order, sid,
793 GUINT_TO_POINTER (size + 1));
798 object_denied = object_permissions_all;
799 container_allowed = 0;
800 container_denied = container_permissions_all;
802 for (map = 0; map < permissions_map_size; map++) {
803 if (!(permissions_map[map].mapi_permission & perms))
806 object_allowed |= permissions_map[map].object_allowed;
807 object_denied &= ~permissions_map[map].object_not_denied;
808 container_allowed |= permissions_map[map].container_allowed;
809 container_denied &= ~permissions_map[map].container_not_denied;
813 ace.Header.AceSize = GUINT16_TO_LE (sizeof (ace.Header) +
815 E2K_SID_BINARY_SID_LEN (bsid));
817 ace.Header.AceType = E2K_ACCESS_ALLOWED_ACE_TYPE;
818 ace.Header.AceFlags = E2K_OBJECT_INHERIT_ACE | E2K_INHERIT_ONLY_ACE;
819 ace.Mask = object_allowed;
821 if (sid != sd->priv->default_sid) {
822 ace.Header.AceType = E2K_ACCESS_DENIED_ACE_TYPE;
823 ace.Header.AceFlags = E2K_OBJECT_INHERIT_ACE | E2K_INHERIT_ONLY_ACE;
824 ace.Mask = object_denied;
828 ace.Header.AceType = E2K_ACCESS_ALLOWED_ACE_TYPE;
829 ace.Header.AceFlags = E2K_CONTAINER_INHERIT_ACE;
830 ace.Mask = container_allowed;
832 if (sid != sd->priv->default_sid) {
833 ace.Header.AceType = E2K_ACCESS_DENIED_ACE_TYPE;
834 ace.Header.AceFlags = E2K_CONTAINER_INHERIT_ACE;
835 ace.Mask = container_denied;
844 } roles[E2K_PERMISSIONS_ROLE_NUM_ROLES] = {
845 /* i18n: These are Outlook's words for the default roles in
846 the folder permissions dialog. */
847 { N_("Owner"), (E2K_PERMISSION_FOLDER_VISIBLE |
848 E2K_PERMISSION_READ_ANY |
849 E2K_PERMISSION_CREATE |
850 E2K_PERMISSION_DELETE_OWNED |
851 E2K_PERMISSION_EDIT_OWNED |
852 E2K_PERMISSION_DELETE_ANY |
853 E2K_PERMISSION_EDIT_ANY |
854 E2K_PERMISSION_CREATE_SUBFOLDER |
855 E2K_PERMISSION_CONTACT |
856 E2K_PERMISSION_OWNER) },
857 { N_("Publishing Editor"), (E2K_PERMISSION_FOLDER_VISIBLE |
858 E2K_PERMISSION_READ_ANY |
859 E2K_PERMISSION_CREATE |
860 E2K_PERMISSION_DELETE_OWNED |
861 E2K_PERMISSION_EDIT_OWNED |
862 E2K_PERMISSION_DELETE_ANY |
863 E2K_PERMISSION_EDIT_ANY |
864 E2K_PERMISSION_CREATE_SUBFOLDER) },
865 { N_("Editor"), (E2K_PERMISSION_FOLDER_VISIBLE |
866 E2K_PERMISSION_READ_ANY |
867 E2K_PERMISSION_CREATE |
868 E2K_PERMISSION_DELETE_OWNED |
869 E2K_PERMISSION_EDIT_OWNED |
870 E2K_PERMISSION_DELETE_ANY |
871 E2K_PERMISSION_EDIT_ANY) },
872 { N_("Publishing Author"), (E2K_PERMISSION_FOLDER_VISIBLE |
873 E2K_PERMISSION_READ_ANY |
874 E2K_PERMISSION_CREATE |
875 E2K_PERMISSION_DELETE_OWNED |
876 E2K_PERMISSION_EDIT_OWNED |
877 E2K_PERMISSION_CREATE_SUBFOLDER) },
878 { N_("Author"), (E2K_PERMISSION_FOLDER_VISIBLE |
879 E2K_PERMISSION_READ_ANY |
880 E2K_PERMISSION_CREATE |
881 E2K_PERMISSION_DELETE_OWNED |
882 E2K_PERMISSION_EDIT_OWNED) },
883 { N_("Non-editing Author"),(E2K_PERMISSION_FOLDER_VISIBLE |
884 E2K_PERMISSION_READ_ANY |
885 E2K_PERMISSION_CREATE |
886 E2K_PERMISSION_DELETE_OWNED) },
887 { N_("Reviewer"), (E2K_PERMISSION_FOLDER_VISIBLE |
888 E2K_PERMISSION_READ_ANY) },
889 { N_("Contributor"), (E2K_PERMISSION_FOLDER_VISIBLE |
890 E2K_PERMISSION_CREATE) },
891 { N_("None"), (E2K_PERMISSION_FOLDER_VISIBLE) }
895 * e2k_permissions_role_get_name:
896 * @role: a permissions role
898 * Returns the localized name corresponding to @role
900 * Return value: the name
903 e2k_permissions_role_get_name (E2kPermissionsRole role)
905 if (role == E2K_PERMISSIONS_ROLE_CUSTOM)
908 g_return_val_if_fail (role > E2K_PERMISSIONS_ROLE_CUSTOM &&
909 role < E2K_PERMISSIONS_ROLE_NUM_ROLES, NULL);
910 return _(roles[role].name);
914 * e2k_permissions_role_get_perms
915 * @role: a permissions role
917 * Returns the MAPI permissions associated with @role. @role may not
918 * be %E2K_PERMISSIONS_ROLE_CUSTOM.
920 * Return value: the MAPI permissions
923 e2k_permissions_role_get_perms (E2kPermissionsRole role)
925 g_return_val_if_fail (role >= E2K_PERMISSIONS_ROLE_CUSTOM &&
926 role < E2K_PERMISSIONS_ROLE_NUM_ROLES, 0);
927 return roles[role].perms;
931 * e2k_permissions_role_find:
932 * @perms: MAPI permissions
934 * Finds the #E2kPermissionsRole value associated with @perms. If
935 * @perms don't describe any standard role, the return value will be
936 * %E2K_PERMISSIONS_ROLE_CUSTOM
938 * Return value: the role
941 e2k_permissions_role_find (guint perms)
945 /* "Folder contact" isn't actually a permission, and is ignored
946 * for purposes of roles.
948 perms &= ~E2K_PERMISSION_CONTACT;
950 /* The standard "None" permission includes "Folder visible",
951 * but 0 counts as "None" too.
954 return E2K_PERMISSIONS_ROLE_NONE;
956 for (role = 0; role < E2K_PERMISSIONS_ROLE_NUM_ROLES; role++) {
957 if ((roles[role].perms & ~E2K_PERMISSION_CONTACT) == perms)
961 return E2K_PERMISSIONS_ROLE_CUSTOM;