2 OpenChange MAPI implementation.
4 Copyright (C) Julien Kerihuel 2007-2011.
5 Copyright (C) Fabien Le Mentec 2007.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "libmapi/libmapi.h"
22 #include "libmapi/libmapi_private.h"
23 #include <credentials.h>
24 #include <ldb_errors.h>
30 \brief MAPI Profiles interface
38 * Load a MAPI profile into a mapi_profile struct
40 static enum MAPISTATUS ldb_load_profile(TALLOC_CTX *mem_ctx,
41 struct ldb_context *ldb_ctx,
42 struct mapi_profile *profile,
43 const char *profname, const char *password)
46 enum ldb_scope scope = LDB_SCOPE_SUBTREE;
47 struct ldb_result *res;
48 struct ldb_message *msg;
49 const char * const attrs[] = { "*", NULL };
51 /* fills in profile name */
52 profile->profname = talloc_strdup(mem_ctx, profname);
53 if (!profile->profname) return MAPI_E_NOT_ENOUGH_RESOURCES;
55 ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs, "(cn=%s)(cn=Profiles)", profile->profname);
56 if (ret != LDB_SUCCESS) return MAPI_E_NOT_FOUND;
58 /* profile not found */
59 if (!res->count) return MAPI_E_NOT_FOUND;
60 /* more than one profile */
61 if (res->count > 1) return MAPI_E_COLLISION;
63 /* fills in profile with query result */
66 profile->username = ldb_msg_find_attr_as_string(msg, "username", NULL);
67 profile->password = password ? password : ldb_msg_find_attr_as_string(msg, "password", "");
68 profile->workstation = ldb_msg_find_attr_as_string(msg, "workstation", NULL);
69 profile->realm = ldb_msg_find_attr_as_string(msg, "realm", NULL);
70 profile->domain = ldb_msg_find_attr_as_string(msg, "domain", NULL);
71 profile->mailbox = ldb_msg_find_attr_as_string(msg, "EmailAddress", NULL);
72 profile->homemdb = ldb_msg_find_attr_as_string(msg, "HomeMDB", NULL);
73 profile->localaddr = ldb_msg_find_attr_as_string(msg, "localaddress", NULL);
74 profile->server = ldb_msg_find_attr_as_string(msg, "binding", NULL);
75 profile->seal = ldb_msg_find_attr_as_bool(msg, "seal", false);
76 profile->org = ldb_msg_find_attr_as_string(msg, "Organization", NULL);
77 profile->ou = ldb_msg_find_attr_as_string(msg, "OrganizationUnit", NULL);
78 profile->codepage = ldb_msg_find_attr_as_int(msg, "codepage", 0);
79 profile->language = ldb_msg_find_attr_as_int(msg, "language", 0);
80 profile->method = ldb_msg_find_attr_as_int(msg, "method", 0);
81 profile->exchange_version = ldb_msg_find_attr_as_int(msg, "exchange_version", 0);
83 if (!profile->password) return MAPI_E_INVALID_PARAMETER;
85 return MAPI_E_SUCCESS;
89 * Remove the "default" attribute from whichever profile is currently the default profile
91 static enum MAPISTATUS ldb_clear_default_profile(struct mapi_context *mapi_ctx,
94 enum ldb_scope scope = LDB_SCOPE_SUBTREE;
95 struct ldb_context *ldb_ctx;
96 struct ldb_dn *basedn;
97 struct ldb_message *msg;
98 struct ldb_result *res;
99 const char *attrs[] = { "PR_DEFAULT_PROFILE", NULL };
103 ldb_ctx = mapi_ctx->ldb_ctx;
105 basedn = ldb_dn_new(ldb_ctx, ldb_ctx, "CN=Profiles");
106 ret = ldb_search(ldb_ctx, mem_ctx, &res, basedn, scope, attrs, "(cn=*)");
108 if (ret != LDB_SUCCESS) return MAPI_E_NOT_FOUND;
109 if (!res->count) return MAPI_E_NOT_FOUND;
111 for (i = 0; i < res->count; i++) {
112 struct ldb_message *message;
115 if (msg->num_elements == 1) {
116 message = talloc_steal(mem_ctx, msg);
117 message->elements[0].flags = LDB_FLAG_MOD_DELETE;
119 ret = ldb_modify(ldb_ctx, message);
120 talloc_free(message);
124 return MAPI_E_SUCCESS;
128 * Test if the password is correct
130 static enum MAPISTATUS ldb_test_password(struct mapi_context *mapi_ctx,
133 const char *password)
135 enum ldb_scope scope = LDB_SCOPE_DEFAULT;
136 struct ldb_context *ldb_ctx;
137 struct ldb_message *msg;
138 struct ldb_result *res;
139 const char *attrs[] = {"cn", "password", NULL };
140 const char *ldb_password;
143 ldb_ctx = mapi_ctx->ldb_ctx;
145 ret = ldb_search(ldb_ctx, mem_ctx, &res, NULL, scope, attrs,
146 "(cn=%s)(cn=Profiles)", profile);
148 if (ret != LDB_SUCCESS) return MAPI_E_NO_SUPPORT;
149 if (!res->count) return MAPI_E_NOT_FOUND;
153 ldb_password = ldb_msg_find_attr_as_string(msg, "password", NULL);
154 if (!ldb_password) return MAPI_E_NO_SUPPORT;
155 if (strncmp(password, ldb_password, strlen(password))) return MAPI_E_LOGON_FAILED;
157 return MAPI_E_SUCCESS;
162 * Add a profile to the database with default fields
164 static enum MAPISTATUS ldb_create_profile(TALLOC_CTX *mem_ctx,
165 struct ldb_context *ldb_ctx,
166 const char *profname)
168 enum ldb_scope scope = LDB_SCOPE_SUBTREE;
169 struct ldb_message msg;
170 struct ldb_message_element el[2];
171 struct ldb_val vals[2][1];
172 struct ldb_result *res;
173 struct ldb_dn *basedn;
176 const char * const attrs[] = { "*", NULL };
179 if (profname == NULL)
180 return MAPI_E_BAD_VALUE;
182 /* Does the profile already exists? */
183 ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx),
184 scope, attrs, "(cn=%s)(cn=Profiles)", profname);
185 if (ret == LDB_SUCCESS && res && res->msgs) return MAPI_E_NO_ACCESS;
188 * We now prepare the entry for transaction
191 dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", profname);
192 basedn = ldb_dn_new(ldb_ctx, ldb_ctx, dn);
194 if (!ldb_dn_validate(basedn)) return MAPI_E_BAD_VALUE;
196 msg.dn = ldb_dn_copy(mem_ctx, basedn);
197 msg.num_elements = 2;
201 el[0].name = talloc_strdup(mem_ctx, "cn");
202 el[0].num_values = 1;
203 el[0].values = vals[0];
204 vals[0][0].data = (uint8_t *)talloc_strdup(mem_ctx, profname);
205 vals[0][0].length = strlen(profname);
208 el[1].name = talloc_strdup(mem_ctx, "name");
209 el[1].num_values = 1;
210 el[1].values = vals[1];
211 vals[1][0].data = (uint8_t *)talloc_strdup(mem_ctx, profname);
212 vals[1][0].length = strlen(profname);
214 ret = ldb_add(ldb_ctx, &msg);
216 if (ret != LDB_SUCCESS) return MAPI_E_NO_SUPPORT;
218 return MAPI_E_SUCCESS;
222 * delete the current profile
224 static enum MAPISTATUS ldb_delete_profile(TALLOC_CTX *mem_ctx,
225 struct ldb_context *ldb_ctx,
226 const char *profname)
228 enum ldb_scope scope = LDB_SCOPE_SUBTREE;
229 struct ldb_result *res;
230 const char * const attrs[] = { "*", NULL };
233 ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs, "(cn=%s)(cn=Profiles)", profname);
234 if (!res->msgs) return MAPI_E_NOT_FOUND;
236 ret = ldb_delete(ldb_ctx, res->msgs[0]->dn);
237 if (ret != LDB_SUCCESS) return MAPI_E_NOT_FOUND;
239 return MAPI_E_SUCCESS;
244 \details Copy the MAPI profile
246 \param mem_ctx pointer to the memory context
247 \param ldb_ctx pointer to the LDB context
248 \param profname_src pointer to the source profile name
249 \param profname_dest pointer to the destination profile name
251 static enum MAPISTATUS ldb_copy_profile(TALLOC_CTX *mem_ctx,
252 struct ldb_context *ldb_ctx,
253 const char *profname_src,
254 const char *profname_dest)
257 enum ldb_scope scope = LDB_SCOPE_SUBTREE;
258 struct ldb_result *res;
259 struct ldb_result *res_dest;
260 struct ldb_message *msg;
261 const char * const attrs[] = { "*", NULL };
264 struct ldb_message_element *el;
265 struct ldb_dn *basedn;
267 /* Step 1. Load the source profile */
268 ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs,
269 "(cn=%s)(cn=Profiles)", profname_src);
270 /* profile not found */
271 if (ret != LDB_SUCCESS) return MAPI_E_NOT_FOUND;
272 /* more than one profile */
273 if (res->count > 1) return MAPI_E_COLLISION;
275 /* fills in profile with query result */
278 /* Step 2. Encure the desintation profile doesn't exist */
279 ret = ldb_search(ldb_ctx, mem_ctx, &res_dest, ldb_get_default_basedn(ldb_ctx), scope, attrs,
280 "(cn=%s)(cn=Profiles)", profname_dest);
281 /* If profile exists or there is more than one */
282 if (ret == LDB_SUCCESS && res_dest->count) return MAPI_E_COLLISION;
284 /* Step 3. Customize destination profile */
285 dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", profname_dest);
286 basedn = ldb_dn_new(ldb_ctx, ldb_ctx, dn);
288 if (!ldb_dn_validate(basedn)) return MAPI_E_BAD_VALUE;
289 msg->dn = ldb_dn_copy(mem_ctx, basedn);
293 for (i = 0; i < msg->num_elements; i++) {
294 if (el[i].name && !strcmp(el[i].name, "cn")) {
295 el[i].values[0].data = (uint8_t *)talloc_strdup(mem_ctx, profname_dest);
296 el[i].values[0].length = strlen(profname_dest);
300 /* Step 4. Copy the profile */
301 ret = ldb_add(ldb_ctx, msg);
302 /* talloc_free(basedn); */
304 if (ret != LDB_SUCCESS) return MAPI_E_NO_SUPPORT;
306 return MAPI_E_SUCCESS;
311 \details Rename a profile
313 \param mem_ctx pointer on the memory context
314 \param old_profname the old profile name string
315 \param new_profname the new profile name string
317 \return MAPI_E_SUCCESS on success otherwise MAPI error.
319 static enum MAPISTATUS ldb_rename_profile(struct mapi_context *mapi_ctx,
321 const char *old_profname,
322 const char *new_profname)
325 struct ldb_context *ldb_ctx;
326 struct ldb_dn *old_dn;
327 struct ldb_dn *new_dn;
331 OPENCHANGE_RETVAL_IF(!old_profname, MAPI_E_INVALID_PARAMETER, NULL);
332 OPENCHANGE_RETVAL_IF(!new_profname, MAPI_E_INVALID_PARAMETER, NULL);
334 ldb_ctx = mapi_ctx->ldb_ctx;
336 dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", old_profname);
337 old_dn = ldb_dn_new(mem_ctx, ldb_ctx, dn);
340 dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", new_profname);
341 new_dn = ldb_dn_new(mem_ctx, ldb_ctx, dn);
344 ret = ldb_rename(ldb_ctx, old_dn, new_dn);
345 OPENCHANGE_RETVAL_IF(ret, MAPI_E_CORRUPT_STORE, NULL);
347 return MAPI_E_SUCCESS;
356 \details Add an attribute to the profile
358 \param mapi_ctx pointer to the MAPI context
359 \param profile pointer to the profile name
360 \param attr the name of the atribute
361 \param value the value of the attribute
363 _PUBLIC_ enum MAPISTATUS mapi_profile_add_string_attr(struct mapi_context *mapi_ctx,
369 enum ldb_scope scope = LDB_SCOPE_SUBTREE;
370 struct ldb_message msg;
371 struct ldb_message_element el[1];
372 struct ldb_val vals[1][1];
373 struct ldb_result *res;
374 struct ldb_context *ldb_ctx;
375 struct ldb_dn *basedn;
378 const char * const attrs[] = { "*", NULL };
380 OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
381 OPENCHANGE_RETVAL_IF(!mapi_ctx->ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
382 OPENCHANGE_RETVAL_IF(!profile, MAPI_E_BAD_VALUE, NULL);
383 OPENCHANGE_RETVAL_IF(!value, MAPI_E_INVALID_PARAMETER, NULL);
385 mem_ctx = talloc_named(NULL, 0, "mapi_profile_add_string_attr");
386 ldb_ctx = mapi_ctx->ldb_ctx;
388 /* Retrieve the profile from the database */
389 ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs, "(cn=%s)(cn=Profiles)", profile);
390 OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_BAD_VALUE, mem_ctx);
392 /* Preparing for the transaction */
393 dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", profile);
394 basedn = ldb_dn_new(ldb_ctx, ldb_ctx, dn);
396 OPENCHANGE_RETVAL_IF(!ldb_dn_validate(basedn), MAPI_E_BAD_VALUE, mem_ctx);
398 msg.dn = ldb_dn_copy(mem_ctx, basedn);
399 msg.num_elements = 1;
402 el[0].flags = LDB_FLAG_MOD_ADD;
403 el[0].name = talloc_strdup(mem_ctx, attr);
404 el[0].num_values = 1;
405 el[0].values = vals[0];
406 vals[0][0].data = (uint8_t *)talloc_strdup(mem_ctx, value);
407 vals[0][0].length = strlen(value);
409 ret = ldb_modify(ldb_ctx, &msg);
410 OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_SUPPORT, mem_ctx);
412 talloc_free(mem_ctx);
413 return MAPI_E_SUCCESS;
417 \details Modify an attribute
419 \param mapi_ctx pointer to the MAPI context
420 \param profname the name of the profile
421 \param attr the name of the attribute
422 \param value the value of the attribute
424 _PUBLIC_ enum MAPISTATUS mapi_profile_modify_string_attr(struct mapi_context *mapi_ctx,
425 const char *profname,
430 enum ldb_scope scope = LDB_SCOPE_SUBTREE;
431 struct ldb_message msg;
432 struct ldb_message_element el[1];
433 struct ldb_val vals[1][1];
434 struct ldb_result *res;
435 struct ldb_context *ldb_ctx;
436 struct ldb_dn *basedn;
439 const char * const attrs[] = { "*", NULL };
441 OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
442 OPENCHANGE_RETVAL_IF(!profname, MAPI_E_BAD_VALUE, NULL);
444 ldb_ctx = mapi_ctx->ldb_ctx;
445 mem_ctx = talloc_named(NULL, 0, "mapi_profile_modify_string_attr");
447 /* Retrieve the profile from the database */
448 ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs, "(cn=%s)(cn=Profiles)", profname);
449 OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_BAD_VALUE, mem_ctx);
451 /* Preparing for the transaction */
452 dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", profname);
453 basedn = ldb_dn_new(ldb_ctx, ldb_ctx, dn);
455 OPENCHANGE_RETVAL_IF(!ldb_dn_validate(basedn), MAPI_E_BAD_VALUE, mem_ctx);
457 msg.dn = ldb_dn_copy(mem_ctx, basedn);
458 msg.num_elements = 1;
461 el[0].flags = LDB_FLAG_MOD_REPLACE;
462 el[0].name = talloc_strdup(mem_ctx, attr);
463 el[0].num_values = 1;
464 el[0].values = vals[0];
465 vals[0][0].data = (uint8_t *)talloc_strdup(mem_ctx, value);
466 vals[0][0].length = strlen(value);
468 ret = ldb_modify(ldb_ctx, &msg);
469 OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_SUPPORT, mem_ctx);
471 talloc_free(mem_ctx);
473 return MAPI_E_SUCCESS;
477 \details Delete an attribute
479 \param mapi_ctx pointer to the MAPI context
480 \param profname the name of the profile
481 \param attr the name of the attribute
482 \param value the value of the attribute
486 _PUBLIC_ enum MAPISTATUS mapi_profile_delete_string_attr(struct mapi_context *mapi_ctx,
487 const char *profname,
492 enum ldb_scope scope = LDB_SCOPE_SUBTREE;
493 struct ldb_message msg;
494 struct ldb_message_element el[1];
495 struct ldb_val vals[1][1];
496 struct ldb_result *res;
497 struct ldb_context *ldb_ctx;
498 struct ldb_dn *basedn;
501 const char * const attrs[] = { "*", NULL };
504 OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
505 OPENCHANGE_RETVAL_IF(!mapi_ctx->ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
506 OPENCHANGE_RETVAL_IF(!profname, MAPI_E_BAD_VALUE, NULL);
508 ldb_ctx = mapi_ctx->ldb_ctx;
509 mem_ctx = talloc_named(NULL, 0, "mapi_profile_delete_string_attr");
511 /* Retrieve the profile from the database */
512 ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs, "(cn=%s)(cn=Profiles)", profname);
513 OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_BAD_VALUE, mem_ctx);
515 /* Preparing for the transaction */
516 dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", profname);
517 basedn = ldb_dn_new(ldb_ctx, ldb_ctx, dn);
519 OPENCHANGE_RETVAL_IF(!ldb_dn_validate(basedn), MAPI_E_BAD_VALUE, mem_ctx);
521 msg.dn = ldb_dn_copy(mem_ctx, basedn);
522 msg.num_elements = 1;
525 el[0].flags = LDB_FLAG_MOD_DELETE;
526 el[0].name = talloc_strdup(mem_ctx, attr);
527 el[0].num_values = 1;
528 el[0].values = vals[0];
529 vals[0][0].data = (uint8_t *)talloc_strdup(mem_ctx, value);
530 vals[0][0].length = strlen(value);
532 ret = ldb_modify(ldb_ctx, &msg);
533 OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_SUPPORT, mem_ctx);
535 talloc_free(mem_ctx);
537 return MAPI_E_SUCCESS;
541 * Private function which opens the profile store
542 * Should only be called within MAPIInitialize
544 enum MAPISTATUS OpenProfileStore(TALLOC_CTX *mem_ctx, struct ldb_context **ldb_ctx,
545 const char *profiledb)
548 struct ldb_context *tmp_ctx;
549 struct tevent_context *ev;
554 if (!profiledb) return MAPI_E_NOT_FOUND;
556 ev = tevent_context_init(mem_ctx);
557 if (!ev) return MAPI_E_NOT_ENOUGH_RESOURCES;
559 /* connect to the store */
560 tmp_ctx = ldb_init(mem_ctx, ev);
561 if (!tmp_ctx) return MAPI_E_NOT_ENOUGH_RESOURCES;
563 ret = ldb_connect(tmp_ctx, profiledb, 0, NULL);
564 if (ret != LDB_SUCCESS) return MAPI_E_NOT_FOUND;
567 return MAPI_E_SUCCESS;
572 \details Get default ldif_path
574 This function returns the path for the default LDIF files.
576 \sa CreateProfileStore
578 _PUBLIC_ const char *mapi_profile_get_ldif_path(void)
585 \details Create a profile database
587 This function creates a new profile database, including doing an
590 \param profiledb the absolute path to the profile database intended
592 \param ldif_path the absolute path to the LDIF information to use
595 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
597 \note Developers may also call GetLastError() to retrieve the last
598 MAPI error code. Possible MAPI error codes are:
599 - MAPI_E_CALL_FAILED: profiledb or ldif_path is not set
600 - MAPI_E_NOT_ENOUGH_RESOURCES: ldb subsystem initialization failed
601 - MAPI_E_NO_ACCESS: connection or ldif add failed
603 \sa GetLastError, mapi_profile_get_ldif_path
605 _PUBLIC_ enum MAPISTATUS CreateProfileStore(const char *profiledb, const char *ldif_path)
609 struct ldb_context *ldb_ctx;
610 struct ldb_ldif *ldif;
612 char *filename = NULL;
614 struct tevent_context *ev;
616 OPENCHANGE_RETVAL_IF(!profiledb, MAPI_E_CALL_FAILED, NULL);
617 OPENCHANGE_RETVAL_IF(!ldif_path, MAPI_E_CALL_FAILED, NULL);
619 mem_ctx = talloc_named(NULL, 0, "CreateProfileStore");
621 ev = tevent_context_init(mem_ctx);
622 OPENCHANGE_RETVAL_IF(!ev, MAPI_E_NOT_ENOUGH_RESOURCES, mem_ctx);
624 ldb_ctx = ldb_init(mem_ctx, ev);
625 OPENCHANGE_RETVAL_IF(!ldb_ctx, MAPI_E_NOT_ENOUGH_RESOURCES, mem_ctx);
627 url = talloc_asprintf(mem_ctx, "tdb://%s", profiledb);
628 ret = ldb_connect(ldb_ctx, url, 0, 0);
630 OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_ACCESS, mem_ctx);
632 filename = talloc_asprintf(mem_ctx, "%s/oc_profiles_init.ldif", ldif_path);
633 f = fopen(filename, "r");
634 OPENCHANGE_RETVAL_IF(!f, MAPI_E_NO_ACCESS, mem_ctx);
635 talloc_free(filename);
637 while ((ldif = ldb_ldif_read_file(ldb_ctx, f))) {
638 struct ldb_message *normalized_msg;
639 ret = ldb_msg_normalize(ldb_ctx, mem_ctx, ldif->msg, &normalized_msg);
640 OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_ACCESS, mem_ctx);
641 ret = ldb_add(ldb_ctx, normalized_msg);
642 if (ret != LDB_SUCCESS) {
644 OPENCHANGE_RETVAL_ERR(MAPI_E_NO_ACCESS, mem_ctx);
646 ldb_ldif_read_free(ldb_ctx, ldif);
647 talloc_free(normalized_msg);
651 filename = talloc_asprintf(mem_ctx, "%s/oc_profiles_schema.ldif", ldif_path);
652 f = fopen(filename, "r");
653 OPENCHANGE_RETVAL_IF(!f, MAPI_E_NO_ACCESS, mem_ctx);
655 talloc_free(filename);
656 while ((ldif = ldb_ldif_read_file(ldb_ctx, f))) {
657 struct ldb_message *normalized_msg;
658 ret = ldb_msg_normalize(ldb_ctx, mem_ctx, ldif->msg, &normalized_msg);
659 OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_ACCESS, mem_ctx);
660 ret = ldb_add(ldb_ctx, normalized_msg);
661 if (ret != LDB_SUCCESS) {
663 OPENCHANGE_RETVAL_ERR(MAPI_E_NO_ACCESS, mem_ctx);
666 ldb_ldif_read_free(ldb_ctx, ldif);
667 talloc_free(normalized_msg);
671 talloc_free(mem_ctx);
673 return MAPI_E_SUCCESS;
678 \details Load a profile from the database
680 This function opens a named profile from the database, and fills
681 the mapi_profile structure with common profile information.
683 \param mapi_ctx pointer to the MAPI context
684 \param profile the resulting profile
685 \param profname the name of the profile to open
686 \param password the password to use with the profile
688 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
690 \note Developers may also call GetLastError() to retrieve the last
691 MAPI error code. Possible MAPI error codes are:
692 - MAPI_E_NOT_ENOUGH_RESOURCES: ldb subsystem initialization failed
693 - MAPI_E_NOT_FOUND: the profile was not found in the profile
695 - MAPI_E_COLLISION: profname matched more than one entry
697 \sa MAPIInitialize, GetLastError
699 _PUBLIC_ enum MAPISTATUS OpenProfile(struct mapi_context *mapi_ctx,
700 struct mapi_profile *profile,
701 const char *profname,
702 const char *password)
705 enum MAPISTATUS retval;
707 OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
708 OPENCHANGE_RETVAL_IF(!mapi_ctx->ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
710 mem_ctx = (TALLOC_CTX *) mapi_ctx;
712 /* find the profile in ldb store */
713 retval = ldb_load_profile(mem_ctx, mapi_ctx->ldb_ctx, profile, profname, password);
715 OPENCHANGE_RETVAL_IF(retval, retval, NULL);
717 return MAPI_E_SUCCESS;
721 \details Load a MAPI Profile and sets its credentials
723 This function loads a named MAPI profile and sets the MAPI session
726 \param mapi_ctx pointer to the MAPI context
727 \param profile pointer to the MAPI profile
729 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
731 \note Developers may also call GetLastError() to retrieve the last
732 MAPI error code. Possible MAPI error codes are:
733 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
734 - MAPI_E_INVALID_PARAMETER: The profile parameter is not
736 - MAPI_E_NOT_ENOUGH_RESOURCES: MAPI subsystem failed to allocate
737 the necessary resources to perform the operation
739 \sa OpenProfile, GetLastError
741 _PUBLIC_ enum MAPISTATUS LoadProfile(struct mapi_context *mapi_ctx,
742 struct mapi_profile *profile)
747 OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
748 OPENCHANGE_RETVAL_IF(!mapi_ctx->session, MAPI_E_NOT_INITIALIZED, NULL);
749 OPENCHANGE_RETVAL_IF(!profile, MAPI_E_INVALID_PARAMETER, NULL);
751 mem_ctx = (TALLOC_CTX *) mapi_ctx->session;
753 profile->credentials = cli_credentials_init(mem_ctx);
754 OPENCHANGE_RETVAL_IF(!profile->credentials, MAPI_E_NOT_ENOUGH_RESOURCES, NULL);
755 cli_credentials_set_username(profile->credentials, profile->username, CRED_SPECIFIED);
756 cli_credentials_set_password(profile->credentials, profile->password, CRED_SPECIFIED);
757 cli_credentials_set_workstation(profile->credentials, profile->workstation, CRED_SPECIFIED);
758 cli_credentials_set_realm(profile->credentials, profile->realm, CRED_SPECIFIED);
759 cli_credentials_set_domain(profile->credentials, profile->domain, CRED_SPECIFIED);
761 return MAPI_E_SUCCESS;
765 \details Release a profile
767 This function releases the credentials associated with the profile.
769 \param profile the profile to release.
771 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
773 \note Developers may also call GetLastError() to retrieve the last
774 MAPI error code. Possible MAPI error codes are:
775 - MAPI_E_INVALID_PARAMETER: The profile parameter was not set or
778 _PUBLIC_ enum MAPISTATUS ShutDown(struct mapi_profile *profile)
780 OPENCHANGE_RETVAL_IF(!profile, MAPI_E_INVALID_PARAMETER, NULL);
782 if (profile->credentials)
783 talloc_free(profile->credentials);
784 return MAPI_E_SUCCESS;
789 \details Create a profile in the MAPI profile database
791 This function creates a profile named \a profile in the MAPI profile
792 database and sets the specified username in that profile.
794 This function may also set the password. If the flags include
795 OC_PROFILE_NOPASSWORD then the password will not be set. Otherwise,
796 the specified password argument will also be saved to the profile.
798 \param mapi_ctx pointer to the MAPI context
799 \param profile the name of the profile
800 \param username the username of the profile
801 \param password the password for the profile (if used)
802 \param flag the union of the flags.
804 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
806 \note Developers may also call GetLastError() to retrieve the last
807 MAPI error code. Possible MAPI error codes are:
808 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been
809 initialized. The MAPI subsystem must be initialized (using
810 MAPIInitialize) prior to creating a profile.
811 - MAPI_E_NOT_ENOUGH_RESOURCES: MAPI subsystem failed to allocate
812 the necessary resources to operate properly
813 - MAPI_E_NO_SUPPORT: An error was encountered while setting the
814 MAPI profile attributes in the database.
816 \note profile information (including the password, if saved to the
817 profile) is stored unencrypted.
819 \sa DeleteProfile, SetDefaultProfile, GetDefaultProfile,
820 ChangeProfilePassword, GetProfileTable, ProcessNetworkProfile,
823 _PUBLIC_ enum MAPISTATUS CreateProfile(struct mapi_context *mapi_ctx,
825 const char *username,
826 const char *password,
829 enum MAPISTATUS retval;
832 OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
833 OPENCHANGE_RETVAL_IF(!mapi_ctx->ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
835 mem_ctx = talloc_named(NULL, 0, "CreateProfile");
836 retval = ldb_create_profile(mem_ctx, mapi_ctx->ldb_ctx, profile);
837 OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
839 retval = mapi_profile_add_string_attr(mapi_ctx, profile, "username", username);
840 if (flag != OC_PROFILE_NOPASSWORD) {
841 retval = mapi_profile_add_string_attr(mapi_ctx, profile, "password", password);
843 talloc_free(mem_ctx);
850 \details Delete a profile from the MAPI profile database
852 \param mapi_ctx pointer to the MAPI context
853 \param profile the name of the profile to delete
855 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
857 \note Developers may also call GetLastError() to retrieve the last
858 MAPI error code. Possible MAPI error codes are:
859 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been
860 initialized. The MAPI subsystem must be initialized (using
861 MAPIInitialize) prior to creating a profile.
862 - MAPI_E_NOT_FOUND: The profile was not found in the database.
864 \sa CreateProfile, ChangeProfilePassword, GetProfileTable,
865 GetProfileAttr, ProcessNetworkProfile, GetLastError
867 _PUBLIC_ enum MAPISTATUS DeleteProfile(struct mapi_context *mapi_ctx,
871 enum MAPISTATUS retval;
874 OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
875 OPENCHANGE_RETVAL_IF(!mapi_ctx->ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
877 mem_ctx = talloc_named(NULL, 0, "DeleteProfile");
878 retval = ldb_delete_profile(mem_ctx, mapi_ctx->ldb_ctx, profile);
879 OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
880 talloc_free(mem_ctx);
887 \details Change the profile password of an existing MAPI profile
889 \param mapi_ctx pointer to the MAPI context
890 \param profile the name of the profile to have its password changed
891 \param old_password the old password
892 \param password the new password
894 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
896 \note Developers may also call GetLastError() to retrieve the last
897 MAPI error code. Possible MAPI error codes are:
898 - MAPI_E_INVALID_PARAMETER: One of the following argument was not
899 set: profile, old_password, password
900 - MAPI_E_NOT_FOUND: The profile was not found in the database
902 \sa CreateProfile, GetProfileTable, GetProfileAttr,
903 ProcessNetworkProfile, GetLastError
905 _PUBLIC_ enum MAPISTATUS ChangeProfilePassword(struct mapi_context *mapi_ctx,
907 const char *old_password,
908 const char *password)
911 enum MAPISTATUS retval;
914 OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
915 OPENCHANGE_RETVAL_IF(!profile || !old_password ||
916 !password, MAPI_E_INVALID_PARAMETER, NULL);
918 mem_ctx = talloc_named(NULL, 0, "ChangeProfilePassword");
920 retval = ldb_test_password(mapi_ctx, mem_ctx, profile, password);
921 OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
923 retval = mapi_profile_modify_string_attr(mapi_ctx, profile, "password", password);
925 talloc_free(mem_ctx);
930 \details Copy a profile
932 \param mapi_ctx pointer to the MAPI context
933 \param profile_src the source profile to copy from
934 \param profile_dst the destination profile to copy to
936 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
938 _PUBLIC_ enum MAPISTATUS CopyProfile(struct mapi_context *mapi_ctx,
939 const char *profile_src,
940 const char *profile_dst)
943 enum MAPISTATUS retval;
946 OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
947 OPENCHANGE_RETVAL_IF(!mapi_ctx->ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
948 OPENCHANGE_RETVAL_IF(!profile_src, MAPI_E_INVALID_PARAMETER, NULL);
949 OPENCHANGE_RETVAL_IF(!profile_dst, MAPI_E_INVALID_PARAMETER, NULL);
951 mem_ctx = talloc_named(NULL, 0, "CopyProfile");
953 retval = ldb_copy_profile(mem_ctx, mapi_ctx->ldb_ctx, profile_src, profile_dst);
954 OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
956 talloc_free(mem_ctx);
962 \details Duplicate an existing profile.
964 The username specified in parameter is used to customize the new
965 profile. This function should only be used in environments where
966 users are within the same administrative group, storage group,
967 server etc. Otherwise this will create an invalid profile and may
968 cause unpredictable results.
970 \param mapi_ctx pointer to the MAPI context
971 \param profile_src the source profile to duplicate from
972 \param profile_dst the destination profile to duplicate to
973 \param username the username to replace within the destination
976 \return MAPI_E_SUCCESS on success, otherwise MAPI error
978 _PUBLIC_ enum MAPISTATUS DuplicateProfile(struct mapi_context *mapi_ctx,
979 const char *profile_src,
980 const char *profile_dst,
981 const char *username)
984 enum MAPISTATUS retval;
985 char *username_src = NULL;
986 char *EmailAddress = NULL;
987 char *ProxyAddress = NULL;
988 struct mapi_profile profile;
989 char **attr_tmp = NULL;
995 OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
996 OPENCHANGE_RETVAL_IF(!profile_src, MAPI_E_INVALID_PARAMETER, NULL);
997 OPENCHANGE_RETVAL_IF(!profile_dst, MAPI_E_INVALID_PARAMETER, NULL);
998 OPENCHANGE_RETVAL_IF(!username, MAPI_E_INVALID_PARAMETER, NULL);
1000 /* Step 1. Copy the profile */
1001 retval = CopyProfile(mapi_ctx, profile_src, profile_dst);
1002 OPENCHANGE_RETVAL_IF(retval, retval, NULL);
1004 /* retrieve username, EmailAddress and ProxyAddress */
1005 retval = OpenProfile(mapi_ctx, &profile, profile_src, NULL);
1006 OPENCHANGE_RETVAL_IF(retval, MAPI_E_NOT_FOUND, NULL);
1008 mem_ctx = talloc_named(NULL, 0, "DuplicateProfile");
1010 retval = GetProfileAttr(&profile, "username", &count, &attr_tmp);
1011 OPENCHANGE_RETVAL_IF(retval || !count, MAPI_E_NOT_FOUND, mem_ctx);
1012 username_src = talloc_strdup(mem_ctx, attr_tmp[0]);
1013 talloc_free(attr_tmp[0]);
1015 retval = GetProfileAttr(&profile, "EmailAddress", &count, &attr_tmp);
1016 OPENCHANGE_RETVAL_IF(retval || !count, MAPI_E_NOT_FOUND, mem_ctx);
1017 EmailAddress = talloc_strdup(mem_ctx, attr_tmp[0]);
1018 talloc_free(attr_tmp[0]);
1020 retval = GetProfileAttr(&profile, "ProxyAddress", &count, &attr_tmp);
1021 OPENCHANGE_RETVAL_IF(retval, MAPI_E_NOT_FOUND, mem_ctx);
1022 ProxyAddress = talloc_strdup(mem_ctx, attr_tmp[0]);
1023 talloc_free(attr_tmp[0]);
1025 /* Change EmailAddress */
1030 for (i = strlen(EmailAddress); i > 0; i--) {
1031 if (EmailAddress[i] == '=') {
1032 tmp = talloc_strndup(mem_ctx, EmailAddress, i + 1);
1036 OPENCHANGE_RETVAL_IF(!tmp, MAPI_E_INVALID_PARAMETER, mem_ctx);
1038 attr = talloc_asprintf(mem_ctx, "%s%s", tmp, username);
1040 mapi_profile_modify_string_attr(mapi_ctx, profile_dst, "EmailAddress", attr);
1044 /* Change ProxyAddress */
1046 tmp = strstr(ProxyAddress, username_src);
1047 attr = talloc_strndup(mem_ctx, ProxyAddress, strlen(ProxyAddress) - strlen(tmp));
1048 tmp += strlen(username_src);
1049 attr = talloc_asprintf_append(attr, "%s%s", username, tmp);
1050 mapi_profile_modify_string_attr(mapi_ctx, profile_dst, "ProxyAddress", attr);
1054 /* Step 2. Change parameters but cn (already changed) */
1055 mapi_profile_modify_string_attr(mapi_ctx, profile_dst, "name", profile_dst);
1056 mapi_profile_modify_string_attr(mapi_ctx, profile_dst, "username", username);
1057 mapi_profile_modify_string_attr(mapi_ctx, profile_dst, "DisplayName", username);
1058 mapi_profile_modify_string_attr(mapi_ctx, profile_dst, "Account", username);
1060 talloc_free(mem_ctx);
1062 return MAPI_E_SUCCESS;
1066 \details Rename a profile
1068 \param mapi_ctx pointer to the MAPI context
1069 \param old_profile old profile name
1070 \param profile new profile name
1072 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1074 _PUBLIC_ enum MAPISTATUS RenameProfile(struct mapi_context *mapi_ctx,
1075 const char *old_profile,
1076 const char *profile)
1078 TALLOC_CTX *mem_ctx;
1079 enum MAPISTATUS retval;
1080 struct SRowSet proftable;
1081 struct SPropValue *lpProp;
1082 struct ldb_message *msg = NULL;
1089 OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1090 OPENCHANGE_RETVAL_IF(!old_profile, MAPI_E_INVALID_PARAMETER, NULL);
1091 OPENCHANGE_RETVAL_IF(!profile, MAPI_E_INVALID_PARAMETER, NULL);
1093 mem_ctx = mapi_ctx->mem_ctx;
1095 retval = GetProfileTable(mapi_ctx, &proftable);
1096 OPENCHANGE_RETVAL_IF(retval, retval, NULL);
1098 /* Step 1. Check if old profile exists */
1099 for (found = false, i = 0; i < proftable.cRows; i++) {
1100 lpProp = get_SPropValue_SRow(&(proftable.aRow[i]), PR_DISPLAY_NAME);
1101 if (lpProp && !strcmp(lpProp->value.lpszA, old_profile)) {
1105 OPENCHANGE_RETVAL_IF(found == false, MAPI_E_NOT_FOUND, proftable.aRow);
1107 /* Step 2. Check if new profile already exists */
1108 for (found = false, i = 0; i < proftable.cRows; i++) {
1109 lpProp = get_SPropValue_SRow(&(proftable.aRow[i]), PR_DISPLAY_NAME);
1110 if (lpProp && !strcmp(lpProp->value.lpszA, profile)) {
1114 talloc_free(proftable.aRow);
1115 OPENCHANGE_RETVAL_IF(found == true, MAPI_E_INVALID_PARAMETER, NULL);
1117 /* Step 3. Rename the profile */
1118 retval = ldb_rename_profile(mapi_ctx, mem_ctx, old_profile, profile);
1119 OPENCHANGE_RETVAL_IF(retval, retval, NULL);
1121 /* Step 4. Change name and cn */
1122 msg = ldb_msg_new(mem_ctx);
1123 dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", profile);
1124 msg->dn = ldb_dn_new(mem_ctx, mapi_ctx->ldb_ctx, dn);
1127 ret = ldb_msg_add_string(msg, "cn", profile);
1128 ret = ldb_msg_add_string(msg, "name", profile);
1129 for (i = 0; i < msg->num_elements; i++) {
1130 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1133 OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_CORRUPT_STORE, NULL);
1134 ret = ldb_modify(mapi_ctx->ldb_ctx, msg);
1135 OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_CORRUPT_STORE, NULL);
1137 return MAPI_E_SUCCESS;
1142 \details Set a default profile for the database
1144 \param mapi_ctx pointer to the MAPI context
1145 \param profname the name of the profile to make the default profile
1147 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1149 \note Developers may also call GetLastError() to retrieve the last
1150 MAPI error code. Possible MAPI error codes are:
1151 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
1152 - MAPI_E_INVALID_PARAMETER: The profile parameter was not set
1154 - MAPI_E_NOT_FOUND: The profile was not found in the database
1156 \sa GetDefaultProfile, GetProfileTable, GetLastError
1158 _PUBLIC_ enum MAPISTATUS SetDefaultProfile(struct mapi_context *mapi_ctx,
1159 const char *profname)
1161 TALLOC_CTX *mem_ctx;
1162 struct mapi_profile profile;
1163 enum MAPISTATUS retval;
1166 OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1167 OPENCHANGE_RETVAL_IF(!mapi_ctx->ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1168 OPENCHANGE_RETVAL_IF(!profname, MAPI_E_INVALID_PARAMETER, NULL);
1170 mem_ctx = talloc_named(NULL, 0, "SetDefaultProfile");
1173 retval = ldb_load_profile(mem_ctx, mapi_ctx->ldb_ctx, &profile, profname, NULL);
1174 OPENCHANGE_RETVAL_IF(retval && retval != MAPI_E_INVALID_PARAMETER, retval, mem_ctx);
1176 /* search any previous default profile and unset it */
1177 retval = ldb_clear_default_profile(mapi_ctx, mem_ctx);
1179 /* set profname as the default profile */
1180 retval = mapi_profile_modify_string_attr(mapi_ctx, profname, "PR_DEFAULT_PROFILE", "1");
1182 talloc_free(mem_ctx);
1189 \details Get the default profile from the database
1191 \param mapi_ctx pointer to the MAPI context
1192 \param profname the result of the function (name of the default
1195 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1197 \note Developers may also call GetLastError() to retrieve the last
1198 MAPI error code. Possible MAPI error codes are:
1199 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
1200 - MAPI_E_NOT_FOUND: The profile was not found in the database
1202 \note On success GetDefaultProfile profname string is allocated. It
1203 is up to the developer to free it when not needed anymore.
1205 \sa SetDefaultProfile, GetProfileTable, GetLastError
1207 _PUBLIC_ enum MAPISTATUS GetDefaultProfile(struct mapi_context *mapi_ctx,
1210 enum MAPISTATUS retval;
1211 struct SRowSet proftable;
1212 struct SPropValue *lpProp;
1216 OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1218 retval = GetProfileTable(mapi_ctx, &proftable);
1219 OPENCHANGE_RETVAL_IF(retval, retval, NULL);
1221 for (i = 0; i < proftable.cRows; i++) {
1222 lpProp = get_SPropValue_SRow(&(proftable.aRow[i]), PR_DEFAULT_PROFILE);
1223 if (lpProp && (lpProp->value.l == 1)) {
1224 lpProp = get_SPropValue_SRow(&(proftable.aRow[i]), PR_DISPLAY_NAME);
1226 *profname = talloc_strdup(mapi_ctx->mem_ctx, lpProp->value.lpszA);
1227 talloc_free(proftable.aRow);
1228 return MAPI_E_SUCCESS;
1233 OPENCHANGE_RETVAL_ERR(MAPI_E_NOT_FOUND, proftable.aRow);
1238 \details Retrieve the profile table
1240 This function retrieves the profile table. Two fields are returned:
1241 - PR_DISPLAY_NAME: The profile name stored as a UTF8 string
1242 - PR_DEFAULT_PROFILE: Whether the profile is the default one(1) or
1243 not(0), stored as an integer
1245 \param mapi_ctx pointer to the MAPI context
1246 \param proftable the result of the call
1248 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1250 \note Developers may also call GetLastError() to retrieve the last
1251 MAPI error code. Possible MAPI error codes are:
1252 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
1253 - MAPI_E_NOT_FOUND: The profile was not found in the database
1255 \sa SetDefaultProfile, GetLastError
1257 _PUBLIC_ enum MAPISTATUS GetProfileTable(struct mapi_context *mapi_ctx,
1258 struct SRowSet *proftable)
1260 TALLOC_CTX *mem_ctx;
1261 enum ldb_scope scope = LDB_SCOPE_SUBTREE;
1262 struct ldb_context *ldb_ctx;
1263 struct ldb_result *res;
1264 struct ldb_message *msg;
1265 struct ldb_dn *basedn;
1266 const char *attrs[] = {"cn", "PR_DEFAULT_PROFILE", NULL};
1270 OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1272 ldb_ctx = mapi_ctx->ldb_ctx;
1273 mem_ctx = talloc_autofree_context();
1275 basedn = ldb_dn_new(ldb_ctx, ldb_ctx, "CN=Profiles");
1276 ret = ldb_search(ldb_ctx, mem_ctx, &res, basedn, scope, attrs, "(cn=*)");
1277 talloc_free(basedn);
1278 OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NOT_FOUND, NULL);
1281 proftable->cRows = res->count;
1282 proftable->aRow = talloc_array(mapi_ctx->mem_ctx, struct SRow, res->count);
1284 /* Build Arow array */
1285 for (count = 0; count < res->count; count++) {
1286 msg = res->msgs[count];
1288 proftable->aRow[count].lpProps = talloc_array((TALLOC_CTX *)proftable->aRow, struct SPropValue, 2);
1289 proftable->aRow[count].cValues = 2;
1291 proftable->aRow[count].lpProps[0].ulPropTag = PR_DISPLAY_NAME;
1292 proftable->aRow[count].lpProps[0].value.lpszA = talloc_strdup((TALLOC_CTX *)proftable->aRow,
1293 ldb_msg_find_attr_as_string(msg, "cn", NULL));
1295 proftable->aRow[count].lpProps[1].ulPropTag = PR_DEFAULT_PROFILE;
1296 proftable->aRow[count].lpProps[1].value.l = ldb_msg_find_attr_as_int(msg, "PR_DEFAULT_PROFILE", 0);
1301 return MAPI_E_SUCCESS;
1306 \details Retrieve attribute values from a profile
1308 This function retrieves all the attribute values from the given
1309 profile. The number of results is stored in \a count and values
1310 are stored in an allocated string array in the \a value parameter
1311 that needs to be free'd using MAPIFreeBuffer().
1313 \param profile the name of the profile to retrieve attributes from
1314 \param attribute the attribute(s) to search for
1315 \param count the number of results
1316 \param value the resulting values
1318 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1320 \note Developers may also call GetLastError() to retrieve the last
1321 MAPI error code. Possible MAPI error codes are:
1322 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
1323 - MAPI_E_INVALID_PARAMETER: Either profile or attribute was not set
1325 - MAPI_E_NOT_FOUND: The profile was not found in the database
1327 \sa SetDefaultProfile, GetDefaultProfile, MAPIFreeBuffer,
1328 GetProfileTable, GetLastError
1330 _PUBLIC_ enum MAPISTATUS GetProfileAttr(struct mapi_profile *profile,
1331 const char *attribute,
1332 unsigned int *count,
1335 TALLOC_CTX *mem_ctx;
1336 struct mapi_context *mapi_ctx;
1337 struct ldb_context *ldb_ctx;
1338 struct ldb_result *res;
1339 struct ldb_message *msg;
1340 struct ldb_message_element *ldb_element;
1341 struct ldb_dn *basedn;
1342 const char *attrs[] = {"*", NULL};
1347 OPENCHANGE_RETVAL_IF(!profile, MAPI_E_INVALID_PARAMETER, NULL);
1348 OPENCHANGE_RETVAL_IF(!attribute, MAPI_E_INVALID_PARAMETER, NULL);
1350 mapi_ctx = profile->mapi_ctx;
1351 OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1352 OPENCHANGE_RETVAL_IF(!mapi_ctx->ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1354 mem_ctx = (TALLOC_CTX *)mapi_ctx->ldb_ctx;
1355 ldb_ctx = mapi_ctx->ldb_ctx;
1357 basedn = ldb_dn_new(ldb_ctx, ldb_ctx, "CN=Profiles");
1359 ret = ldb_search(ldb_ctx, mem_ctx, &res, basedn, LDB_SCOPE_SUBTREE, attrs, "(cn=%s)", profile->profname);
1360 OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NOT_FOUND, NULL);
1363 ldb_element = ldb_msg_find_element(msg, attribute);
1365 DEBUG(3, ("ldb_msg_find_element: NULL\n"));
1366 return MAPI_E_NOT_FOUND;
1369 *count = ldb_element[0].num_values;
1370 value[0] = talloc_array(mem_ctx, char *, *count);
1373 value[0][0] = talloc_strdup(value[0],
1374 ldb_msg_find_attr_as_string(msg, attribute, NULL));
1376 for (i = 0; i < *count; i++) {
1377 value[0][i] = talloc_strdup(mem_ctx, (char *)ldb_element->values[i].data);
1381 return MAPI_E_SUCCESS;
1385 \details Search the value of an attribute within a given profile
1387 \param profile pointer to the MAPI profile
1388 \param attribute pointer to the attribute name
1389 \param value pointer to the attribute value
1391 \return MAPI_E_SUCCESS on success, otherwise MAPI error
1393 _PUBLIC_ enum MAPISTATUS FindProfileAttr(struct mapi_profile *profile,
1394 const char *attribute,
1397 TALLOC_CTX *mem_ctx;
1398 struct mapi_context *mapi_ctx;
1399 struct ldb_context *ldb_ctx;
1400 struct ldb_result *res;
1401 struct ldb_message *msg;
1402 struct ldb_message_element *ldb_element;
1404 struct ldb_dn *basedn;
1405 const char *attrs[] = {"*", NULL};
1408 OPENCHANGE_RETVAL_IF(!profile, MAPI_E_INVALID_PARAMETER, NULL);
1409 OPENCHANGE_RETVAL_IF(!attribute, MAPI_E_INVALID_PARAMETER, NULL);
1410 OPENCHANGE_RETVAL_IF(!value, MAPI_E_INVALID_PARAMETER, NULL);
1412 mapi_ctx = profile->mapi_ctx;
1413 OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1414 OPENCHANGE_RETVAL_IF(!mapi_ctx->ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1416 mem_ctx = (TALLOC_CTX *)mapi_ctx->ldb_ctx;
1417 ldb_ctx = mapi_ctx->ldb_ctx;
1419 basedn = ldb_dn_new(ldb_ctx, ldb_ctx, "CN=Profiles");
1421 ret = ldb_search(ldb_ctx, mem_ctx, &res, basedn, LDB_SCOPE_SUBTREE, attrs, "(CN=%s)", profile->profname);
1422 OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NOT_FOUND, NULL);
1423 OPENCHANGE_RETVAL_IF(!res->count, MAPI_E_NOT_FOUND, NULL);
1426 ldb_element = ldb_msg_find_element(msg, attribute);
1427 OPENCHANGE_RETVAL_IF(!ldb_element, MAPI_E_NOT_FOUND, NULL);
1429 val.data = (uint8_t *)talloc_strdup(mem_ctx, value);
1430 val.length = strlen(value);
1431 OPENCHANGE_RETVAL_IF(!ldb_msg_find_val(ldb_element, &val), MAPI_E_NOT_FOUND, NULL);
1433 return MAPI_E_SUCCESS;
1440 static bool set_profile_attribute(struct mapi_context *mapi_ctx,
1441 const char *profname,
1442 struct SRowSet rowset,
1447 struct SPropValue *lpProp;
1448 enum MAPISTATUS ret;
1450 lpProp = get_SPropValue_SRow(&(rowset.aRow[index]), property);
1453 DEBUG(3, ("MAPI Property %s not set\n", attr));
1457 ret = mapi_profile_add_string_attr(mapi_ctx, profname, attr, lpProp->value.lpszA);
1459 if (ret != MAPI_E_SUCCESS) {
1460 DEBUG(3, ("Problem adding attribute %s in profile %s\n", attr, profname));
1466 static bool set_profile_mvstr_attribute(struct mapi_context *mapi_ctx,
1467 const char *profname,
1468 struct SRowSet rowset,
1473 struct SPropValue *lpProp;
1474 enum MAPISTATUS ret;
1477 lpProp = get_SPropValue_SRow(&(rowset.aRow[index]), property);
1480 DEBUG(3, ("MAPI Property %s not set\n", attr));
1484 for (i = 0; i < lpProp->value.MVszA.cValues; i++) {
1485 ret = mapi_profile_add_string_attr(mapi_ctx, profname, attr, lpProp->value.MVszA.lppszA[i]);
1486 if (ret != MAPI_E_SUCCESS) {
1487 DEBUG(3, ("Problem adding attribute %s in profile %s\n", attr, profname));
1496 \details Process a full and automated MAPI profile creation
1498 This function process a full and automated MAPI profile creation
1499 using the \a username pattern passed as a parameter. The functions
1500 takes a callback parameter which will be called when the username
1501 checked matches several usernames. Private data needed by the
1502 callback can be supplied using the private_data pointer.
1505 typedef int (*mapi_callback_t) callback(struct SRowSet *, void *private_data);
1508 The callback returns the SRow element index within the SRowSet
1509 structure. If the user cancels the operation the callback return
1510 value should be SRowSet->cRows or more.
1512 \param session the session context
1513 \param username the username for the network profile
1514 \param callback function pointer callback function
1515 \param private_data context data that will be provided to the callback
1517 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1519 \note Developers may also call GetLastError() to retrieve the last
1520 MAPI error code. Possible MAPI error codes are:
1522 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been
1523 initialized. The MAPI subsystem must be initialized (using
1524 MAPIInitialize) prior to creating a profile.
1525 - MAPI_E_END_OF_SESSION: The NSPI session has not been initialized
1526 - MAPI_E_CANCEL_USER: The user has aborted the operation
1527 - MAPI_E_INVALID_PARAMETER: The profile parameter was not set
1529 - MAPI_E_NOT_FOUND: One of the mandatory field was not found during
1530 the profile creation process.
1532 \sa OpenProfileStore, MAPILogonProvider, GetLastError
1534 _PUBLIC_ enum MAPISTATUS ProcessNetworkProfile(struct mapi_session *session,
1535 const char *username,
1536 mapi_profile_callback_t callback,
1537 const void *private_data)
1539 TALLOC_CTX *mem_ctx;
1540 enum MAPISTATUS retval;
1541 struct mapi_context *mapi_ctx;
1542 struct nspi_context *nspi;
1543 struct SPropTagArray *SPropTagArray = NULL;
1544 struct Restriction_r Filter;
1545 struct SRowSet *SRowSet;
1546 struct SPropValue *lpProp = NULL;
1547 struct SPropTagArray *MIds = NULL;
1548 struct SPropTagArray MIds2;
1549 struct SPropTagArray *MId_server = NULL;
1550 struct StringsArray_r pNames;
1551 const char *profname;
1552 uint32_t instance_key = 0;
1555 OPENCHANGE_RETVAL_IF(!session, MAPI_E_NOT_INITIALIZED, NULL);
1556 OPENCHANGE_RETVAL_IF(!session->nspi->ctx, MAPI_E_END_OF_SESSION, NULL);
1557 OPENCHANGE_RETVAL_IF(!session->mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1559 mapi_ctx = session->mapi_ctx;
1561 mem_ctx = talloc_named(NULL, 0, "ProcessNetworkProfile");
1562 nspi = (struct nspi_context *) session->nspi->ctx;
1563 profname = session->profile->profname;
1566 SRowSet = talloc_zero(mem_ctx, struct SRowSet);
1567 retval = nspi_GetSpecialTable(nspi, mem_ctx, 0x0, &SRowSet);
1568 MAPIFreeBuffer(SRowSet);
1569 OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1571 SPropTagArray = set_SPropTagArray(mem_ctx, 0xc,
1573 PR_OFFICE_TELEPHONE_NUMBER,
1586 /* Retrieve the username to match */
1588 username = cli_credentials_get_username(nspi->cred);
1589 OPENCHANGE_RETVAL_IF(!username, MAPI_E_INVALID_PARAMETER, mem_ctx);
1592 /* Build the restriction we want for NspiGetMatches */
1593 lpProp = talloc_zero(mem_ctx, struct SPropValue);
1594 lpProp->ulPropTag = PR_ANR_UNICODE;
1595 lpProp->dwAlignPad = 0;
1596 lpProp->value.lpszW = username;
1598 Filter.rt = (enum RestrictionType_r)RES_PROPERTY;
1599 Filter.res.resProperty.relop = RES_PROPERTY;
1600 Filter.res.resProperty.ulPropTag = PR_ANR_UNICODE;
1601 Filter.res.resProperty.lpProp = lpProp;
1603 SRowSet = talloc_zero(mem_ctx, struct SRowSet);
1604 MIds = talloc_zero(mem_ctx, struct SPropTagArray);
1605 retval = nspi_GetMatches(nspi, mem_ctx, SPropTagArray, &Filter, &SRowSet, &MIds);
1606 MAPIFreeBuffer(SPropTagArray);
1607 MAPIFreeBuffer(lpProp);
1608 if (retval != MAPI_E_SUCCESS) {
1609 MAPIFreeBuffer(MIds);
1610 MAPIFreeBuffer(SRowSet);
1611 talloc_free(mem_ctx);
1615 /* if there's no match */
1616 OPENCHANGE_RETVAL_IF(!SRowSet, MAPI_E_NOT_FOUND, mem_ctx);
1617 OPENCHANGE_RETVAL_IF(!SRowSet->cRows, MAPI_E_NOT_FOUND, mem_ctx);
1618 OPENCHANGE_RETVAL_IF(!MIds, MAPI_E_NOT_FOUND, mem_ctx);
1620 /* if SRowSet count is superior than 1 an callback is specified, call it */
1621 if (SRowSet->cRows > 1 && callback) {
1622 index = callback(SRowSet, private_data);
1623 OPENCHANGE_RETVAL_IF((index >= SRowSet->cRows), MAPI_E_USER_CANCEL, mem_ctx);
1624 instance_key = MIds->aulPropTag[index];
1626 instance_key = MIds->aulPropTag[0];
1628 MAPIFreeBuffer(MIds);
1630 MIds2.cValues = 0x1;
1631 MIds2.aulPropTag = (enum MAPITAGS *) &instance_key;
1633 set_profile_attribute(mapi_ctx, profname, *SRowSet, index, PR_EMAIL_ADDRESS, "EmailAddress");
1634 set_profile_attribute(mapi_ctx, profname, *SRowSet, index, PR_DISPLAY_NAME, "DisplayName");
1635 set_profile_attribute(mapi_ctx, profname, *SRowSet, index, PR_ACCOUNT, "Account");
1636 set_profile_attribute(mapi_ctx, profname, *SRowSet, index, PR_ADDRTYPE, "AddrType");
1638 SPropTagArray = set_SPropTagArray(mem_ctx, 0x7,
1644 PR_PROFILE_HOME_SERVER_ADDRS,
1645 PR_EMS_AB_PROXY_ADDRESSES
1648 nspi->pStat->CurrentRec = 0x0;
1649 nspi->pStat->Delta = 0x0;
1650 nspi->pStat->NumPos = 0x0;
1651 nspi->pStat->TotalRecs = 0x1;
1653 MAPIFreeBuffer(SRowSet);
1654 SRowSet = talloc(mem_ctx, struct SRowSet);
1655 retval = nspi_QueryRows(nspi, mem_ctx, SPropTagArray, &MIds2, 1, &SRowSet);
1656 MAPIFreeBuffer(SPropTagArray);
1657 OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1659 lpProp = get_SPropValue_SRowSet(SRowSet, PR_EMS_AB_HOME_MDB);
1660 OPENCHANGE_RETVAL_IF(!lpProp, MAPI_E_NOT_FOUND, mem_ctx);
1662 nspi->org = x500_get_dn_element(mem_ctx, lpProp->value.lpszA, ORG);
1663 nspi->org_unit = x500_get_dn_element(mem_ctx, lpProp->value.lpszA, ORG_UNIT);
1665 OPENCHANGE_RETVAL_IF(!nspi->org_unit, MAPI_E_INVALID_PARAMETER, mem_ctx);
1666 OPENCHANGE_RETVAL_IF(!nspi->org, MAPI_E_INVALID_PARAMETER, mem_ctx);
1668 retval = mapi_profile_add_string_attr(mapi_ctx, profname, "Organization", nspi->org);
1669 retval = mapi_profile_add_string_attr(mapi_ctx, profname, "OrganizationUnit", nspi->org_unit);
1671 nspi->servername = x500_get_servername(lpProp->value.lpszA);
1672 mapi_profile_add_string_attr(mapi_ctx, profname, "ServerName", nspi->servername);
1673 set_profile_attribute(mapi_ctx, profname, *SRowSet, 0, PR_EMS_AB_HOME_MDB, "HomeMDB");
1674 set_profile_mvstr_attribute(mapi_ctx, profname, *SRowSet, 0, PR_EMS_AB_PROXY_ADDRESSES, "ProxyAddress");
1677 pNames.Strings = (const char **) talloc_array(mem_ctx, char **, 1);
1678 pNames.Strings[0] = (const char *) talloc_asprintf(mem_ctx, SERVER_DN,
1679 nspi->org, nspi->org_unit,
1681 MId_server = talloc_zero(mem_ctx, struct SPropTagArray);
1682 retval = nspi_DNToMId(nspi, mem_ctx, &pNames, &MId_server);
1683 MAPIFreeBuffer((char *)pNames.Strings[0]);
1684 MAPIFreeBuffer((char **)pNames.Strings);
1685 OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1687 MAPIFreeBuffer(SRowSet);
1688 SRowSet = talloc_zero(mem_ctx, struct SRowSet);
1689 SPropTagArray = set_SPropTagArray(mem_ctx, 0x1, PR_EMS_AB_NETWORK_ADDRESS);
1690 retval = nspi_GetProps(nspi, mem_ctx, SPropTagArray, MId_server, &SRowSet);
1691 MAPIFreeBuffer(SPropTagArray);
1692 MAPIFreeBuffer(MId_server);
1693 OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1695 set_profile_mvstr_attribute(mapi_ctx, profname, *SRowSet, 0, PR_EMS_AB_NETWORK_ADDRESS, "NetworkAddress");
1696 MAPIFreeBuffer(SRowSet);
1697 talloc_free(mem_ctx);
1699 return MAPI_E_SUCCESS;