2
OpenChange Storage Abstraction Layer library
6
Copyright (C) Julien Kerihuel 2010-2011
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.
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.
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/>.
24
#include "mapistore_errors.h"
25
#include "mapistore.h"
26
#include "mapistore_private.h"
27
#include "mapistore_common.h"
34
\brief MAPIStore database provisioning interface
38
\details Create a new mapistore database context
40
\param mem_ctx pointer to the memory context
42
\return Allocated mapistore database context on success, otherwise
45
struct mapistoredb_context *mapistoredb_new(TALLOC_CTX *mem_ctx)
47
struct mapistoredb_context *mdb_ctx;
51
/* Step 1. Initialize mapistoredb context */
52
mdb_ctx = talloc_zero(mem_ctx, struct mapistoredb_context);
54
MSTORE_DEBUG_ERROR(MSTORE_LEVEL_CRITICAL, "Failed to allocated memory for %s\n", "mdb_ctx");
58
mdb_ctx->param = talloc_zero(mem_ctx, struct mapistoredb_conf);
59
if (!mdb_ctx->param) {
60
MSTORE_DEBUG_ERROR(MSTORE_LEVEL_CRITICAL, "Failed to allocate memory for %s\n", "mdb_ctx->param");
65
/* Step 2. Initialize Samba loadparm context and load default values */
66
mdb_ctx->lp_ctx = loadparm_init(mdb_ctx);
67
lpcfg_load_default(mdb_ctx->lp_ctx);
69
/* Step 3. Retrieve default values from smb.conf */
70
mdb_ctx->param->netbiosname = strlower_talloc(mdb_ctx->param, lpcfg_netbios_name(mdb_ctx->lp_ctx));
71
mdb_ctx->param->dnsdomain = strlower_talloc(mdb_ctx->param, lpcfg_realm(mdb_ctx->lp_ctx));
72
mdb_ctx->param->domain = strlower_talloc(mdb_ctx->param, lpcfg_sam_name(mdb_ctx->lp_ctx));
74
switch (lpcfg_server_role(mdb_ctx->lp_ctx)) {
75
case ROLE_DOMAIN_CONTROLLER:
78
domaindn = str_list_make(mdb_ctx->param, mdb_ctx->param->dnsdomain, ".");
79
el_lower = strlower_talloc(mem_ctx, domaindn[0]);
80
mdb_ctx->param->domaindn = talloc_asprintf(mdb_ctx->param, "DC=%s", el_lower);
81
talloc_free(el_lower);
82
for (i = 1; domaindn[i]; i++) {
83
el_lower = strlower_talloc(mem_ctx, domaindn[i]);
84
mdb_ctx->param->domaindn = talloc_asprintf_append_buffer(mdb_ctx->param->domaindn, ",DC=%s", el_lower);
85
talloc_free(el_lower);
87
talloc_free(domaindn);
91
mdb_ctx->param->domaindn = talloc_asprintf(mdb_ctx->param, "CN=%s", mdb_ctx->param->domain);
95
mdb_ctx->param->serverdn = talloc_asprintf(mdb_ctx->param, TMPL_MDB_SERVERDN,
96
mdb_ctx->param->netbiosname,
97
mdb_ctx->param->domaindn);
98
mdb_ctx->param->firstorg = talloc_strdup(mdb_ctx->param, DFLT_MDB_FIRSTORG);
99
mdb_ctx->param->firstou = talloc_strdup(mdb_ctx->param, DFLT_MDB_FIRSTOU);
100
mdb_ctx->param->firstorgdn = talloc_asprintf(mdb_ctx->param, TMPL_MDB_FIRSTORGDN,
101
mdb_ctx->param->firstou,
102
mdb_ctx->param->firstorg,
103
mdb_ctx->param->serverdn);
104
mdb_ctx->param->db_path = NULL;
105
mdb_ctx->param->mstore_path = NULL;
106
mdb_ctx->param->db_named_path = NULL;
108
mdb_ctx->mstore_ctx = NULL;
114
\details Initialize the mapistore database context
116
\param mdb_ctx pointer to the mapistoredb context
117
\param path string pointer to the mapistore database location
119
If path is NULL, then the default mapistore database path will be used instead.
121
mdb_ctx is expected to have been created using mapistoredb_new
123
\return Allocated mapistore database context on success, otherwise NULL
125
enum MAPISTORE_ERROR mapistoredb_init(struct mapistoredb_context *mdb_ctx,
133
path = MAPISTORE_DBPATH;
136
if (!mdb_ctx->param->db_path)
138
mdb_ctx->param->db_path = talloc_asprintf(mdb_ctx->param, "%s/mapistore.ldb", path);
139
/* Ensure the path is valid */
140
ret = stat(path, &sb);
141
MAPISTORE_RETVAL_IF(ret == -1, MAPISTORE_ERR_NO_DIRECTORY, NULL);
143
if (!mdb_ctx->param->mstore_path)
144
mdb_ctx->param->mstore_path = talloc_asprintf(mdb_ctx->param, "%s/mapistore", path);
145
if (!mdb_ctx->param->db_named_path)
146
mdb_ctx->param->db_named_path = talloc_asprintf(mdb_ctx->param, "%s/%s",
147
mdb_ctx->param->mstore_path,
148
MAPISTORE_DB_NAMED_V2);
150
/* Step 4. Initialize mapistore */
151
if (stat(mdb_ctx->param->mstore_path, &sb) == -1) {
152
ret = mkdir(mdb_ctx->param->mstore_path, 0700);
154
perror(mdb_ctx->param->mstore_path);
155
return MAPISTORE_ERR_NO_DIRECTORY;
159
mapistore_set_database_path(mdb_ctx->param->db_path);
160
mapistore_set_mapping_path(mdb_ctx->param->mstore_path);
161
mapistore_set_named_properties_database_path(mdb_ctx->param->db_named_path);
162
mdb_ctx->mstore_ctx = mapistore_init(mdb_ctx, NULL);
163
if (!mdb_ctx->mstore_ctx) {
164
MSTORE_DEBUG_ERROR(MSTORE_LEVEL_INFO, "Failed to initialize mapistore %s\n", "context");
165
talloc_free(mdb_ctx);
166
return MAPISTORE_ERR_NOT_INITIALIZED;
169
return MAPISTORE_SUCCESS;
174
\details Free a mapistore database context
176
\param mdb_ctx the context to free (from mapistoredb_new())
178
void mapistoredb_release(struct mapistoredb_context *mdb_ctx)
181
MSTORE_DEBUG_ERROR(MSTORE_LEVEL_INFO, "Invalid mapistore database %s\n", "context");
185
talloc_free(mdb_ctx->lp_ctx);
186
talloc_free(mdb_ctx->param);
187
talloc_free(mdb_ctx);
192
\details Get a mapistore URI for a system/special folder from
195
\param mdb_ctx pointer to the mapistore database context
196
\param index the special folder index
197
\param username the username for which we want to retrieve the uri
198
\param uri the uri namespace for the backend we want to use
199
\param namespace_uri pointer to the resulting namespace uri (return value)
201
The special folder is specified by the \p index parameter. For example
202
to create the "inbox" folder, pass MDB_INBOX.
204
\return MAPISTORE_SUCCESS on success, otherwise MAPISTORE_ERROR
206
enum MAPISTORE_ERROR mapistoredb_get_mapistore_uri(struct mapistoredb_context *mdb_ctx,
207
enum MAPISTORE_DFLT_FOLDERS index,
208
const char *namespace_uri,
209
const char *username,
212
enum MAPISTORE_ERROR retval;
216
if (!mdb_ctx || !mdb_ctx->mstore_ctx) {
217
MSTORE_DEBUG_ERROR(MSTORE_LEVEL_INFO, "Invalid mapistore database %s\n", "context");
218
return MAPISTORE_ERR_INVALID_CONTEXT;
220
if (!namespace_uri || !username) {
221
MSTORE_DEBUG_ERROR(MSTORE_LEVEL_INFO, "Invalid %s\n", "parameter");
222
return MAPISTORE_ERR_INVALID_PARAMETER;
225
retval = mapistore_create_uri(mdb_ctx->mstore_ctx, index, namespace_uri, username, &_uri);
226
if (retval == MAPISTORE_SUCCESS) {
235
\details Retrieve the next available folder or message identifier
237
This function is a wrapper over mapistore_get_new_fmid from
238
mapistore_processing.c
240
\param mdb_ctx pointer to the mapistore database context
241
\param username the user to get the folder or message identifier for (i.e. identifier scope)
242
\param _fmid pointer on the next fmid available to return
244
\return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
246
\sa mapistoredb_get_new_allocation_range for an alternative function returning multiple identifiers
248
enum MAPISTORE_ERROR mapistoredb_get_new_fmid(struct mapistoredb_context *mdb_ctx,
249
const char *username,
252
enum MAPISTORE_ERROR retval;
256
MAPISTORE_RETVAL_IF(!mdb_ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
257
MAPISTORE_RETVAL_IF(!mdb_ctx->mstore_ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
258
MAPISTORE_RETVAL_IF(!mdb_ctx->mstore_ctx->processing_ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
259
MAPISTORE_RETVAL_IF(!_fmid, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
261
retval = mapistore_get_new_fmid(mdb_ctx->mstore_ctx->processing_ctx, username, &fmid);
262
if (retval == MAPISTORE_SUCCESS) {
264
return MAPISTORE_SUCCESS;
272
\details Retrieve a new allocation range
274
This function obtains a range of folder / message identifiers. Conceptually
275
you specify how many identifiers you want, and are provided a contiguous block
276
of identiers (in terms of a start and end, which are inclusive).
278
This function is a wrapper over mapistore_get_new_allocation_range
279
from mapistore_processing.c
281
\param mdb_ctx pointer to the mapistore database context
282
\param username the user for which we want to retrieve an
284
\param range the number of IDs to allocate
285
\param range_start pointer to the first ID of the range to return
286
\param range_end pointer to the last ID of the range to return
288
\return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
290
enum MAPISTORE_ERROR mapistoredb_get_new_allocation_range(struct mapistoredb_context *mdb_ctx,
291
const char *username,
293
uint64_t *range_start,
296
enum MAPISTORE_ERROR retval;
297
uint64_t _range_start = 0;
298
uint64_t _range_end = 0;
301
MAPISTORE_RETVAL_IF(!mdb_ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
302
MAPISTORE_RETVAL_IF(!mdb_ctx->mstore_ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
303
MAPISTORE_RETVAL_IF(!mdb_ctx->mstore_ctx->processing_ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
304
MAPISTORE_RETVAL_IF(!range_start || !range_end, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
306
retval = mapistore_get_new_allocation_range(mdb_ctx->mstore_ctx->processing_ctx, username, range, &_range_start, &_range_end);
307
if (retval == MAPISTORE_SUCCESS) {
308
*range_start = _range_start;
309
*range_end = _range_end;
311
return MAPISTORE_SUCCESS;
317
/** TODO: this is a copy of code in mapistore_mstoredb.c */
318
static bool write_ldif_string_to_store(struct mapistoredb_context *mdb_ctx, const char *ldif_string)
320
enum MAPISTORE_ERROR retval;
322
retval = mapistore_write_ldif_string_to_store(mdb_ctx->mstore_ctx->processing_ctx, ldif_string);
323
return (retval == MAPISTORE_SUCCESS) ? true : false;
328
\details Register a new folder in the mapistore database
330
This function is mainly used to encapsulate the creation of the
331
User store container, root Mailbox folder. subfolders getting
332
created through mstoredb backend.
334
This function is a wrapper over the
335
mapistore_indexing_add_fmid_record function from
336
indexing/mapistore_indexing.c file.
338
\param mdb_ctx pointer to the mapistore database context
339
\param username the username for which we want to create the
341
\param mapistore_uri the mapistore URI to register
343
\return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
345
enum MAPISTORE_ERROR mapistoredb_register_new_mailbox(struct mapistoredb_context *mdb_ctx,
346
const char *username,
347
const char *mapistore_uri)
350
enum MAPISTORE_ERROR retval;
351
struct mapistore_indexing_context_list *indexing_ctx;
352
const char *firstorgdn;
353
char *user_store_ldif;
362
MAPISTORE_RETVAL_IF(!mdb_ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
363
MAPISTORE_RETVAL_IF(!mdb_ctx->mstore_ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
364
MAPISTORE_RETVAL_IF(!username, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
365
MAPISTORE_RETVAL_IF(!mapistore_uri, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
367
/* Step 1. We want to ensure the mapistore_uri is a mstoredb:// one */
368
if (strncmp("mstoredb://", mapistore_uri, strlen("mstoredb://"))) {
369
MSTORE_DEBUG_ERROR(MSTORE_LEVEL_INFO, "Invalid mapistore URI. MUST be %s\n", "mstoredb");
370
return MAPISTORE_ERR_INVALID_PARAMETER;
373
/* Retrieve configuration parameters */
374
firstorgdn = mapistore_get_firstorgdn();
376
MSTORE_DEBUG_ERROR(MSTORE_LEVEL_INFO, "Invalid %s\n", "firstorgdn");
377
return MAPISTORE_ERR_INVALID_PARAMETER;
380
/* Step 2. Create the user store entry within the mapistore database */
381
mem_ctx = talloc_named(NULL, 0, __FUNCTION__);
382
user_store_ldif = talloc_asprintf(mem_ctx, MDB_USER_STORE_LDIF_TMPL,
383
username, firstorgdn, username);
384
if (write_ldif_string_to_store(mdb_ctx, user_store_ldif) == false) {
385
MSTORE_DEBUG_ERROR(MSTORE_LEVEL_INFO, "Failed to add user store %s\n", "container");
386
talloc_free(mem_ctx);
387
return MAPISTORE_ERR_DATABASE_OPS;
389
talloc_free(user_store_ldif);
391
/* Step 3. Generate a fid for this mailbox root container */
392
retval = mapistore_get_new_fmid(mdb_ctx->mstore_ctx->processing_ctx, username, &fid);
393
MAPISTORE_RETVAL_IF(retval, retval, mem_ctx);
395
/* Step 4. Add an indexing context for user */
396
retval = mapistore_indexing_context_add(mdb_ctx->mstore_ctx, username, &indexing_ctx);
397
MAPISTORE_RETVAL_IF(retval, retval, NULL);
399
/* Step 5. Register the mailbox root container */
400
retval = mapistore_indexing_add_fmid_record(indexing_ctx, fid, mapistore_uri, 0, MAPISTORE_INDEXING_FOLDER);
401
MAPISTORE_RETVAL_IF(retval, retval, mem_ctx);
403
/* Step 6. Delete the indexing context */
404
retval = mapistore_indexing_context_del(mdb_ctx->mstore_ctx, username);
405
MAPISTORE_RETVAL_IF(retval, retval, mem_ctx);
407
/* Step 7. Add the mailbox root container to mapistore.ldb */
409
dn = (char *) &mapistore_uri[strlen("mstoredb://")];
411
guid = GUID_random();
412
mailboxGUID = GUID_string(mem_ctx, &guid);
414
guid = GUID_random();
415
replicaGUID = GUID_string(mem_ctx, &guid);
417
mailbox_ldif = talloc_asprintf(mem_ctx, MDB_MAILBOX_LDIF_TMPL,
418
username, firstorgdn, dn, "Mailbox Root",
419
mailboxGUID, replicaGUID,
420
MDB_ROOT_FOLDER, mapistore_uri, dn);
421
if (write_ldif_string_to_store(mdb_ctx, mailbox_ldif) == false) {
422
MSTORE_DEBUG_ERROR(MSTORE_LEVEL_CRITICAL, "Failed to add mailbox root %s\n", "container");
423
talloc_free(mem_ctx);
425
return MAPISTORE_ERR_DATABASE_OPS;
428
talloc_free(mailboxGUID);
429
talloc_free(replicaGUID);
430
talloc_free(mailbox_ldif);
432
talloc_free(mem_ctx);
439
\details Add an allocation range for messages to the mailbox root
440
container within the mapistore database.
442
\param mdb_ctx pointer to the mapistore database context
443
\param username the username for which we want to add a new
444
allocation range to the mailbox container
445
\param rstart the beginning of the allocation ID range
446
\param rend the end of the allocation ID range
448
\return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
450
enum MAPISTORE_ERROR mapistoredb_register_new_mailbox_allocation_range(struct mapistoredb_context *mdb_ctx,
451
const char *username,
455
enum MAPISTORE_ERROR retval;
456
struct mapistore_indexing_context_list *indexing_ctx;
461
MAPISTORE_RETVAL_IF(!mdb_ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
462
MAPISTORE_RETVAL_IF(!mdb_ctx->mstore_ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
463
MAPISTORE_RETVAL_IF(!username, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
464
MAPISTORE_RETVAL_IF(!rstart || !rend, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
465
MAPISTORE_RETVAL_IF(rstart > rend, MAPISTORE_ERR_INVALID_PARAMETER, NULL);
467
/* Step 1. Add an indexing context for user */
468
retval = mapistore_indexing_context_add(mdb_ctx->mstore_ctx, username, &indexing_ctx);
469
MAPISTORE_RETVAL_IF(retval, retval, NULL);
471
/* Step 2. Retrieve the FID for the user mailbox root folder */
472
retval = mapistore_get_mailbox_uri(mdb_ctx->mstore_ctx->processing_ctx, username, &mailbox_root);
473
MAPISTORE_RETVAL_IF(retval, retval, NULL);
475
retval = mapistore_indexing_get_record_fmid_by_uri(indexing_ctx, mailbox_root, &fid);
476
talloc_free(mailbox_root);
477
MAPISTORE_RETVAL_IF(retval, retval, NULL);
479
/* Step 3. Update the allocation range for root container */
480
retval = mapistore_indexing_add_folder_record_allocation_range(indexing_ctx, fid, rstart, rend);
481
MAPISTORE_RETVAL_IF(retval, retval, NULL);
483
/* Step 4. Delete the indexing context */
484
retval = mapistore_indexing_context_del(mdb_ctx->mstore_ctx, username);
485
MAPISTORE_RETVAL_IF(retval, retval, NULL);
492
\details Default provisioning for mapistore.ldb database
494
\param mdb_ctx pointer to the mapistore database context
496
\return MAPISTORE_SUCCESS on success, otherwise a non-zero MAPISTORE_ERROR
498
enum MAPISTORE_ERROR mapistoredb_provision(struct mapistoredb_context *mdb_ctx)
503
MAPISTORE_RETVAL_IF(!mdb_ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
504
MAPISTORE_RETVAL_IF(!mdb_ctx->mstore_ctx, MAPISTORE_ERR_NOT_INITIALIZED, NULL);
506
/* Step 1. Add database schema */
507
if (write_ldif_string_to_store(mdb_ctx, MDB_INIT_LDIF_TMPL) == false) {
508
MSTORE_DEBUG_ERROR(MSTORE_LEVEL_INFO, "Failed to add database %s\n", "schema");
509
return MAPISTORE_ERR_DATABASE_OPS;
512
/* Step 2. Add RootDSE schema */
513
ldif_str = talloc_asprintf(mdb_ctx, MDB_ROOTDSE_LDIF_TMPL,
514
mdb_ctx->param->firstou,
515
mdb_ctx->param->firstorg,
516
mdb_ctx->param->serverdn,
517
mdb_ctx->param->serverdn);
518
if (write_ldif_string_to_store(mdb_ctx, ldif_str) == false) {
519
MSTORE_DEBUG_ERROR(MSTORE_LEVEL_INFO, "Failed to add RootDSE %s\n", "schema");
520
talloc_free(ldif_str);
521
return MAPISTORE_ERR_DATABASE_OPS;
523
talloc_free(ldif_str);
525
/* Step 3. Provision Server object responsible for maintaining
526
* the Replica and GlobalCount identifier */
527
ldif_str = talloc_asprintf(mdb_ctx, MDB_SERVER_LDIF_TMPL,
528
mdb_ctx->param->serverdn,
529
mdb_ctx->param->netbiosname,
530
mdb_ctx->param->firstorg,
531
mdb_ctx->param->serverdn,
532
mdb_ctx->param->firstorg,
533
mdb_ctx->param->firstou,
534
mdb_ctx->param->firstorg,
535
mdb_ctx->param->serverdn,
536
mdb_ctx->param->firstou);
537
if (write_ldif_string_to_store(mdb_ctx, ldif_str) == false) {
538
MSTORE_DEBUG_ERROR(MSTORE_LEVEL_INFO, "Failed to provision server %s\n", "object");
539
talloc_free(ldif_str);
540
return MAPISTORE_ERR_DATABASE_OPS;
542
talloc_free(ldif_str);
544
return MAPISTORE_SUCCESS;