Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / servers / exchange / lib / e2k-sid.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3 /* Copyright (C) 2002-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-sid.h"
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <glib.h>
29 #include <libxml/xmlmemory.h>
30
31 typedef struct {
32         guint8  Revision;
33         guint8  SubAuthorityCount;
34         guint8  zero_pad[5];
35         guint8  IdentifierAuthority;
36         guint32 SubAuthority[1];
37 } E2kSid_SID;
38 #define E2K_SID_SID_REVISION 1
39
40 struct _E2kSidPrivate {
41         E2kSidType type;
42         E2kSid_SID *binary_sid;
43         char *string_sid;
44         char *display_name;
45 };
46
47 #define PARENT_TYPE G_TYPE_OBJECT
48 static GObjectClass *parent_class = NULL;
49
50 static void dispose (GObject *object);
51
52 static void
53 class_init (GObjectClass *object_class)
54 {
55         parent_class = g_type_class_ref (PARENT_TYPE);
56
57         object_class->dispose = dispose;
58 }
59
60 static void
61 init (GObject *object)
62 {
63         E2kSid *sid = E2K_SID (object);
64
65         sid->priv = g_new0 (E2kSidPrivate, 1);
66 }
67
68 static void
69 dispose (GObject *object)
70 {
71         E2kSid *sid = E2K_SID (object);
72
73         if (sid->priv) {
74                 if (sid->priv->string_sid)
75                         g_free (sid->priv->string_sid);
76                 if (sid->priv->binary_sid)
77                         g_free (sid->priv->binary_sid);
78                 g_free (sid->priv->display_name);
79
80                 g_free (sid->priv);
81                 sid->priv = NULL;
82         }
83
84         G_OBJECT_CLASS (parent_class)->dispose (object);
85 }
86
87 E2K_MAKE_TYPE (e2k_sid, E2kSid, class_init, init, PARENT_TYPE)
88
89 static E2kSid *
90 sid_new_internal (E2kSidType type, const char *display_name,
91                   const char *string_sid, const guint8 *binary_sid)
92 {
93         E2kSid *sid;
94
95         sid = g_object_new (E2K_TYPE_SID, NULL);
96         sid->priv->type = type;
97
98         if (binary_sid)
99                 sid->priv->binary_sid = g_memdup (binary_sid, E2K_SID_BINARY_SID_LEN (binary_sid));
100         if (string_sid)
101                 sid->priv->string_sid = g_strdup (string_sid);
102         else if (!display_name)
103                 e2k_sid_get_string_sid (sid);
104
105         if (!display_name) {
106                 if (type == E2K_SID_TYPE_WELL_KNOWN_GROUP) {
107                         if (!strcmp (string_sid, E2K_SID_WKS_ANONYMOUS))
108                                 display_name = _(E2K_SID_WKS_ANONYMOUS_NAME);
109                         else if (!strcmp (string_sid, E2K_SID_WKS_EVERYONE))
110                                 display_name = _(E2K_SID_WKS_EVERYONE_NAME);
111                 }
112                 if (!display_name)
113                         display_name = string_sid;
114         }
115         sid->priv->display_name = g_strdup (display_name);
116
117         return sid;
118 }
119
120 /**
121  * e2k_sid_new_from_string_sid:
122  * @type: the type of SID that @string_sid is
123  * @string_sid: the string form of a Windows Security Identifier
124  * @display_name: UTF-8 display name of the user/group/etc identified
125  * by @string_sid
126  *
127  * Creates an %E2kSid from the given information
128  *
129  * Return value: the new SID
130  **/
131 E2kSid *
132 e2k_sid_new_from_string_sid (E2kSidType type, const char *string_sid,
133                              const char *display_name)
134 {
135         g_return_val_if_fail (string_sid != NULL, NULL);
136
137         if (strlen (string_sid) < 6 || strncmp (string_sid, "S-1-", 4) != 0)
138                 return NULL;
139
140         return sid_new_internal (type, display_name, string_sid, NULL);
141 }
142
143 /**
144  * e2k_sid_new_from_binary_sid:
145  * @type: the type of SID that @binary_sid is
146  * @binary_sid: the binary form of a Windows Security Identifier
147  * @display_name: UTF-8 display name of the user/group/etc identified
148  * by @string_sid
149  *
150  * Creates an %E2kSid from the given information
151  *
152  * Return value: the new SID
153  **/
154 E2kSid *
155 e2k_sid_new_from_binary_sid (E2kSidType    type,
156                              const guint8 *binary_sid,
157                              const char   *display_name)
158 {
159         g_return_val_if_fail (binary_sid != NULL, NULL);
160
161         return sid_new_internal (type, display_name, NULL, binary_sid);
162 }
163
164 /**
165  * e2k_sid_get_sid_type:
166  * @sid: a SID
167  *
168  * Returns the type of @sid (user, group, etc)
169  *
170  * Return value: the %E2kSidType
171  **/
172 E2kSidType
173 e2k_sid_get_sid_type (E2kSid *sid)
174 {
175         g_return_val_if_fail (E2K_IS_SID (sid), E2K_SID_TYPE_USER);
176
177         return sid->priv->type;
178 }
179
180 /**
181  * e2k_sid_get_string_sid:
182  * @sid: a SID
183  *
184  * Returns the string form of @sid
185  *
186  * Return value: the string SID
187  **/
188 const char *
189 e2k_sid_get_string_sid (E2kSid *sid)
190 {
191         g_return_val_if_fail (E2K_IS_SID (sid), NULL);
192
193         if (!sid->priv->string_sid) {
194                 GString *string;
195                 int sa;
196
197                 string = g_string_new (NULL);
198
199                 /* Revision and IdentifierAuthority. */
200                 g_string_append_printf (string, "S-%u-%u",
201                                         sid->priv->binary_sid->Revision,
202                                         sid->priv->binary_sid->IdentifierAuthority);
203
204                 /* Subauthorities. */
205                 for (sa = 0; sa < sid->priv->binary_sid->SubAuthorityCount; sa++) {
206                         g_string_append_printf (string, "-%lu",
207                                                 (unsigned long) GUINT32_FROM_LE (sid->priv->binary_sid->SubAuthority[sa]));
208                 }
209
210                 sid->priv->string_sid = string->str;
211                 g_string_free (string, FALSE);
212         }
213
214         return sid->priv->string_sid;
215 }
216
217 /**
218  * e2k_sid_get_binary_sid:
219  * @sid: a SID
220  *
221  * Returns the binary form of @sid. Since the SID data is self-delimiting,
222  * no length value is needed. Use E2K_SID_BINARY_SID_LEN() if you need to
223  * know the size of the binary data.
224  *
225  * Return value: the binary SID
226  **/
227 const guint8 *
228 e2k_sid_get_binary_sid (E2kSid *sid)
229 {
230         g_return_val_if_fail (E2K_IS_SID (sid), NULL);
231
232         if (!sid->priv->binary_sid) {
233                 int sa, subauth_count;
234                 guint32 subauthority;
235                 char *p;
236
237                 p = sid->priv->string_sid + 4;
238                 subauth_count = 0;
239                 while ((p = strchr (p, '-'))) {
240                         subauth_count++;
241                         p++;
242                 }
243
244                 sid->priv->binary_sid = g_malloc0 (sizeof (E2kSid_SID) + 4 * (subauth_count - 1));
245                 sid->priv->binary_sid->Revision = E2K_SID_SID_REVISION;
246                 sid->priv->binary_sid->IdentifierAuthority = strtoul (sid->priv->string_sid + 4, &p, 10);
247                 sid->priv->binary_sid->SubAuthorityCount = subauth_count;
248
249                 sa = 0;
250                 while (*p == '-' && sa < subauth_count) {
251                         subauthority = strtoul (p + 1, &p, 10);
252                         sid->priv->binary_sid->SubAuthority[sa++] =
253                                 GUINT32_TO_LE (subauthority);
254                 }
255         }
256
257         return (guint8 *)sid->priv->binary_sid;
258 }
259
260 /**
261  * e2k_sid_get_display_name:
262  * @sid: a SID
263  *
264  * Returns the display name of the entity identified by @sid
265  *
266  * Return value: the UTF-8 display name
267  **/
268 const char *
269 e2k_sid_get_display_name (E2kSid *sid)
270 {
271         g_return_val_if_fail (E2K_IS_SID (sid), NULL);
272
273         return sid->priv->display_name;
274 }
275
276
277 /**
278  * e2k_sid_binary_sid_equal:
279  * @a: pointer to a binary SID
280  * @b: pointer to another binary SID
281  *
282  * Determines if @a and @b contain the same SID data. For use
283  * with #GHashTable.
284  *
285  * Return value: %TRUE or %FALSE
286  **/
287 gint
288 e2k_sid_binary_sid_equal (gconstpointer a, gconstpointer b)
289 {
290         const guint8 *bsida = (const guint8 *)a;
291         const guint8 *bsidb = (const guint8 *)b;
292
293         if (E2K_SID_BINARY_SID_LEN (bsida) !=
294             E2K_SID_BINARY_SID_LEN (bsidb))
295                 return FALSE;
296         return memcmp (bsida, bsidb, E2K_SID_BINARY_SID_LEN (bsida)) == 0;
297 }
298
299 /**
300  * e2k_sid_binary_sid_hash:
301  * @key: pointer to a binary SID
302  *
303  * Hashes @key, a binary SID. For use with #GHashTable.
304  *
305  * Return value: the hash value
306  **/
307 guint
308 e2k_sid_binary_sid_hash (gconstpointer key)
309 {
310         const guint8 *bsid = (const guint8 *)key;
311         guint32 final_sa;
312
313         /* The majority of SIDs will differ only in the last
314          * subauthority value.
315          */
316         memcpy (&final_sa, bsid + E2K_SID_BINARY_SID_LEN (bsid) - 4, 4);
317         return final_sa;
318 }