fe88dbf95215ad11c9da4caf94073e07a06e8a5a
[jelmer/openchange.git] / mapiproxy / libmapistore / mapistore_namedprops.c
1 /*
2    OpenChange Storage Abstraction Layer library
3
4    OpenChange Project
5
6    Copyright (C) Julien Kerihuel 2010
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include "mapistore.h"
23 #include "mapistore_errors.h"
24 #include "mapistore_private.h"
25 #include "libmapi/libmapi_private.h"
26 #include <ldb.h>
27
28 #include <sys/stat.h>
29
30 static struct MAPINAMEID        **nameids_cache = NULL;
31
32 static const char *mapistore_namedprops_get_ldif_path(void)
33 {
34         return MAPISTORE_LDIF;
35 }
36
37 /**
38    \details Initialize the named properties database or return pointer
39    to the existing one if already initialized/opened.
40
41    \param mem_ctx pointer to the memory context
42    \param ldb_ctx pointer on pointer to the ldb context the function
43    returns
44
45    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
46  */
47 enum mapistore_error mapistore_namedprops_init(TALLOC_CTX *mem_ctx, struct ldb_context **_ldb_ctx)
48 {
49         int                     ret;
50         struct stat             sb;
51         struct ldb_context      *ldb_ctx = NULL;
52         struct ldb_ldif         *ldif;
53         char                    *filename;
54         FILE                    *f;
55         struct tevent_context   *ev;
56         char                    *database;
57
58         /* Sanity checks */
59         MAPISTORE_RETVAL_IF(!mem_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
60         MAPISTORE_RETVAL_IF(!_ldb_ctx, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
61
62         ev = tevent_context_init(mem_ctx);
63         MAPISTORE_RETVAL_IF(!ev, MAPISTORE_ERR_NO_MEMORY, NULL);
64
65         database = talloc_asprintf(mem_ctx, "%s/%s", mapistore_get_mapping_path(), MAPISTORE_DB_NAMED);
66         DEBUG(0, ("database = %s\n", database));
67
68         /* Step 1. Stat the database and populate it if it doesn't exist */
69         if (stat(database, &sb) == -1) {
70                 ldb_ctx = mapistore_ldb_wrap_connect(ldb_ctx, ev, database, 0);
71                 talloc_free(database);
72                 MAPISTORE_RETVAL_IF(!ldb_ctx, MAPISTORE_ERR_DATABASE_INIT, NULL);
73
74                 filename = talloc_asprintf(mem_ctx, "%s/mapistore_namedprops.ldif", 
75                                            mapistore_namedprops_get_ldif_path());
76                 f = fopen(filename, "r");
77                 talloc_free(filename);
78                 MAPISTORE_RETVAL_IF(!f, MAPISTORE_ERROR, NULL);
79                 
80                 ldb_transaction_start(ldb_ctx);
81
82                 while ((ldif = ldb_ldif_read_file(ldb_ctx, f))) {
83                         struct ldb_message *normalized_msg;
84                         ret = ldb_msg_normalize(ldb_ctx, mem_ctx, ldif->msg, &normalized_msg);
85                         MAPISTORE_RETVAL_IF(ret, MAPISTORE_ERR_DATABASE_INIT, NULL);
86                         ret = ldb_add(ldb_ctx, normalized_msg);
87                         talloc_free(normalized_msg);
88                         if (ret != LDB_SUCCESS) {
89                                 fclose(f);
90                                 MAPISTORE_RETVAL_IF(ret, MAPISTORE_ERR_DATABASE_INIT, NULL);
91                         }
92                         ldb_ldif_read_free(ldb_ctx, ldif);
93                 }
94
95                 ldb_transaction_commit(ldb_ctx);
96                 fclose(f);
97
98         } else {
99                 ldb_ctx = mapistore_ldb_wrap_connect(ldb_ctx, ev, database, 0);
100                 talloc_free(database);
101                 MAPISTORE_RETVAL_IF(!ldb_ctx, MAPISTORE_ERR_DATABASE_INIT, NULL);
102         }
103
104         *_ldb_ctx = ldb_ctx;
105
106         return MAPISTORE_SUCCESS;
107 }
108
109
110 /**
111    \details return the next unmapped property ID
112
113    \param ldb_ctx pointer to the namedprops ldb context
114
115    \return 0 on error, the next mapped id otherwise
116  */
117 _PUBLIC_ uint16_t mapistore_namedprops_next_unused_id(struct ldb_context *ldb_ctx)
118 {
119         uint16_t                highest_id = 0, current_id;
120         TALLOC_CTX              *mem_ctx;
121         struct ldb_result       *res = NULL;
122         const char * const      attrs[] = { "mappedId", NULL };
123         int                     ret;
124         unsigned int            i;
125
126         mem_ctx = talloc_named(NULL, 0, "mapistore_namedprops_get_mapped_propID");
127
128         ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx),
129                          LDB_SCOPE_SUBTREE, attrs, "(cn=*)");
130         MAPISTORE_RETVAL_IF(ret != LDB_SUCCESS, 0, mem_ctx);
131
132         for (i = 0; i < res->count; i++) {
133                 current_id = ldb_msg_find_attr_as_uint(res->msgs[i], "mappedId", 0);
134                 if (current_id > 0 && highest_id < current_id) {
135                         highest_id = current_id;
136                 }
137         }
138
139         talloc_free(mem_ctx);
140
141         DEBUG(5, ("next_mapped_id: %d\n", (highest_id + 1)));
142
143         return (highest_id + 1);
144 }
145
146 /**
147    \details return the mapped property ID matching the nameid
148    structure passed in parameter.
149
150    \param ldb_ctx pointer to the namedprops ldb context
151    \param nameid the MAPINAMEID structure to lookup
152    \param propID pointer to the property ID the function returns
153
154    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR
155  */
156 _PUBLIC_ enum mapistore_error mapistore_namedprops_create_id(struct ldb_context *ldb_ctx, struct MAPINAMEID nameid, uint16_t mapped_id)
157 {
158         int ret;
159         TALLOC_CTX *mem_ctx;
160         char *ldif_record;
161         struct ldb_ldif *ldif;
162         char *hex_id, *dec_id, *dec_mappedid, *guid;
163         struct ldb_message *normalized_msg;
164         const char *ldif_records[] = { NULL, NULL };
165
166         mem_ctx = talloc_zero(NULL, TALLOC_CTX);
167
168         dec_mappedid = talloc_asprintf(mem_ctx, "%u", mapped_id);
169         guid = GUID_string(mem_ctx, &nameid.lpguid);
170         switch (nameid.ulKind) {
171         case MNID_ID:
172                 hex_id = talloc_asprintf(mem_ctx, "%.4x", nameid.kind.lid);
173                 dec_id = talloc_asprintf(mem_ctx, "%u", nameid.kind.lid);
174                 ldif_record = talloc_asprintf(mem_ctx, "dn: CN=0x%s,CN=%s,CN=default\nobjectClass: MNID_ID\ncn: 0x%s\npropType: PT_NULL\noleguid: %s\nmappedId: %s\npropId: %s\n",
175                                               hex_id, guid, hex_id, guid, dec_mappedid, dec_id);
176                 break;
177         case MNID_STRING:
178                 ldif_record = talloc_asprintf(mem_ctx, "dn: CN=%s,CN=%s,CN=default\nobjectClass: MNID_STRING\ncn: %s\npropType: PT_NULL\noleguid: %s\nmappedId: %s\npropName: %s\n",
179                                               nameid.kind.lpwstr.Name, guid, nameid.kind.lpwstr.Name, guid, dec_mappedid, nameid.kind.lpwstr.Name);
180                 break;
181         default:
182                 abort();
183         }
184
185         DEBUG(5, ("inserting record:\n%s\n", ldif_record));
186         ldif_records[0] = ldif_record;
187         ldif = ldb_ldif_read_string(ldb_ctx, ldif_records);
188         ret = ldb_msg_normalize(ldb_ctx, mem_ctx, ldif->msg, &normalized_msg);
189         MAPISTORE_RETVAL_IF(ret, MAPISTORE_ERR_DATABASE_INIT, NULL);
190         ret = ldb_add(ldb_ctx, normalized_msg);
191         talloc_free(normalized_msg);
192         if (ret != LDB_SUCCESS) {
193                 MAPISTORE_RETVAL_IF(ret, MAPISTORE_ERR_DATABASE_INIT, NULL);
194         }
195
196         /* we invalidate the cache, if present */
197         if (nameids_cache) {
198                 talloc_free(nameids_cache);
199                 nameids_cache = NULL;
200         }
201
202         return ret;
203 }
204
205 /**
206    \details return the mapped property ID matching the nameid
207    structure passed in parameter.
208
209    \param ldb_ctx pointer to the namedprops ldb context
210    \param nameid the MAPINAMEID structure to lookup
211    \param propID pointer to the property ID the function returns
212
213    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR
214  */
215 _PUBLIC_ enum mapistore_error mapistore_namedprops_get_mapped_id(struct ldb_context *ldb_ctx, struct MAPINAMEID nameid, uint16_t *propID)
216 {
217         TALLOC_CTX              *mem_ctx;
218         struct ldb_result       *res = NULL;
219         const char * const      attrs[] = { "*", NULL };
220         int                     ret;
221         char                    *filter = NULL;
222         char                    *guid;
223
224         /* Sanity checks */
225         MAPISTORE_RETVAL_IF(!ldb_ctx, MAPISTORE_ERROR, NULL);
226         MAPISTORE_RETVAL_IF(!propID, MAPISTORE_ERROR, NULL);
227
228         *propID = 0;
229         mem_ctx = talloc_named(NULL, 0, "mapistore_namedprops_get_mapped_propID");
230         guid = GUID_string(mem_ctx, (const struct GUID *)&nameid.lpguid);
231
232         switch (nameid.ulKind) {
233         case MNID_ID:
234                 filter = talloc_asprintf(mem_ctx, "(&(objectClass=MNID_ID)(oleguid=%s)(cn=0x%.4x))",
235                                          guid, nameid.kind.lid);
236                 break;
237         case MNID_STRING:
238                 filter = talloc_asprintf(mem_ctx, "(&(objectClass=MNID_STRING)(oleguid=%s)(cn=%s))",
239                                          guid, nameid.kind.lpwstr.Name);
240                 break;
241         }
242         talloc_free(guid);
243
244         ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx),
245                          LDB_SCOPE_SUBTREE, attrs, "%s", filter);
246         MAPISTORE_RETVAL_IF((ret != LDB_SUCCESS || !res->count), MAPISTORE_ERROR, mem_ctx);
247
248         *propID = ldb_msg_find_attr_as_uint(res->msgs[0], "mappedId", 0);
249         MAPISTORE_RETVAL_IF(!*propID, MAPISTORE_ERROR, mem_ctx);
250
251         talloc_free(mem_ctx);
252
253         return MAPISTORE_SUCCESS;
254 }
255
256 /**
257    \details return the nameid structture matching the mapped property ID
258    passed in parameter.
259
260    \param ldb_ctx pointer to the namedprops ldb context
261    \param propID the property ID to lookup
262    \param nameid pointer to the MAPINAMEID structure the function returns
263
264    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR
265  */
266 _PUBLIC_ enum mapistore_error mapistore_namedprops_get_nameid(struct ldb_context *ldb_ctx, 
267                                                               uint16_t propID,
268                                                               struct MAPINAMEID **nameidp)
269 {
270         TALLOC_CTX                      *mem_ctx;
271         struct ldb_result               *res = NULL;
272         const char * const              attrs[] = { "*", NULL };
273         int                             ret;
274         const char                      *guid, *oClass, *cn;
275         struct MAPINAMEID               *nameid;
276         int                             rc = MAPISTORE_SUCCESS;
277         uint16_t                        propidx;
278                                              
279         /* Sanity checks */
280         MAPISTORE_RETVAL_IF(!ldb_ctx, MAPISTORE_ERROR, NULL);
281         MAPISTORE_RETVAL_IF(!nameidp, MAPISTORE_ERROR, NULL);
282         MAPISTORE_RETVAL_IF(propID < 0x8000, MAPISTORE_ERROR, NULL);
283
284         if (!nameids_cache) {
285                 nameids_cache = talloc_array(NULL, struct MAPINAMEID *, 0x8000);
286                 memset(nameids_cache, 0, 0x8000 * sizeof (struct MAPINAMEID *));
287         }
288
289         mem_ctx = talloc_zero(NULL, TALLOC_CTX);
290
291         propidx = propID - 0x8000;
292         nameid = nameids_cache[propidx];
293         if (nameid) {
294                 *nameidp = nameid;
295                 return MAPISTORE_SUCCESS;
296         }
297
298         ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx),
299                          LDB_SCOPE_SUBTREE, attrs, "(mappedId=%d)", propID);
300         MAPISTORE_RETVAL_IF(ret != LDB_SUCCESS || !res->count, MAPISTORE_ERROR, mem_ctx);
301
302         guid = ldb_msg_find_attr_as_string(res->msgs[0], "oleguid", 0);
303         MAPISTORE_RETVAL_IF(!guid, MAPISTORE_ERROR, mem_ctx);
304
305         cn = ldb_msg_find_attr_as_string(res->msgs[0], "cn", 0);
306         MAPISTORE_RETVAL_IF(!cn, MAPISTORE_ERROR, mem_ctx);
307
308         oClass = ldb_msg_find_attr_as_string(res->msgs[0], "objectClass", 0);
309         MAPISTORE_RETVAL_IF(!propID, MAPISTORE_ERROR, mem_ctx);
310
311         nameid = talloc_zero(nameids_cache, struct MAPINAMEID);
312         GUID_from_string(guid, &nameid->lpguid);
313         if (strcmp(oClass, "MNID_ID") == 0) {
314                 nameid->ulKind = MNID_ID;
315                 nameid->kind.lid = strtol(cn, NULL, 16);
316         }
317         else if (strcmp(oClass, "MNID_STRING") == 0) {
318                 nameid->ulKind = MNID_STRING;
319                 nameid->kind.lpwstr.NameSize = strlen(cn) * 2 + 2;
320                 nameid->kind.lpwstr.Name = talloc_strdup(nameid, cn);
321         }
322         else {
323                 talloc_unlink(nameids_cache, nameid);
324                 nameid = NULL;
325                 rc = MAPISTORE_ERROR;
326         }
327
328         if (!rc) {
329                 nameids_cache[propidx] = nameid;
330                 *nameidp = nameid;
331         }
332
333         talloc_free(mem_ctx);
334
335         return rc;
336 }