2
OpenChange Storage Abstraction Layer library
3
MAPIStore database backend
7
Copyright (C) Julien Kerihuel 2010-2011
8
Copyright (C) Brad Hards 2010-2011
10
This program is free software; you can redistribute it and/or modify
11
it under the terms of the GNU General Public License as published by
12
the Free Software Foundation; either version 3 of the License, or
13
(at your option) any later version.
15
This program is distributed in the hope that it will be useful,
16
but WITHOUT ANY WARRANTY; without even the implied warranty of
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
GNU General Public License for more details.
20
You should have received a copy of the GNU General Public License
21
along with this program. If not, see <http://www.gnu.org/licenses/>.
24
#include "mapistore_mstoredb.h"
25
#include "mapiproxy/libmapiproxy/libmapiproxy.h"
28
\details Initialize mstoredb mapistore backend
30
\return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
32
static enum MAPISTORE_ERROR mstoredb_init(void)
34
MSTORE_DEBUG_INFO(MSTORE_LEVEL_INFO, MSTORE_SINGLE_MSG, "mstoredb backend initialized\n");
35
return MAPISTORE_SUCCESS;
39
\details Generate a mapistore URI for root (system/special) folders
41
\param mem_ctx pointer to the memory context
42
\param index the folder index for which to create the mapistore URI
43
\param username the username for which to create the mapistore URI
44
\param mapistore_uri pointer on pointer to the string to return
46
\return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
48
static enum MAPISTORE_ERROR mstoredb_create_mapistore_uri(TALLOC_CTX *mem_ctx,
49
enum MAPISTORE_DFLT_FOLDERS index,
53
const char *firstorgdn;
57
if (!username || !mapistore_uri) {
58
MSTORE_DEBUG_ERROR(MSTORE_LEVEL_PEDANTIC, MSTORE_SINGLE_MSG, "Invalid parameter\n");
59
return MAPISTORE_ERR_INVALID_PARAMETER;
62
firstorgdn = mapistore_get_firstorgdn();
64
MSTORE_DEBUG_ERROR(MSTORE_LEVEL_PEDANTIC, MSTORE_SINGLE_MSG, "Invalid firstorgdn\n");
65
return MAPISTORE_ERR_INVALID_PARAMETER;
68
for (i = 0; dflt_folders[i].name; i++) {
69
if (dflt_folders[i].index == index) {
70
*mapistore_uri = talloc_asprintf(mem_ctx, "mstoredb://%s,CN=%s,%s", dflt_folders[i].name, username, firstorgdn);
71
MSTORE_DEBUG_SUCCESS(MSTORE_LEVEL_DEBUG, "URI = %s\n", *mapistore_uri);
72
return MAPISTORE_SUCCESS;
76
return MAPISTORE_ERR_NOT_FOUND;
80
\details Provides a LDIF file or buffer to upper mapistore layers
81
to provision mstoredb:// Internal namespace
83
\param mem_ctx pointer to the memory context
84
\param ldif pointer on pointer to the LDIF filename or buffer to return
85
\param type pointer to the type of LDIF content to return
87
\return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
89
static enum MAPISTORE_ERROR mstoredb_provision_namedprops(TALLOC_CTX *mem_ctx,
91
enum MAPISTORE_NAMEDPROPS_PROVISION_TYPE *ntype)
94
MAPISTORE_RETVAL_IF(!ldif, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
96
return MAPISTORE_ERR_NOT_IMPLEMENTED;
100
\details Create a connection context to the mstoredb backend
102
\param ctx pointer to the opaque mapistore backend context
103
\param login_user the username used to authenticate
104
\param username the username we want to impersonate
105
\param uri pointer to the mstoredb DN to open
106
\param private_data pointer to the private backend context to return
108
static enum MAPISTORE_ERROR mstoredb_create_context(struct mapistore_backend_context *ctx,
109
const char *login_user,
110
const char *username,
114
enum MAPISTORE_ERROR retval;
116
struct mstoredb_context *mstoredb_ctx;
120
MAPISTORE_RETVAL_IF(!ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
121
MAPISTORE_RETVAL_IF(!uri, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
122
MAPISTORE_RETVAL_IF(!private_data, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
124
MSTORE_DEBUG_SUCCESS(MSTORE_LEVEL_PEDANTIC, "uri = %s\n", uri);
126
mem_ctx = (TALLOC_CTX *) ctx;
128
/* Step 1. Initialize mstoredb context */
129
mstoredb_ctx = talloc_zero(mem_ctx, struct mstoredb_context);
130
mstoredb_ctx->context_dn = talloc_strdup(mstoredb_ctx, uri);
131
mstoredb_ctx->login_user = talloc_strdup(mstoredb_ctx, username);
132
mstoredb_ctx->username = talloc_strdup(mstoredb_ctx, username);
133
mstoredb_ctx->mdb_ctx = ctx;
135
/* Step 2. Retrieve path to the mapistore database */
136
mstoredb_ctx->dbpath = mapistore_get_database_path();
137
MSTORE_DEBUG_SUCCESS(MSTORE_LEVEL_PEDANTIC, "database path = %s\n", mstoredb_ctx->dbpath);
139
/* Step 3. Open a wrapped connection to mapistore.ldb */
140
mstoredb_ctx->ldb_ctx = mapistore_public_ldb_connect(mstoredb_ctx->mdb_ctx, mstoredb_ctx->dbpath);
141
if (!mstoredb_ctx->ldb_ctx) {
142
MSTORE_DEBUG_ERROR(MSTORE_LEVEL_CRITICAL, "Unable to open mapistore.ldb at %s\n", mstoredb_ctx->dbpath);
143
talloc_free(mstoredb_ctx);
144
return MAPISTORE_ERR_DATABASE_INIT;
147
/* Step 4. Retrieve the FID associated to this URI */
148
new_uri = talloc_asprintf(mem_ctx, "mstoredb://%s", uri);
149
retval = mapistore_exist(mstoredb_ctx->mdb_ctx, username, new_uri);
150
if (retval != MAPISTORE_ERR_EXIST) {
151
MSTORE_DEBUG_ERROR(MSTORE_LEVEL_DEBUG, "Indexing database failed to find a record for URI: %s\n", uri);
152
talloc_free(new_uri);
153
talloc_free(mstoredb_ctx);
157
talloc_free(new_uri);
159
mstoredb_ctx->basedn = ldb_dn_new(mstoredb_ctx, mstoredb_ctx->ldb_ctx, uri);
160
if (!mstoredb_ctx->basedn) {
161
MSTORE_DEBUG_ERROR(MSTORE_LEVEL_DEBUG, MSTORE_SINGLE_MSG, "Unable to create DN from URI");
162
talloc_free(mstoredb_ctx);
163
return MAPISTORE_ERROR;
166
*private_data = (void *)mstoredb_ctx;
168
return MAPISTORE_SUCCESS;
172
\details Delete a connection context from the mstoredb backend
174
\param private_data pointer to the current mstoredb context
176
\return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
178
static enum MAPISTORE_ERROR mstoredb_delete_context(void *private_data)
180
MSTORE_DEBUG_INFO(MSTORE_LEVEL_DEBUG, MSTORE_SINGLE_MSG, "");
182
return MAPISTORE_SUCCESS;
186
\details Create a root default/system mailbox folder in the
187
mstoredb backend and store store common attributes for caching
190
\param private_data pointer to the current mstoredb context
191
\param mapistore_uri pointer to the mapistore URI for the folder
192
\param folder_name the name of the folder to create
193
\param folder_desc the description for the folder
195
\return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
197
static enum MAPISTORE_ERROR mstoredb_op_db_mkdir(void *private_data,
198
enum MAPISTORE_DFLT_FOLDERS system_idx,
199
const char *mapistore_uri,
200
const char *folder_name)
203
struct mstoredb_context *mstoredb_ctx = (struct mstoredb_context *) private_data;
204
enum MAPISTORE_ERROR retval;
205
char *mapistore_root_folder = NULL;
207
const char *cn = NULL;
208
const char *container_class = "IPF.Note";
211
MSTORE_DEBUG_INFO(MSTORE_LEVEL_DEBUG, MSTORE_SINGLE_MSG, "");
214
MAPISTORE_RETVAL_IF(!mstoredb_ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
215
MAPISTORE_RETVAL_IF(!mapistore_uri, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
217
/* Step 1. Ensure the mapistore URI doesn't already exist in the indexing database */
218
retval = mapistore_exist(mstoredb_ctx->mdb_ctx, mstoredb_ctx->username, mapistore_uri);
219
if (retval == MAPISTORE_ERR_EXIST) {
220
MSTORE_DEBUG_ERROR(MSTORE_LEVEL_HIGH, "URI for %s already registered (%s)\n", mstoredb_ctx->username, mapistore_uri);
224
/* Step 2. Retrieve the cn attribute's value from our dflt folder array */
225
for (i = 0; dflt_folders[i].name; i++) {
226
if (dflt_folders[i].index == system_idx) {
228
folder_name = dflt_folders[i].cn;
230
cn = dflt_folders[i].cn;
231
container_class = dflt_folders[i].container_class;
235
MAPISTORE_RETVAL_IF(!cn, MAPISTORE_ERR_INVALID_URI, NULL);
237
/* Step 3. Strip out the namespace from URI if required */
238
if (!strncmp("mstoredb://", mapistore_uri, strlen("mstoredb://"))) {
239
uri = &mapistore_uri[strlen("mstoredb://")];
244
/* Step 3. Create the LDIF formated entry for the folder */
245
mem_ctx = talloc_new(NULL);
246
mapistore_root_folder = talloc_asprintf(mem_ctx, MDB_ROOTFOLDER_LDIF_TMPL,
247
uri, cn, folder_name, container_class,
250
/* Step 3. Create folder entry within mapistore.ldb */
251
retval = mapistore_ldb_write_ldif_string_to_store(mstoredb_ctx->ldb_ctx, mapistore_root_folder);
252
talloc_free(mapistore_root_folder);
253
talloc_free(mem_ctx);
259
\details Create a folder in the mstoredb backend
261
\param private_data pointer to the current mstoredb backend
262
\param parent_uri the parent folder mapistore URI
263
\param folder_name the folder name to be created
264
\param folder_desc the folder description for the folder
265
\param folder_type the type of folder
266
\param folder_uri the folder URI to return
268
\return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
270
static enum MAPISTORE_ERROR mstoredb_op_mkdir(void *private_data,
271
const char *parent_uri,
272
const char *folder_name,
273
const char *folder_desc,
274
enum FOLDER_TYPE folder_type,
278
enum MAPISTORE_ERROR retval = MAPISTORE_SUCCESS;
279
const char *stripped_uri;
280
struct mstoredb_context *mstoredb_ctx = (struct mstoredb_context *) private_data;
282
const char *folder_dn;
284
MSTORE_DEBUG_INFO(MSTORE_LEVEL_DEBUG, MSTORE_SINGLE_MSG, "");
287
MAPISTORE_RETVAL_IF(!mstoredb_ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
288
MAPISTORE_RETVAL_IF(!parent_uri, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
289
MAPISTORE_RETVAL_IF(!folder_name, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
290
MAPISTORE_RETVAL_IF(!folder_uri, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
294
/* Step 1. Ensure the parent uri exists */
295
retval = mapistore_exist(mstoredb_ctx->mdb_ctx, mstoredb_ctx->username, parent_uri);
296
if (retval != MAPISTORE_ERR_EXIST) {
297
MSTORE_DEBUG_ERROR(MSTORE_LEVEL_HIGH, "Failed to find parent folder: %s\n", parent_uri);
301
mem_ctx = talloc_named(NULL, 0, __FUNCTION__);
303
/* Step 2. Generate the URI for the folder */
304
retval = mapistore_strip_ns_from_uri(parent_uri, &stripped_uri);
306
*folder_uri = talloc_asprintf((TALLOC_CTX *)mstoredb_ctx, "mstoredb://CN=%s,%s", folder_name, stripped_uri);
307
MAPISTORE_RETVAL_IF(!*folder_uri, MAPISTORE_ERR_NO_MEMORY, mem_ctx);
308
MSTORE_DEBUG_INFO(MSTORE_LEVEL_DEBUG, "Generated URI: '%s'\n", *folder_uri);
310
retval = mapistore_strip_ns_from_uri(*folder_uri, &folder_dn);
312
talloc_free(*folder_uri);
317
/* Ensure the folder doesn't exist */
318
retval = mapistore_exist(mstoredb_ctx->mdb_ctx, mstoredb_ctx->username, (const char *)*folder_uri);
319
if (retval == MAPISTORE_ERR_EXIST) {
320
MSTORE_DEBUG_ERROR(MSTORE_LEVEL_INFO, "URI already exists!: %s\n", *folder_uri);
321
talloc_free(*folder_uri);
326
/* Do ACLs check on parent URI */
328
/* Do folder creation */
330
ldif = talloc_asprintf(mem_ctx, MDB_FOLDER_WITH_COMMENT_LDIF_TMPL,
331
folder_dn, folder_name, (uint32_t)folder_type,
332
folder_name, folder_desc);
334
retval = MAPISTORE_ERR_NO_MEMORY;
338
ldif = talloc_asprintf(mem_ctx, MDB_FOLDER_WITH_NAME_LDIF_TMPL,
339
folder_dn, folder_name, (uint32_t)folder_type,
343
retval = mapistore_ldb_write_ldif_string_to_store(mstoredb_ctx->ldb_ctx, ldif);
347
talloc_free(mem_ctx);
352
static enum MAPISTORE_ERROR mstoredb_op_opendir(void *private_data,
353
const char *parent_uri,
354
const char *folder_uri)
356
struct mstoredb_context *mstoredb_ctx = (struct mstoredb_context *) private_data;
359
MAPISTORE_RETVAL_IF(!mstoredb_ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
360
MAPISTORE_RETVAL_IF(!parent_uri, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
361
MAPISTORE_RETVAL_IF(!folder_uri, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
363
/* TODO: This is just a stub implementation */
364
MSTORE_DEBUG_INFO(MSTORE_LEVEL_DEBUG, "Opening: %s\n", folder_uri);
366
return MAPISTORE_SUCCESS;
369
static enum MAPISTORE_ERROR mstoredb_op_setprops(void *private_data,
374
struct mstoredb_context *mstoredb_ctx = (struct mstoredb_context *) private_data;
375
const char *dn = NULL;
376
enum MAPISTORE_ERROR retval;
377
struct ldb_message *msg = NULL;
378
TALLOC_CTX *mem_ctx = NULL;
382
MSTORE_DEBUG_INFO(MSTORE_LEVEL_DEBUG, "Setting properties on %s\n", uri);
385
MAPISTORE_RETVAL_IF(!mstoredb_ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
386
MAPISTORE_RETVAL_IF(!uri, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
387
MAPISTORE_RETVAL_IF(!aRow, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
389
retval = mapistore_strip_ns_from_uri(uri, &dn);
390
MAPISTORE_RETVAL_IF(retval, retval, NULL);
392
MSTORE_DEBUG_INFO(MSTORE_LEVEL_DEBUG, "Setting props on dn: '%s'\n", dn);
394
/* TODO: ensure the uri exists */
396
/* TODO: check ACLs on folder */
398
/* build the ldb_msg */
399
mem_ctx = talloc_named(NULL, 0, __FUNCTION__);
400
msg = ldb_msg_new(mem_ctx);
401
msg->dn = ldb_dn_new(msg, mstoredb_ctx->ldb_ctx, dn);
402
for (i = 0; i < aRow->cValues; ++i) {
403
char *property_tag = talloc_strdup(mem_ctx, get_proptag_name(aRow->lpProps[i].ulPropTag));
405
property_tag = talloc_asprintf(mem_ctx, "0x%"PRIx32, aRow->lpProps[i].ulPropTag);
407
switch (aRow->lpProps[i].ulPropTag & 0xFFFF) {
409
ldb_msg_add_fmt(msg, property_tag , "%"PRIi16, aRow->lpProps[i].value.i);
412
ldb_msg_add_fmt(msg, property_tag, "%"PRIi32, aRow->lpProps[i].value.l);
415
ldb_msg_add_fmt(msg, property_tag, aRow->lpProps[i].value.b?"True":"False");
418
ldb_msg_add_fmt(msg, property_tag, "%g", aRow->lpProps[i].value.dbl);
421
ldb_msg_add_fmt(msg, property_tag, "0x%"PRIx64, aRow->lpProps[i].value.d);
424
ldb_msg_add_fmt(msg, property_tag, "%s", aRow->lpProps[i].value.lpszA);
427
ldb_msg_add_fmt(msg, property_tag, "%s", aRow->lpProps[i].value.lpszW);
430
MSTORE_DEBUG_INFO(MSTORE_LEVEL_CRITICAL, "Unsupported property type: 0x%x\n", aRow->lpProps[i].ulPropTag & 0xFFFF);
432
msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
435
/* Write properties to store */
436
ret = ldb_modify(mstoredb_ctx->ldb_ctx, msg);
437
if (ret != LDB_SUCCESS) {
438
MSTORE_DEBUG_INFO(MSTORE_LEVEL_CRITICAL, "Failed to set properties on %s: %s\n", uri, ldb_strerror(ret));;
439
talloc_free(mem_ctx);
440
return MAPISTORE_ERR_DATABASE_OPS;
442
talloc_free(mem_ctx);
444
return MAPISTORE_SUCCESS;
448
\details Entry point for mapistore MSTOREDB backend
450
\return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
452
enum MAPISTORE_ERROR mapistore_init_backend(void)
454
struct mapistore_backend backend;
455
enum MAPISTORE_ERROR retval;
457
/* Initialize backend with defaults */
458
retval = mapistore_backend_init_defaults(&backend);
459
MAPISTORE_RETVAL_IF(retval, retval, NULL);
461
/* Fill in our name */
462
backend.name = "mstoredb";
463
backend.description = "mapistore database backend";
464
backend.uri_namespace = "mstoredb://";
466
/* Fill in backend operations */
467
backend.init = mstoredb_init;
468
backend.create_context = mstoredb_create_context;
469
backend.delete_context = mstoredb_delete_context;
471
/* Fill in folder operations */
472
backend.op_mkdir = mstoredb_op_mkdir;
473
backend.op_opendir = mstoredb_op_opendir;
474
backend.op_setprops = mstoredb_op_setprops;
476
/* Fill in MAPIStoreDB/store operations */
477
backend.op_db_create_uri = mstoredb_create_mapistore_uri;
478
backend.op_db_provision_namedprops = mstoredb_provision_namedprops;
479
backend.op_db_mkdir = mstoredb_op_db_mkdir;
481
/* Register ourselves with the MAPISTORE subsystem */
482
retval = mapistore_backend_register(&backend);
483
if (retval != MAPISTORE_SUCCESS) {
484
MSTORE_DEBUG_ERROR(MSTORE_LEVEL_CRITICAL, "Failed to register the '%s' mapistore backend!\n", backend.name);