~ubuntu-branches/ubuntu/maverick/evolution-data-server/maverick-proposed

« back to all changes in this revision

Viewing changes to servers/exchange/lib/e2k-security-descriptor.c

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2010-05-17 17:02:06 UTC
  • mfrom: (1.1.79 upstream) (1.6.12 experimental)
  • Revision ID: james.westby@ubuntu.com-20100517170206-4ufr52vwrhh26yh0
Tags: 2.30.1-1ubuntu1
* Merge from debian experimental. Remaining change:
  (LP: #42199, #229669, #173703, #360344, #508494)
  + debian/control:
    - add Vcs-Bzr tag
    - don't use libgnome
    - Use Breaks instead of Conflicts against evolution 2.25 and earlier.
  + debian/evolution-data-server.install,
    debian/patches/45_libcamel_providers_version.patch:
    - use the upstream versioning, not a Debian-specific one 
  + debian/libedata-book1.2-dev.install, debian/libebackend-1.2-dev.install,
    debian/libcamel1.2-dev.install, debian/libedataserverui1.2-dev.install:
    - install html documentation
  + debian/rules:
    - don't build documentation it's shipped with the tarball

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
 
 
3
 
/* Copyright (C) 2001-2004 Novell, Inc.
4
 
 *
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.
8
 
 *
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.
13
 
 *
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.
18
 
 */
19
 
 
20
 
#ifdef HAVE_CONFIG_H
21
 
#include "config.h"
22
 
#endif
23
 
 
24
 
#include "e2k-security-descriptor.h"
25
 
#include "e2k-sid.h"
26
 
 
27
 
#include <stdlib.h>
28
 
#include <string.h>
29
 
#include <libxml/parser.h>
30
 
#include <libxml/tree.h>
31
 
#include <libxml/xmlmemory.h>
32
 
 
33
 
struct _E2kSecurityDescriptorPrivate {
34
 
        GByteArray *header;
35
 
        guint16 control_flags;
36
 
        GArray *aces;
37
 
 
38
 
        E2kSid *default_sid, *owner, *group;
39
 
        GHashTable *sids, *sid_order;
40
 
};
41
 
 
42
 
typedef struct {
43
 
        guint8  Revision;
44
 
        guint8  Sbz1;
45
 
        guint16 Control;
46
 
        guint32 Owner;
47
 
        guint32 Group;
48
 
        guint32 Sacl;
49
 
        guint32 Dacl;
50
 
} E2k_SECURITY_DESCRIPTOR_RELATIVE;
51
 
 
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)
56
 
 
57
 
typedef struct {
58
 
        guint8  AclRevision;
59
 
        guint8  Sbz1;
60
 
        guint16 AclSize;
61
 
        guint16 AceCount;
62
 
        guint16 Sbz2;
63
 
} E2k_ACL;
64
 
 
65
 
#define E2K_ACL_REVISION 2
66
 
 
67
 
typedef struct {
68
 
        guint8  AceType;
69
 
        guint8  AceFlags;
70
 
        guint16 AceSize;
71
 
} E2k_ACE_HEADER;
72
 
 
73
 
#define E2K_ACCESS_ALLOWED_ACE_TYPE (0x00)
74
 
#define E2K_ACCESS_DENIED_ACE_TYPE  (0x01)
75
 
 
76
 
#define E2K_OBJECT_INHERIT_ACE      (0x01)
77
 
#define E2K_CONTAINER_INHERIT_ACE   (0x02)
78
 
#define E2K_INHERIT_ONLY_ACE        (0x08)
79
 
 
80
 
typedef struct {
81
 
        E2k_ACE_HEADER  Header;
82
 
        guint32         Mask;
83
 
        E2kSid         *Sid;
84
 
} E2k_ACE;
85
 
 
86
 
typedef struct {
87
 
        guint32 mapi_permission;
88
 
        guint32 container_allowed, container_not_denied;
89
 
        guint32 object_allowed, object_not_denied;
90
 
} E2kPermissionsMap;
91
 
 
92
 
/* The magic numbers are from the WSS SDK, except modified to match
93
 
 * Outlook a bit.
94
 
 */
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) }
117
 
};
118
 
static const gint permissions_map_size =
119
 
        sizeof (permissions_map) / sizeof (permissions_map[0]);
120
 
 
121
 
static const guint32 container_permissions_all = LE(0x1fc9bf);
122
 
static const guint32 object_permissions_all    = LE(0x1f0fbf);
123
 
#undef LE
124
 
 
125
 
#define PARENT_TYPE G_TYPE_OBJECT
126
 
static GObjectClass *parent_class = NULL;
127
 
 
128
 
static void dispose (GObject *object);
129
 
 
130
 
static void
131
 
class_init (GObjectClass *object_class)
132
 
{
133
 
        parent_class = g_type_class_ref (PARENT_TYPE);
134
 
 
135
 
        object_class->dispose = dispose;
136
 
}
137
 
 
138
 
static void
139
 
init (E2kSecurityDescriptor *sd)
140
 
{
141
 
        sd->priv = g_new0 (E2kSecurityDescriptorPrivate, 1);
142
 
 
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));
147
 
}
148
 
 
149
 
static void
150
 
free_sid (gpointer key, gpointer sid, gpointer data)
151
 
{
152
 
        g_object_unref (sid);
153
 
}
154
 
 
155
 
static void
156
 
dispose (GObject *object)
157
 
{
158
 
        E2kSecurityDescriptor *sd = (E2kSecurityDescriptor *) object;
159
 
 
160
 
        if (sd->priv) {
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);
164
 
 
165
 
                g_array_free (sd->priv->aces, TRUE);
166
 
 
167
 
                if (sd->priv->header)
168
 
                        g_byte_array_free (sd->priv->header, TRUE);
169
 
 
170
 
                g_free (sd->priv);
171
 
                sd->priv = NULL;
172
 
        }
173
 
 
174
 
        G_OBJECT_CLASS (parent_class)->dispose (object);
175
 
}
176
 
 
177
 
E2K_MAKE_TYPE (e2k_security_descriptor, E2kSecurityDescriptor, class_init, init, PARENT_TYPE)
178
 
 
179
 
/* This determines the relative ordering of any two ACEs in a SID.
180
 
 * See docs/security for details.
181
 
 */
182
 
static gint
183
 
ace_compar (E2k_ACE *ace1, E2k_ACE *ace2, E2kSecurityDescriptor *sd)
184
 
{
185
 
        E2kSidType t1;
186
 
        E2kSidType t2;
187
 
        gint order1, order2;
188
 
 
189
 
        if (ace1 == ace2)
190
 
                return 0;
191
 
 
192
 
        /* Figure out which overall section the SID will go in and
193
 
         * what its order within that group is.
194
 
         */
195
 
        if (ace1->Sid == sd->priv->default_sid)
196
 
                t1 = E2K_SID_TYPE_GROUP;
197
 
        else
198
 
                t1 = e2k_sid_get_sid_type (ace1->Sid);
199
 
        order1 = GPOINTER_TO_INT (g_hash_table_lookup (sd->priv->sid_order,
200
 
                                                       ace1->Sid));
201
 
 
202
 
        if (ace2->Sid == sd->priv->default_sid)
203
 
                t2 = E2K_SID_TYPE_GROUP;
204
 
        else
205
 
                t2 = e2k_sid_get_sid_type (ace2->Sid);
206
 
        order2 = GPOINTER_TO_INT (g_hash_table_lookup (sd->priv->sid_order,
207
 
                                                       ace2->Sid));
208
 
 
209
 
        if (t1 != t2) {
210
 
                if (t1 == E2K_SID_TYPE_USER)
211
 
                        return -1;
212
 
                else if (t2 == E2K_SID_TYPE_USER)
213
 
                        return 1;
214
 
                else if (t1 == E2K_SID_TYPE_GROUP)
215
 
                        return 1;
216
 
                else /* (t2 == E2K_SID_TYPE_GROUP) */
217
 
                        return -1;
218
 
        }
219
 
 
220
 
        if (t1 != E2K_SID_TYPE_GROUP) {
221
 
                /* Object-level ACEs go before Container-level ACEs */
222
 
                if ((ace1->Header.AceFlags & E2K_OBJECT_INHERIT_ACE) &&
223
 
                    !(ace2->Header.AceFlags & E2K_OBJECT_INHERIT_ACE))
224
 
                        return -1;
225
 
                else if ((ace2->Header.AceFlags & E2K_OBJECT_INHERIT_ACE) &&
226
 
                         !(ace1->Header.AceFlags & E2K_OBJECT_INHERIT_ACE))
227
 
                        return 1;
228
 
 
229
 
                /* Compare SID order */
230
 
                if (order1 < order2)
231
 
                        return -1;
232
 
                else if (order1 > order2)
233
 
                        return 1;
234
 
 
235
 
                /* Allowed ACEs for a given SID go before Denied ACEs */
236
 
                if (ace1->Header.AceType == ace2->Header.AceType)
237
 
                        return 0;
238
 
                else if (ace1->Header.AceType == E2K_ACCESS_ALLOWED_ACE_TYPE)
239
 
                        return -1;
240
 
                else
241
 
                        return 1;
242
 
        } else {
243
 
                /* For groups, object-level ACEs go after Container-level */
244
 
                if ((ace1->Header.AceFlags & E2K_OBJECT_INHERIT_ACE) &&
245
 
                    !(ace2->Header.AceFlags & E2K_OBJECT_INHERIT_ACE))
246
 
                        return 1;
247
 
                else if ((ace2->Header.AceFlags & E2K_OBJECT_INHERIT_ACE) &&
248
 
                         !(ace1->Header.AceFlags & E2K_OBJECT_INHERIT_ACE))
249
 
                        return -1;
250
 
 
251
 
                /* Default comes after groups in each section */
252
 
                if (ace1->Sid != ace2->Sid) {
253
 
                        if (ace1->Sid == sd->priv->default_sid)
254
 
                                return 1;
255
 
                        else if (ace2->Sid == sd->priv->default_sid)
256
 
                                return -1;
257
 
                }
258
 
 
259
 
                /* All Allowed ACEs go before all Denied ACEs */
260
 
                if (ace1->Header.AceType == E2K_ACCESS_ALLOWED_ACE_TYPE &&
261
 
                    ace2->Header.AceType == E2K_ACCESS_DENIED_ACE_TYPE)
262
 
                        return -1;
263
 
                else if (ace1->Header.AceType == E2K_ACCESS_DENIED_ACE_TYPE &&
264
 
                         ace2->Header.AceType == E2K_ACCESS_ALLOWED_ACE_TYPE)
265
 
                        return 1;
266
 
 
267
 
                /* Compare SID order */
268
 
                if (order1 < order2)
269
 
                        return -1;
270
 
                else if (order1 > order2)
271
 
                        return 1;
272
 
                else
273
 
                        return 0;
274
 
        }
275
 
}
276
 
 
277
 
static xmlNode *
278
 
find_child (xmlNode *node, const xmlChar *name)
279
 
{
280
 
        for (node = node->xmlChildrenNode; node; node = node->next) {
281
 
                if (node->name && !xmlStrcmp (node->name, name))
282
 
                        return node;
283
 
        }
284
 
        return NULL;
285
 
}
286
 
 
287
 
static void
288
 
extract_sids (E2kSecurityDescriptor *sd, xmlNodePtr node)
289
 
{
290
 
        xmlNodePtr string_sid_node, type_node, display_name_node;
291
 
        xmlChar *string_sid, *content, *display_name;
292
 
        const guint8 *bsid;
293
 
        E2kSid *sid;
294
 
        E2kSidType type;
295
 
 
296
 
        for (; node; node = node->next) {
297
 
                if (xmlStrcmp (node->name, (xmlChar *) "sid") != 0) {
298
 
                        if (node->xmlChildrenNode)
299
 
                                extract_sids (sd, node->xmlChildrenNode);
300
 
                        continue;
301
 
                }
302
 
 
303
 
                string_sid_node = find_child (node, (xmlChar *) "string_sid");
304
 
                type_node = find_child (node, (xmlChar *) "type");
305
 
                display_name_node = find_child (node, (xmlChar *) "display_name");
306
 
                if (!string_sid_node || !type_node)
307
 
                        continue;
308
 
 
309
 
                string_sid = xmlNodeGetContent (string_sid_node);
310
 
 
311
 
                content = xmlNodeGetContent (type_node);
312
 
                if (!content || !xmlStrcmp (content, (xmlChar *) "user"))
313
 
                        type = E2K_SID_TYPE_USER;
314
 
                else if (!xmlStrcmp (content, (xmlChar *) "group"))
315
 
                        type = E2K_SID_TYPE_GROUP;
316
 
                else if (!xmlStrcmp (content, (xmlChar *) "well_known_group"))
317
 
                        type = E2K_SID_TYPE_WELL_KNOWN_GROUP;
318
 
                else if (!xmlStrcmp (content, (xmlChar *) "alias"))
319
 
                        type = E2K_SID_TYPE_ALIAS;
320
 
                else
321
 
                        type = E2K_SID_TYPE_INVALID;
322
 
                xmlFree (content);
323
 
 
324
 
                if (display_name_node)
325
 
                        display_name = xmlNodeGetContent (display_name_node);
326
 
                else
327
 
                        display_name = NULL;
328
 
 
329
 
                sid = e2k_sid_new_from_string_sid (type, (gchar *) string_sid,
330
 
                                                   (gchar *) display_name);
331
 
                xmlFree (string_sid);
332
 
                if (display_name)
333
 
                        xmlFree (display_name);
334
 
 
335
 
                bsid = e2k_sid_get_binary_sid (sid);
336
 
                if (g_hash_table_lookup (sd->priv->sids, bsid)) {
337
 
                        g_object_unref (sid);
338
 
                        continue;
339
 
                }
340
 
 
341
 
                g_hash_table_insert (sd->priv->sids, (gchar *)bsid, sid);
342
 
        }
343
 
}
344
 
 
345
 
static gboolean
346
 
parse_sid (E2kSecurityDescriptor *sd, GByteArray *binsd, guint16 *off,
347
 
           E2kSid **sid)
348
 
{
349
 
        gint sid_len;
350
 
 
351
 
        if (binsd->len - *off < E2K_SID_BINARY_SID_MIN_LEN)
352
 
                return FALSE;
353
 
        sid_len = E2K_SID_BINARY_SID_LEN (binsd->data + *off);
354
 
        if (binsd->len - *off < sid_len)
355
 
                return FALSE;
356
 
 
357
 
        *sid = g_hash_table_lookup (sd->priv->sids, binsd->data + *off);
358
 
        *off += sid_len;
359
 
 
360
 
        return *sid != NULL;
361
 
}
362
 
 
363
 
static gboolean
364
 
parse_acl (E2kSecurityDescriptor *sd, GByteArray *binsd, guint16 *off)
365
 
{
366
 
        E2k_ACL aclbuf;
367
 
        E2k_ACE acebuf;
368
 
        gint ace_count, i;
369
 
 
370
 
        if (binsd->len - *off < sizeof (E2k_ACL))
371
 
                return FALSE;
372
 
 
373
 
        memcpy (&aclbuf, binsd->data + *off, sizeof (aclbuf));
374
 
        if (*off + GUINT16_FROM_LE (aclbuf.AclSize) > binsd->len)
375
 
                return FALSE;
376
 
        if (aclbuf.AclRevision != E2K_ACL_REVISION)
377
 
                return FALSE;
378
 
 
379
 
        ace_count = GUINT16_FROM_LE (aclbuf.AceCount);
380
 
 
381
 
        *off += sizeof (aclbuf);
382
 
        for (i = 0; i < ace_count; i++) {
383
 
                if (binsd->len - *off < sizeof (E2k_ACE))
384
 
                        return FALSE;
385
 
 
386
 
                memcpy (&acebuf, binsd->data + *off,
387
 
                        sizeof (acebuf.Header) + sizeof (acebuf.Mask));
388
 
                *off += sizeof (acebuf.Header) + sizeof (acebuf.Mask);
389
 
 
390
 
                /* If either of OBJECT_INHERIT_ACE or INHERIT_ONLY_ACE
391
 
                 * is set, both must be.
392
 
                 */
393
 
                if (acebuf.Header.AceFlags & E2K_OBJECT_INHERIT_ACE) {
394
 
                        if (!(acebuf.Header.AceFlags & E2K_INHERIT_ONLY_ACE))
395
 
                                return FALSE;
396
 
                } else {
397
 
                        if (acebuf.Header.AceFlags & E2K_INHERIT_ONLY_ACE)
398
 
                                return FALSE;
399
 
                }
400
 
 
401
 
                if (!parse_sid (sd, binsd, off, &acebuf.Sid))
402
 
                        return FALSE;
403
 
 
404
 
                if (!g_hash_table_lookup (sd->priv->sid_order, acebuf.Sid)) {
405
 
                        gint size = g_hash_table_size (sd->priv->sid_order);
406
 
 
407
 
                        g_hash_table_insert (sd->priv->sid_order, acebuf.Sid,
408
 
                                             GUINT_TO_POINTER (size + 1));
409
 
                }
410
 
 
411
 
                g_array_append_val (sd->priv->aces, acebuf);
412
 
        }
413
 
 
414
 
        return TRUE;
415
 
}
416
 
 
417
 
/**
418
 
 * e2k_security_descriptor_new:
419
 
 * @xml_form: the XML form of the folder's security descriptor
420
 
 * (The "http://schemas.microsoft.com/exchange/security/descriptor"
421
 
 * property, aka %E2K_PR_EXCHANGE_SD_XML)
422
 
 * @binary_form: the binary form of the folder's security descriptor
423
 
 * (The "http://schemas.microsoft.com/exchange/ntsecuritydescriptor"
424
 
 * property, aka %E2K_PR_EXCHANGE_SD_BINARY)
425
 
 *
426
 
 * Constructs an #E2kSecurityDescriptor from the data in @xml_form and
427
 
 * @binary_form.
428
 
 *
429
 
 * Return value: the security descriptor, or %NULL if the data could
430
 
 * not be parsed.
431
 
 **/
432
 
E2kSecurityDescriptor *
433
 
e2k_security_descriptor_new (xmlNodePtr xml_form, GByteArray *binary_form)
434
 
{
435
 
        E2kSecurityDescriptor *sd;
436
 
        E2k_SECURITY_DESCRIPTOR_RELATIVE sdbuf;
437
 
        guint16 off, header_len;
438
 
 
439
 
        g_return_val_if_fail (xml_form != NULL, NULL);
440
 
        g_return_val_if_fail (binary_form != NULL, NULL);
441
 
 
442
 
        if (binary_form->len < 2)
443
 
                return NULL;
444
 
 
445
 
        memcpy (&header_len, binary_form->data, 2);
446
 
        header_len = GUINT16_FROM_LE (header_len);
447
 
        if (header_len + sizeof (sdbuf) > binary_form->len)
448
 
                return NULL;
449
 
 
450
 
        memcpy (&sdbuf, binary_form->data + header_len, sizeof (sdbuf));
451
 
        if (sdbuf.Revision != E2K_SECURITY_DESCRIPTOR_REVISION)
452
 
                return NULL;
453
 
        if ((sdbuf.Control & (E2K_SE_DACL_PRESENT | E2K_SE_SACL_PRESENT)) !=
454
 
            E2K_SE_DACL_PRESENT)
455
 
                return NULL;
456
 
 
457
 
        sd = g_object_new (E2K_TYPE_SECURITY_DESCRIPTOR, NULL);
458
 
        sd->priv->header = g_byte_array_new ();
459
 
        g_byte_array_append (sd->priv->header, binary_form->data, header_len);
460
 
        sd->priv->control_flags = sdbuf.Control;
461
 
 
462
 
        /* Create a SID for "Default" then extract remaining SIDs from
463
 
         * the XML form since they have display names associated with
464
 
         * them.
465
 
         */
466
 
        sd->priv->default_sid =
467
 
                e2k_sid_new_from_string_sid (E2K_SID_TYPE_WELL_KNOWN_GROUP,
468
 
                                             E2K_SID_WKS_EVERYONE, NULL);
469
 
        g_hash_table_insert (sd->priv->sids,
470
 
                             (gchar *)e2k_sid_get_binary_sid (sd->priv->default_sid),
471
 
                             sd->priv->default_sid);
472
 
        extract_sids (sd, xml_form);
473
 
 
474
 
        off = GUINT32_FROM_LE (sdbuf.Owner) + sd->priv->header->len;
475
 
        if (!parse_sid (sd, binary_form, &off, &sd->priv->owner))
476
 
                goto lose;
477
 
        off = GUINT32_FROM_LE (sdbuf.Group) + sd->priv->header->len;
478
 
        if (!parse_sid (sd, binary_form, &off, &sd->priv->group))
479
 
                goto lose;
480
 
 
481
 
        off = GUINT32_FROM_LE (sdbuf.Dacl) + sd->priv->header->len;
482
 
        if (!parse_acl (sd, binary_form, &off))
483
 
                goto lose;
484
 
 
485
 
        return sd;
486
 
 
487
 
 lose:
488
 
        g_object_unref (sd);
489
 
        return NULL;
490
 
}
491
 
 
492
 
/**
493
 
 * e2k_security_descriptor_to_binary:
494
 
 * @sd: an #E2kSecurityDescriptor
495
 
 *
496
 
 * Converts @sd back to binary (#E2K_PR_EXCHANGE_SD_BINARY) form
497
 
 * so it can be PROPPATCHed back to the server.
498
 
 *
499
 
 * Return value: the binary form of @sd.
500
 
 **/
501
 
GByteArray *
502
 
e2k_security_descriptor_to_binary (E2kSecurityDescriptor *sd)
503
 
{
504
 
        GByteArray *binsd;
505
 
        E2k_SECURITY_DESCRIPTOR_RELATIVE sdbuf;
506
 
        E2k_ACL aclbuf;
507
 
        E2k_ACE *aces;
508
 
        gint off, ace, last_ace = -1, acl_size, ace_count;
509
 
        const guint8 *bsid;
510
 
 
511
 
        g_return_val_if_fail (E2K_IS_SECURITY_DESCRIPTOR (sd), NULL);
512
 
 
513
 
        aces = (E2k_ACE *)sd->priv->aces->data;
514
 
 
515
 
        /* Compute the length of the ACL first */
516
 
        acl_size = sizeof (E2k_ACL);
517
 
        for (ace = ace_count = 0; ace < sd->priv->aces->len; ace++) {
518
 
                if (aces[ace].Mask) {
519
 
                        ace_count++;
520
 
                        acl_size += GUINT16_FROM_LE (aces[ace].Header.AceSize);
521
 
                }
522
 
        }
523
 
 
524
 
        binsd = g_byte_array_new ();
525
 
 
526
 
        /* Exchange-specific header */
527
 
        g_byte_array_append (binsd, sd->priv->header->data,
528
 
                             sd->priv->header->len);
529
 
 
530
 
        /* SECURITY_DESCRIPTOR header */
531
 
        memset (&sdbuf, 0, sizeof (sdbuf));
532
 
        sdbuf.Revision = E2K_SECURITY_DESCRIPTOR_REVISION;
533
 
        sdbuf.Control = sd->priv->control_flags;
534
 
        off = sizeof (sdbuf);
535
 
        sdbuf.Dacl = GUINT32_TO_LE (off);
536
 
        off += acl_size;
537
 
        sdbuf.Owner = GUINT32_TO_LE (off);
538
 
        bsid = e2k_sid_get_binary_sid (sd->priv->owner);
539
 
        off += E2K_SID_BINARY_SID_LEN (bsid);
540
 
        sdbuf.Group = GUINT32_TO_LE (off);
541
 
        g_byte_array_append (binsd, (gpointer)&sdbuf, sizeof (sdbuf));
542
 
 
543
 
        /* ACL header */
544
 
        aclbuf.AclRevision = E2K_ACL_REVISION;
545
 
        aclbuf.Sbz1        = 0;
546
 
        aclbuf.AclSize     = GUINT16_TO_LE (acl_size);
547
 
        aclbuf.AceCount    = GUINT16_TO_LE (ace_count);
548
 
        aclbuf.Sbz2        = 0;
549
 
        g_byte_array_append (binsd, (gpointer)&aclbuf, sizeof (aclbuf));
550
 
 
551
 
        /* ACEs */
552
 
        for (ace = 0; ace < sd->priv->aces->len; ace++) {
553
 
                if (!aces[ace].Mask)
554
 
                        continue;
555
 
 
556
 
                if (last_ace != -1) {
557
 
                        if (ace_compar (&aces[last_ace], &aces[ace], sd) != -1) {
558
 
                                g_warning ("ACE order mismatch at %d\n", ace);
559
 
                                g_byte_array_free (binsd, TRUE);
560
 
                                return NULL;
561
 
                        }
562
 
                }
563
 
 
564
 
                g_byte_array_append (binsd, (gpointer)&aces[ace],
565
 
                                     sizeof (aces[ace].Header) +
566
 
                                     sizeof (aces[ace].Mask));
567
 
                bsid = e2k_sid_get_binary_sid (aces[ace].Sid);
568
 
                g_byte_array_append (binsd, bsid,
569
 
                                     E2K_SID_BINARY_SID_LEN (bsid));
570
 
                last_ace = ace;
571
 
        }
572
 
 
573
 
        /* Owner and Group */
574
 
        bsid = e2k_sid_get_binary_sid (sd->priv->owner);
575
 
        g_byte_array_append (binsd, bsid, E2K_SID_BINARY_SID_LEN (bsid));
576
 
        bsid = e2k_sid_get_binary_sid (sd->priv->group);
577
 
        g_byte_array_append (binsd, bsid, E2K_SID_BINARY_SID_LEN (bsid));
578
 
 
579
 
        return binsd;
580
 
}
581
 
 
582
 
/**
583
 
 * e2k_security_descriptor_get_default:
584
 
 * @sd: a security descriptor
585
 
 *
586
 
 * Returns an #E2kSid corresponding to the default permissions
587
 
 * associated with @sd. You can pass this to
588
 
 * e2k_security_descriptor_get_permissions() and
589
 
 * e2k_security_descriptor_set_permissions().
590
 
 *
591
 
 * Return value: the "Default" SID
592
 
 **/
593
 
E2kSid *
594
 
e2k_security_descriptor_get_default (E2kSecurityDescriptor *sd)
595
 
{
596
 
        return sd->priv->default_sid;
597
 
}
598
 
 
599
 
/**
600
 
 * e2k_security_descriptor_get_sids:
601
 
 * @sd: a security descriptor
602
 
 *
603
 
 * Returns a #GList containing the SIDs of each user or group
604
 
 * represented in @sd. You can pass these SIDs to
605
 
 * e2k_security_descriptor_get_permissions(),
606
 
 * e2k_security_descriptor_set_permissions(), and
607
 
 * e2k_security_descriptor_remove_sid().
608
 
 *
609
 
 * Return value: a list of SIDs. The caller must free the list
610
 
 * with g_list_free(), but should not free the contents.
611
 
 **/
612
 
GList *
613
 
e2k_security_descriptor_get_sids (E2kSecurityDescriptor *sd)
614
 
{
615
 
        GList *sids = NULL;
616
 
        GHashTable *added_sids;
617
 
        E2k_ACE *aces;
618
 
        gint ace;
619
 
 
620
 
        g_return_val_if_fail (E2K_IS_SECURITY_DESCRIPTOR (sd), NULL);
621
 
 
622
 
        added_sids = g_hash_table_new (NULL, NULL);
623
 
        aces = (E2k_ACE *)sd->priv->aces->data;
624
 
        for (ace = 0; ace < sd->priv->aces->len; ace++) {
625
 
                if (!g_hash_table_lookup (added_sids, aces[ace].Sid)) {
626
 
                        g_hash_table_insert (added_sids, aces[ace].Sid,
627
 
                                             aces[ace].Sid);
628
 
                        sids = g_list_prepend (sids, aces[ace].Sid);
629
 
                }
630
 
        }
631
 
        g_hash_table_destroy (added_sids);
632
 
 
633
 
        return sids;
634
 
}
635
 
 
636
 
/**
637
 
 * e2k_security_descriptor_remove_sid:
638
 
 * @sd: a security descriptor
639
 
 * @sid: a SID
640
 
 *
641
 
 * Removes @sid from @sd. If @sid is a user, this means s/he will now
642
 
 * have only the default permissions on @sd (unless s/he is a member
643
 
 * of a group that is also present in @sd.)
644
 
 **/
645
 
void
646
 
e2k_security_descriptor_remove_sid (E2kSecurityDescriptor *sd,
647
 
                                    E2kSid *sid)
648
 
{
649
 
        E2k_ACE *aces;
650
 
        gint ace;
651
 
 
652
 
        g_return_if_fail (E2K_IS_SECURITY_DESCRIPTOR (sd));
653
 
        g_return_if_fail (E2K_IS_SID (sid));
654
 
 
655
 
        /* Canonicalize the SID */
656
 
        sid = g_hash_table_lookup (sd->priv->sids,
657
 
                                   e2k_sid_get_binary_sid (sid));
658
 
        if (!sid)
659
 
                return;
660
 
 
661
 
        /* We can't actually remove all trace of the user, because if
662
 
         * he is removed and then re-added without saving in between,
663
 
         * then we need to keep the original AceFlags. So we just
664
 
         * clear out all of the masks, which (assuming the user is
665
 
         * not re-added) will result in him not being written out
666
 
         * when sd is saved.
667
 
         */
668
 
 
669
 
        aces = (E2k_ACE *)sd->priv->aces->data;
670
 
        for (ace = 0; ace < sd->priv->aces->len; ace++) {
671
 
                if (aces[ace].Sid == sid)
672
 
                        aces[ace].Mask = 0;
673
 
        }
674
 
}
675
 
 
676
 
/**
677
 
 * e2k_security_descriptor_get_permissions:
678
 
 * @sd: a security descriptor
679
 
 * @sid: a SID
680
 
 *
681
 
 * Computes the MAPI permissions associated with @sid. (Only the
682
 
 * permissions *directly* associated with @sid, not any acquired via
683
 
 * group memberships or the Default SID.)
684
 
 *
685
 
 * Return value: the MAPI permissions
686
 
 **/
687
 
guint32
688
 
e2k_security_descriptor_get_permissions (E2kSecurityDescriptor *sd,
689
 
                                         E2kSid *sid)
690
 
{
691
 
        E2k_ACE *aces;
692
 
        guint32 mapi_perms, checkperm;
693
 
        gint ace, map;
694
 
 
695
 
        g_return_val_if_fail (E2K_IS_SECURITY_DESCRIPTOR (sd), 0);
696
 
        g_return_val_if_fail (E2K_IS_SID (sid), 0);
697
 
 
698
 
        /* Canonicalize the SID */
699
 
        sid = g_hash_table_lookup (sd->priv->sids,
700
 
                                   e2k_sid_get_binary_sid (sid));
701
 
        if (!sid)
702
 
                return 0;
703
 
 
704
 
        mapi_perms = 0;
705
 
        aces = (E2k_ACE *)sd->priv->aces->data;
706
 
        for (ace = 0; ace < sd->priv->aces->len; ace++) {
707
 
                if (aces[ace].Sid != sid)
708
 
                        continue;
709
 
                if (aces[ace].Header.AceType == E2K_ACCESS_DENIED_ACE_TYPE)
710
 
                        continue;
711
 
 
712
 
                for (map = 0; map < permissions_map_size; map++) {
713
 
                        if (aces[ace].Header.AceFlags & E2K_OBJECT_INHERIT_ACE)
714
 
                                checkperm = permissions_map[map].object_allowed;
715
 
                        else
716
 
                                checkperm = permissions_map[map].container_allowed;
717
 
                        if (!checkperm)
718
 
                                continue;
719
 
 
720
 
                        if ((aces[ace].Mask & checkperm) == checkperm)
721
 
                                mapi_perms |= permissions_map[map].mapi_permission;
722
 
                }
723
 
        }
724
 
 
725
 
        return mapi_perms;
726
 
}
727
 
 
728
 
/* Put @ace into @sd. If no ACE corresponding to @ace currently exists,
729
 
 * it will be added in the right place. If it does already exist, its
730
 
 * flags (in particular INHERITED_ACE) will be preserved and only the
731
 
 * mask will be changed.
732
 
 */
733
 
static void
734
 
set_ace (E2kSecurityDescriptor *sd, E2k_ACE *ace)
735
 
{
736
 
        E2k_ACE *aces = (E2k_ACE *)sd->priv->aces->data;
737
 
        gint low, mid = 0, high, cmp = -1;
738
 
 
739
 
        low = 0;
740
 
        high = sd->priv->aces->len - 1;
741
 
        while (low <= high) {
742
 
                mid = (low + high) / 2;
743
 
                cmp = ace_compar (ace, &aces[mid], sd);
744
 
                if (cmp == 0) {
745
 
                        if (ace->Mask)
746
 
                                aces[mid].Mask = ace->Mask;
747
 
                        else
748
 
                                g_array_remove_index (sd->priv->aces, mid);
749
 
                        return;
750
 
                } else if (cmp < 0)
751
 
                        high = mid - 1;
752
 
                else
753
 
                        low = mid + 1;
754
 
        }
755
 
 
756
 
        if (ace->Mask)
757
 
                g_array_insert_vals (sd->priv->aces, cmp < 0 ? mid : mid + 1, ace, 1);
758
 
}
759
 
 
760
 
/**
761
 
 * e2k_security_descriptor_set_permissions:
762
 
 * @sd: a security descriptor
763
 
 * @sid: a SID
764
 
 * @perms: the MAPI permissions
765
 
 *
766
 
 * Updates or sets @sid's permissions on @sd.
767
 
 **/
768
 
void
769
 
e2k_security_descriptor_set_permissions (E2kSecurityDescriptor *sd,
770
 
                                         E2kSid *sid, guint32 perms)
771
 
{
772
 
        E2k_ACE ace;
773
 
        guint32 object_allowed, object_denied;
774
 
        guint32 container_allowed, container_denied;
775
 
        const guint8 *bsid;
776
 
        E2kSid *sid2;
777
 
        gint map;
778
 
 
779
 
        g_return_if_fail (E2K_IS_SECURITY_DESCRIPTOR (sd));
780
 
        g_return_if_fail (E2K_IS_SID (sid));
781
 
 
782
 
        bsid = e2k_sid_get_binary_sid (sid);
783
 
        sid2 = g_hash_table_lookup (sd->priv->sids, bsid);
784
 
        if (!sid2) {
785
 
                gint size = g_hash_table_size (sd->priv->sid_order);
786
 
 
787
 
                g_hash_table_insert (sd->priv->sids, (gchar *)bsid, sid);
788
 
                g_object_ref (sid);
789
 
 
790
 
                g_hash_table_insert (sd->priv->sid_order, sid,
791
 
                                     GUINT_TO_POINTER (size + 1));
792
 
        } else
793
 
                sid = sid2;
794
 
 
795
 
        object_allowed    = 0;
796
 
        object_denied     = object_permissions_all;
797
 
        container_allowed = 0;
798
 
        container_denied  = container_permissions_all;
799
 
 
800
 
        for (map = 0; map < permissions_map_size; map++) {
801
 
                if (!(permissions_map[map].mapi_permission & perms))
802
 
                        continue;
803
 
 
804
 
                object_allowed    |=  permissions_map[map].object_allowed;
805
 
                object_denied     &= ~permissions_map[map].object_not_denied;
806
 
                container_allowed |=  permissions_map[map].container_allowed;
807
 
                container_denied  &= ~permissions_map[map].container_not_denied;
808
 
        }
809
 
 
810
 
        ace.Sid = sid;
811
 
        ace.Header.AceSize = GUINT16_TO_LE (sizeof (ace.Header) +
812
 
                                            sizeof (ace.Mask) +
813
 
                                            E2K_SID_BINARY_SID_LEN (bsid));
814
 
 
815
 
        ace.Header.AceType  = E2K_ACCESS_ALLOWED_ACE_TYPE;
816
 
        ace.Header.AceFlags = E2K_OBJECT_INHERIT_ACE | E2K_INHERIT_ONLY_ACE;
817
 
        ace.Mask = object_allowed;
818
 
        set_ace (sd, &ace);
819
 
        if (sid != sd->priv->default_sid) {
820
 
                ace.Header.AceType  = E2K_ACCESS_DENIED_ACE_TYPE;
821
 
                ace.Header.AceFlags = E2K_OBJECT_INHERIT_ACE | E2K_INHERIT_ONLY_ACE;
822
 
                ace.Mask = object_denied;
823
 
                set_ace (sd, &ace);
824
 
        }
825
 
 
826
 
        ace.Header.AceType  = E2K_ACCESS_ALLOWED_ACE_TYPE;
827
 
        ace.Header.AceFlags = E2K_CONTAINER_INHERIT_ACE;
828
 
        ace.Mask = container_allowed;
829
 
        set_ace (sd, &ace);
830
 
        if (sid != sd->priv->default_sid) {
831
 
                ace.Header.AceType  = E2K_ACCESS_DENIED_ACE_TYPE;
832
 
                ace.Header.AceFlags = E2K_CONTAINER_INHERIT_ACE;
833
 
                ace.Mask = container_denied;
834
 
                set_ace (sd, &ace);
835
 
        }
836
 
}
837
 
 
838
 
static struct {
839
 
        const gchar *name;
840
 
        guint32 perms;
841
 
} roles[E2K_PERMISSIONS_ROLE_NUM_ROLES] = {
842
 
        /* i18n: These are Outlook's words for the default roles in
843
 
           the folder permissions dialog. */
844
 
        { N_("Owner"),             (E2K_PERMISSION_FOLDER_VISIBLE |
845
 
                                    E2K_PERMISSION_READ_ANY |
846
 
                                    E2K_PERMISSION_CREATE |
847
 
                                    E2K_PERMISSION_DELETE_OWNED |
848
 
                                    E2K_PERMISSION_EDIT_OWNED |
849
 
                                    E2K_PERMISSION_DELETE_ANY |
850
 
                                    E2K_PERMISSION_EDIT_ANY |
851
 
                                    E2K_PERMISSION_CREATE_SUBFOLDER |
852
 
                                    E2K_PERMISSION_CONTACT |
853
 
                                    E2K_PERMISSION_OWNER) },
854
 
        { N_("Publishing Editor"), (E2K_PERMISSION_FOLDER_VISIBLE |
855
 
                                    E2K_PERMISSION_READ_ANY |
856
 
                                    E2K_PERMISSION_CREATE |
857
 
                                    E2K_PERMISSION_DELETE_OWNED |
858
 
                                    E2K_PERMISSION_EDIT_OWNED |
859
 
                                    E2K_PERMISSION_DELETE_ANY |
860
 
                                    E2K_PERMISSION_EDIT_ANY |
861
 
                                    E2K_PERMISSION_CREATE_SUBFOLDER) },
862
 
        { N_("Editor"),            (E2K_PERMISSION_FOLDER_VISIBLE |
863
 
                                    E2K_PERMISSION_READ_ANY |
864
 
                                    E2K_PERMISSION_CREATE |
865
 
                                    E2K_PERMISSION_DELETE_OWNED |
866
 
                                    E2K_PERMISSION_EDIT_OWNED |
867
 
                                    E2K_PERMISSION_DELETE_ANY |
868
 
                                    E2K_PERMISSION_EDIT_ANY) },
869
 
        { N_("Publishing Author"), (E2K_PERMISSION_FOLDER_VISIBLE |
870
 
                                    E2K_PERMISSION_READ_ANY |
871
 
                                    E2K_PERMISSION_CREATE |
872
 
                                    E2K_PERMISSION_DELETE_OWNED |
873
 
                                    E2K_PERMISSION_EDIT_OWNED |
874
 
                                    E2K_PERMISSION_CREATE_SUBFOLDER) },
875
 
        { N_("Author"),            (E2K_PERMISSION_FOLDER_VISIBLE |
876
 
                                    E2K_PERMISSION_READ_ANY |
877
 
                                    E2K_PERMISSION_CREATE |
878
 
                                    E2K_PERMISSION_DELETE_OWNED |
879
 
                                    E2K_PERMISSION_EDIT_OWNED) },
880
 
        { N_("Non-editing Author"),(E2K_PERMISSION_FOLDER_VISIBLE |
881
 
                                    E2K_PERMISSION_READ_ANY |
882
 
                                    E2K_PERMISSION_CREATE |
883
 
                                    E2K_PERMISSION_DELETE_OWNED) },
884
 
        { N_("Reviewer"),          (E2K_PERMISSION_FOLDER_VISIBLE |
885
 
                                    E2K_PERMISSION_READ_ANY) },
886
 
        { N_("Contributor"),       (E2K_PERMISSION_FOLDER_VISIBLE |
887
 
                                    E2K_PERMISSION_CREATE) },
888
 
        { N_("None"),              (E2K_PERMISSION_FOLDER_VISIBLE) }
889
 
};
890
 
 
891
 
/**
892
 
 * e2k_permissions_role_get_name:
893
 
 * @role: a permissions role
894
 
 *
895
 
 * Returns the localized name corresponding to @role
896
 
 *
897
 
 * Return value: the name
898
 
 **/
899
 
const gchar *
900
 
e2k_permissions_role_get_name (E2kPermissionsRole role)
901
 
{
902
 
        if (role == E2K_PERMISSIONS_ROLE_CUSTOM)
903
 
                return _("Custom");
904
 
 
905
 
        g_return_val_if_fail (role > E2K_PERMISSIONS_ROLE_CUSTOM &&
906
 
                              role < E2K_PERMISSIONS_ROLE_NUM_ROLES, NULL);
907
 
        return _(roles[role].name);
908
 
}
909
 
 
910
 
/**
911
 
 * e2k_permissions_role_get_perms
912
 
 * @role: a permissions role
913
 
 *
914
 
 * Returns the MAPI permissions associated with @role. @role may not
915
 
 * be %E2K_PERMISSIONS_ROLE_CUSTOM.
916
 
 *
917
 
 * Return value: the MAPI permissions
918
 
 **/
919
 
guint32
920
 
e2k_permissions_role_get_perms (E2kPermissionsRole role)
921
 
{
922
 
        g_return_val_if_fail (role >= E2K_PERMISSIONS_ROLE_CUSTOM &&
923
 
                              role < E2K_PERMISSIONS_ROLE_NUM_ROLES, 0);
924
 
        return roles[role].perms;
925
 
}
926
 
 
927
 
/**
928
 
 * e2k_permissions_role_find:
929
 
 * @perms: MAPI permissions
930
 
 *
931
 
 * Finds the #E2kPermissionsRole value associated with @perms. If
932
 
 * @perms don't describe any standard role, the return value will be
933
 
 * %E2K_PERMISSIONS_ROLE_CUSTOM
934
 
 *
935
 
 * Return value: the role
936
 
 **/
937
 
E2kPermissionsRole
938
 
e2k_permissions_role_find (guint perms)
939
 
{
940
 
        gint role;
941
 
 
942
 
        /* "Folder contact" isn't actually a permission, and is ignored
943
 
         * for purposes of roles.
944
 
         */
945
 
        perms &= ~E2K_PERMISSION_CONTACT;
946
 
 
947
 
        /* The standard "None" permission includes "Folder visible",
948
 
         * but 0 counts as "None" too.
949
 
         */
950
 
        if (perms == 0)
951
 
                return E2K_PERMISSIONS_ROLE_NONE;
952
 
 
953
 
        for (role = 0; role < E2K_PERMISSIONS_ROLE_NUM_ROLES; role++) {
954
 
                if ((roles[role].perms & ~E2K_PERMISSION_CONTACT) == perms)
955
 
                        return role;
956
 
        }
957
 
 
958
 
        return E2K_PERMISSIONS_ROLE_CUSTOM;
959
 
}