Prevent from trying to add a NULL element to profile database and segfault on strlen
[jelmer/openchange-proposed.git/.git] / libmapi / IProfAdmin.c
1 /*
2    OpenChange MAPI implementation.
3
4    Copyright (C) Julien Kerihuel 2007-2008.
5    Copyright (C) Fabien Le Mentec 2007.
6
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.
11    
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.
16    
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/>.
19  */
20
21 #include <libmapi/libmapi.h>
22 #include <libmapi/proto_private.h>
23 #include <credentials.h>
24 #include <ldb_errors.h>
25 #include <ldb.h>
26
27 /**
28    \file IProfAdmin.c
29
30    \brief MAPI Profiles interface
31  */
32
33 /*
34  * Private functions
35  */
36
37 /**
38  * Load a MAPI profile into a mapi_profile struct
39  */
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)
44 {
45         int                     ret;
46         enum ldb_scope          scope = LDB_SCOPE_SUBTREE;
47         struct ldb_result       *res;
48         struct ldb_message      *msg;
49         const char * const      attrs[] = { "*", NULL };
50
51         /* fills in profile name */
52         profile->profname = talloc_strdup(mem_ctx, profname);
53         if (!profile->profname) return MAPI_E_NOT_ENOUGH_RESOURCES;
54
55         /* ldb query */
56         ldb_ctx = global_mapi_ctx->ldb_ctx;
57
58         ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs, "(cn=%s)(cn=Profiles)", profile->profname);
59         if (ret != LDB_SUCCESS) return MAPI_E_NOT_FOUND;
60
61         /* profile not found */
62         if (!res->count) return MAPI_E_NOT_FOUND;
63         /* more than one profile */
64         if (res->count > 1) return MAPI_E_COLLISION;
65
66         /* fills in profile with query result */
67         msg = res->msgs[0];
68
69         profile->username = ldb_msg_find_attr_as_string(msg, "username", NULL);
70         profile->password = password ? password : ldb_msg_find_attr_as_string(msg, "password", "");
71         profile->workstation = ldb_msg_find_attr_as_string(msg, "workstation", NULL);
72         profile->realm = ldb_msg_find_attr_as_string(msg, "realm", NULL);
73         profile->domain = ldb_msg_find_attr_as_string(msg, "domain", NULL);
74         profile->mailbox = ldb_msg_find_attr_as_string(msg, "EmailAddress", NULL);
75         profile->homemdb = ldb_msg_find_attr_as_string(msg, "HomeMDB", NULL);
76         profile->server = ldb_msg_find_attr_as_string(msg, "binding", NULL);
77         profile->org = ldb_msg_find_attr_as_string(msg, "Organization", NULL);
78         profile->ou = ldb_msg_find_attr_as_string(msg, "OrganizationUnit", NULL);
79         profile->codepage = ldb_msg_find_attr_as_int(msg, "codepage", 0);
80         profile->language = ldb_msg_find_attr_as_int(msg, "language", 0);
81         profile->method = ldb_msg_find_attr_as_int(msg, "method", 0);
82
83         if (!profile->password) return MAPI_E_INVALID_PARAMETER;
84
85         return MAPI_E_SUCCESS;
86 }
87
88 /**
89  * Search for and attribute within profiles
90  */
91 static enum MAPISTATUS ldb_clear_default_profile(TALLOC_CTX *mem_ctx)
92 {
93         enum ldb_scope          scope = LDB_SCOPE_SUBTREE;
94         struct ldb_context      *ldb_ctx;
95         struct ldb_dn           *basedn;
96         struct ldb_message      *msg;
97         struct ldb_result       *res;
98         const char              *attrs[] = { "PR_DEFAULT_PROFILE", NULL };
99         int                     ret;
100         uint32_t                i;
101
102         ldb_ctx = global_mapi_ctx->ldb_ctx;
103
104         basedn = ldb_dn_new(ldb_ctx, ldb_ctx, "CN=Profiles");
105         ret = ldb_search(ldb_ctx, mem_ctx, &res, basedn, scope, attrs, "(cn=*)");
106         
107         if (ret != LDB_SUCCESS) return MAPI_E_NOT_FOUND;
108         if (!res->count) return MAPI_E_NOT_FOUND;
109
110         for (i = 0; i < res->count; i++) {
111                 struct ldb_message              *message;
112
113                 msg = res->msgs[i];
114                 if (msg->num_elements == 1) {
115                         message = talloc_steal(mem_ctx, msg);
116                         message->elements[0].flags = LDB_FLAG_MOD_DELETE;
117
118                         ret = ldb_modify(ldb_ctx, message);
119                         talloc_free(message);
120                 }
121         }
122         
123         return MAPI_E_SUCCESS;
124 }
125
126 /**
127  * Test if the password is correct
128  */
129 static enum MAPISTATUS ldb_test_password(TALLOC_CTX *mem_ctx, const char *profile, 
130                                          const char *password)
131 {
132         enum ldb_scope          scope = LDB_SCOPE_DEFAULT;
133         struct ldb_context      *ldb_ctx;
134         struct ldb_message      *msg;
135         struct ldb_result       *res;
136         const char              *attrs[] = {"cn", "password", NULL };
137         const char              *ldb_password;
138         int                     ret;
139
140         ldb_ctx = global_mapi_ctx->ldb_ctx;
141         
142         ret = ldb_search(ldb_ctx, mem_ctx, &res, NULL, scope, attrs, 
143                                          "(cn=%s)(cn=Profiles)", profile);
144
145         if (ret != LDB_SUCCESS) return MAPI_E_NO_SUPPORT;
146         if (!res->count) return MAPI_E_NOT_FOUND;
147         
148         msg = res->msgs[0];
149         
150         ldb_password = ldb_msg_find_attr_as_string(msg, "password", NULL);
151         if (!ldb_password) return MAPI_E_NO_SUPPORT;
152         if (strncmp(password, ldb_password, strlen(password))) return MAPI_E_LOGON_FAILED;
153         
154         return MAPI_E_SUCCESS;
155 }
156
157
158 /*
159  * Add a profile to the database with default fields
160  */
161 static enum MAPISTATUS ldb_create_profile(TALLOC_CTX *mem_ctx,
162                                           struct ldb_context *ldb_ctx,
163                                           const char *profname)
164 {
165         enum ldb_scope                  scope = LDB_SCOPE_SUBTREE;
166         struct ldb_message              msg;
167         struct ldb_message_element      el[2];
168         struct ldb_val                  vals[2][1];
169         struct ldb_result               *res;
170         struct ldb_dn                   *basedn;
171         char                            *dn;
172         int                             ret;
173         const char * const              attrs[] = { "*", NULL };
174
175         /* Sanity check */
176         if (profname == NULL) 
177                 return MAPI_E_BAD_VALUE;
178
179         /* Does the profile already exists? */
180         ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), 
181                                          scope, attrs, "(cn=%s)(cn=Profiles)", profname);
182         if (res->msgs) return MAPI_E_NO_ACCESS;
183
184         /*
185          * We now prepare the entry for transaction
186          */
187         
188         dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", profname);
189         basedn = ldb_dn_new(ldb_ctx, ldb_ctx, dn);
190         talloc_free(dn);
191         if (!ldb_dn_validate(basedn)) return MAPI_E_BAD_VALUE;
192
193         msg.dn = ldb_dn_copy(mem_ctx, basedn);
194         msg.num_elements = 2;
195         msg.elements = el;
196
197         el[0].flags = 0;
198         el[0].name = talloc_strdup(mem_ctx, "cn");
199         el[0].num_values = 1;
200         el[0].values = vals[0];
201         vals[0][0].data = (uint8_t *)talloc_strdup(mem_ctx, profname);
202         vals[0][0].length = strlen(profname);
203
204         el[1].flags = 0;
205         el[1].name = talloc_strdup(mem_ctx, "name");
206         el[1].num_values = 1;
207         el[1].values = vals[1];
208         vals[1][0].data = (uint8_t *)talloc_strdup(mem_ctx, profname);
209         vals[1][0].length = strlen(profname);
210
211         ret = ldb_add(ldb_ctx, &msg);
212
213         if (ret != LDB_SUCCESS) return MAPI_E_NO_SUPPORT;
214
215         return MAPI_E_SUCCESS;
216 }
217
218 /*
219  * delete the current profile
220  */
221 static enum MAPISTATUS ldb_delete_profile(TALLOC_CTX *mem_ctx,
222                                           struct ldb_context *ldb_ctx,
223                                           const char *profname)
224 {
225         enum ldb_scope          scope = LDB_SCOPE_SUBTREE;
226         struct ldb_result       *res;
227         const char * const      attrs[] = { "*", NULL };
228         int                     ret;
229
230         ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs, "(cn=%s)(cn=Profiles)", profname);
231         if (!res->msgs) return MAPI_E_NOT_FOUND;
232
233         ret = ldb_delete(ldb_ctx, res->msgs[0]->dn);
234         if (ret != LDB_SUCCESS) return MAPI_E_NOT_FOUND;
235         
236         return MAPI_E_SUCCESS;
237 }
238
239 /*
240  * Public interface
241  */
242
243 /**
244    \details Add an attribute to the profile
245  */
246 _PUBLIC_ enum MAPISTATUS mapi_profile_add_string_attr(const char *profile, 
247                                                       const char *attr, 
248                                                       const char *value)
249 {
250         TALLOC_CTX                      *mem_ctx;
251         enum ldb_scope                  scope = LDB_SCOPE_SUBTREE;
252         struct ldb_message              msg;
253         struct ldb_message_element      el[1];
254         struct ldb_val                  vals[1][1];
255         struct ldb_result               *res;
256         struct ldb_context              *ldb_ctx;
257         struct ldb_dn                   *basedn;
258         char                            *dn;
259         int                             ret;
260         const char * const              attrs[] = { "*", NULL };
261
262         MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
263         MAPI_RETVAL_IF(!global_mapi_ctx->ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
264         MAPI_RETVAL_IF(!profile, MAPI_E_BAD_VALUE, NULL);
265         MAPI_RETVAL_IF(!value, MAPI_E_INVALID_PARAMETER, NULL);
266
267         mem_ctx = talloc_init("mapi_profile_add_string_attr");
268         ldb_ctx = global_mapi_ctx->ldb_ctx;
269
270         /* Retrieve the profile from the database */
271         ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs, "(cn=%s)(cn=Profiles)", profile);
272         MAPI_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_BAD_VALUE, mem_ctx);
273
274         /* Preparing for the transaction */
275         dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", profile);
276         basedn = ldb_dn_new(ldb_ctx, ldb_ctx, dn);
277         talloc_free(dn);
278         MAPI_RETVAL_IF(!ldb_dn_validate(basedn), MAPI_E_BAD_VALUE, mem_ctx);
279
280         msg.dn = ldb_dn_copy(mem_ctx, basedn);
281         msg.num_elements = 1;
282         msg.elements = el;
283
284         el[0].flags = LDB_FLAG_MOD_ADD;
285         el[0].name = talloc_strdup(mem_ctx, attr);
286         el[0].num_values = 1;
287         el[0].values = vals[0];
288         vals[0][0].data = (uint8_t *)talloc_strdup(mem_ctx, value);
289         vals[0][0].length = strlen(value);
290
291         ret = ldb_modify(ldb_ctx, &msg);
292         MAPI_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_SUPPORT, mem_ctx);
293         
294         talloc_free(mem_ctx);
295         return MAPI_E_SUCCESS;
296 }
297
298 /**
299    \details Modify an attribute
300  */
301 _PUBLIC_ enum MAPISTATUS mapi_profile_modify_string_attr(const char *profname, 
302                                                          const char *attr, 
303                                                          const char *value)
304 {
305         TALLOC_CTX                      *mem_ctx;
306         enum ldb_scope                  scope = LDB_SCOPE_SUBTREE;
307         struct ldb_message              msg;
308         struct ldb_message_element      el[1];
309         struct ldb_val                  vals[1][1];
310         struct ldb_result               *res;
311         struct ldb_context              *ldb_ctx;
312         struct ldb_dn                   *basedn;
313         char                            *dn;
314         int                             ret;
315         const char * const              attrs[] = { "*", NULL };
316
317         MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
318         MAPI_RETVAL_IF(!profname, MAPI_E_BAD_VALUE, NULL);
319
320         ldb_ctx = global_mapi_ctx->ldb_ctx;
321         mem_ctx = talloc_init("mapi_profile_modify_string_attr");
322
323         /* Retrieve the profile from the database */
324         ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs, "(cn=%s)(cn=Profiles)", profname);
325         MAPI_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_BAD_VALUE, mem_ctx);
326
327         /* Preparing for the transaction */
328         dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", profname);
329         basedn = ldb_dn_new(ldb_ctx, ldb_ctx, dn);
330         talloc_free(dn);
331         MAPI_RETVAL_IF(!ldb_dn_validate(basedn), MAPI_E_BAD_VALUE, mem_ctx);
332
333         msg.dn = ldb_dn_copy(mem_ctx, basedn);
334         msg.num_elements = 1;
335         msg.elements = el;
336
337         el[0].flags = LDB_FLAG_MOD_REPLACE;
338         el[0].name = talloc_strdup(mem_ctx, attr);
339         el[0].num_values = 1;
340         el[0].values = vals[0];
341         vals[0][0].data = (uint8_t *)talloc_strdup(mem_ctx, value);
342         vals[0][0].length = strlen(value);
343
344         ret = ldb_modify(ldb_ctx, &msg);
345         MAPI_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_SUPPORT, mem_ctx);
346
347         talloc_free(mem_ctx);
348         
349         return MAPI_E_SUCCESS;
350 }
351
352 /**
353    \details Delete an attribute
354  */
355 _PUBLIC_ enum MAPISTATUS mapi_profile_delete_string_attr(const char *profname, 
356                                                          const char *attr, 
357                                                          const char *value)
358 {
359         TALLOC_CTX                      *mem_ctx;
360         enum ldb_scope                  scope = LDB_SCOPE_SUBTREE;
361         struct ldb_message              msg;
362         struct ldb_message_element      el[1];
363         struct ldb_val                  vals[1][1];
364         struct ldb_result               *res;
365         struct ldb_context              *ldb_ctx;
366         struct ldb_dn                   *basedn;
367         char                            *dn;
368         int                             ret;
369         const char * const              attrs[] = { "*", NULL };
370
371         MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
372         MAPI_RETVAL_IF(!profname, MAPI_E_BAD_VALUE, NULL);
373
374         ldb_ctx = global_mapi_ctx->ldb_ctx;
375         mem_ctx = talloc_init("mapi_profile_delete_string_attr");
376
377         /* Retrieve the profile from the database */
378         ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs, "(cn=%s)(cn=Profiles)", profname);
379         MAPI_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_BAD_VALUE, mem_ctx);
380
381         /* Preparing for the transaction */
382         dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", profname);
383         basedn = ldb_dn_new(ldb_ctx, ldb_ctx, dn);
384         talloc_free(dn);
385         MAPI_RETVAL_IF(!ldb_dn_validate(basedn), MAPI_E_BAD_VALUE, mem_ctx);
386
387         msg.dn = ldb_dn_copy(mem_ctx, basedn);
388         msg.num_elements = 1;
389         msg.elements = el;
390
391         el[0].flags = LDB_FLAG_MOD_DELETE;
392         el[0].name = talloc_strdup(mem_ctx, attr);
393         el[0].num_values = 1;
394         el[0].values = vals[0];
395         vals[0][0].data = (uint8_t *)talloc_strdup(mem_ctx, value);
396         vals[0][0].length = strlen(value);
397
398         ret = ldb_modify(ldb_ctx, &msg);
399         MAPI_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_SUPPORT, mem_ctx);
400
401         talloc_free(mem_ctx);
402         
403         return MAPI_E_SUCCESS;
404 }
405
406 /*
407  * Private function which opens the profile store
408  * Should only be called within MAPIInitialize
409  */
410 enum MAPISTATUS OpenProfileStore(TALLOC_CTX *mem_ctx, struct ldb_context **ldb_ctx, 
411                                  const char *profiledb)
412 {
413         int                     ret;
414         struct ldb_context      *tmp_ctx;
415         struct event_context *ev;
416         
417         *ldb_ctx = 0;
418         
419         /* store path */
420         if (!profiledb) return MAPI_E_NOT_FOUND;
421
422         ev = event_context_init(mem_ctx);
423         if (!ev) return MAPI_E_NOT_ENOUGH_RESOURCES;
424
425         /* connect to the store */
426         tmp_ctx = ldb_init(mem_ctx, ev);
427         if (!tmp_ctx) return MAPI_E_NOT_ENOUGH_RESOURCES;
428
429         ret = ldb_connect(tmp_ctx, profiledb, 0, NULL);
430         if (ret != LDB_SUCCESS) return MAPI_E_NOT_FOUND;
431
432         *ldb_ctx = tmp_ctx;
433         return MAPI_E_SUCCESS;
434 }
435
436
437 /**
438    \details Get default ldif_path
439
440    This function returns the path for the default LDIF files.
441
442    \sa CreateProfileStore
443 */
444 _PUBLIC_ const char *mapi_profile_get_ldif_path(void)
445 {
446         return DEFAULT_LDIF;
447 }
448
449
450 /**
451    \details Create a profile database
452    
453    This function creates a new profile database, including doing an
454    initial setup.
455
456    \param profiledb the absolute path to the profile database intended
457    to be created
458    \param ldif_path the absolute path to the LDIF information to use
459    for initial setup.
460
461    \return MAPI_E_SUCCESS on success, otherwise -1.
462  
463    \note Developers should call GetLastError() to retrieve the last
464    MAPI error code. Possible MAPI error codes are:
465    - MAPI_E_CALL_FAILED: profiledb or ldif_path is not set
466    - MAPI_E_NOT_ENOUGH_RESOURCES: ldb subsystem initialization failed
467    - MAPI_E_NO_ACCESS: connection or ldif add failed
468
469    \sa GetLastError, mapi_profile_get_ldif_path
470 */
471 _PUBLIC_ enum MAPISTATUS CreateProfileStore(const char *profiledb, const char *ldif_path)
472 {
473         int                     ret;
474         TALLOC_CTX              *mem_ctx;
475         struct ldb_context      *ldb_ctx;
476         struct ldb_ldif         *ldif;
477         char                    *url = NULL;
478         char                    *filename = NULL;
479         FILE                    *f;
480         struct event_context *ev;
481
482         MAPI_RETVAL_IF(!profiledb, MAPI_E_CALL_FAILED, NULL);
483         MAPI_RETVAL_IF(!ldif_path, MAPI_E_CALL_FAILED, NULL);
484
485         mem_ctx = talloc_init("CreateProfileStore");
486
487         ev = event_context_init(mem_ctx);
488         MAPI_RETVAL_IF(!ev, MAPI_E_NOT_ENOUGH_RESOURCES, mem_ctx);
489
490         ldb_ctx = ldb_init(mem_ctx, ev);
491         MAPI_RETVAL_IF(!ldb_ctx, MAPI_E_NOT_ENOUGH_RESOURCES, mem_ctx);
492
493         url = talloc_asprintf(mem_ctx, "tdb://%s", profiledb);
494         ret = ldb_connect(ldb_ctx, url, 0, 0);
495         talloc_free(url);
496         MAPI_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_ACCESS, mem_ctx);
497
498         filename = talloc_asprintf(mem_ctx, "%s/oc_profiles_init.ldif", ldif_path);
499         f = fopen(filename, "r");
500         MAPI_RETVAL_IF(!f, MAPI_E_NO_ACCESS, mem_ctx);
501         talloc_free(filename);
502
503         while ((ldif = ldb_ldif_read_file(ldb_ctx, f))) {
504                 ldif->msg = ldb_msg_canonicalize(ldb_ctx, ldif->msg);
505                 ret = ldb_add(ldb_ctx, ldif->msg);
506                 if (ret != LDB_SUCCESS) {
507                         fclose(f);
508                         MAPI_RETVAL_IF("ldb_ldif_read_file", MAPI_E_NO_ACCESS, mem_ctx);
509                 }
510                 ldb_ldif_read_free(ldb_ctx, ldif);
511         }
512         fclose(f);
513
514         filename = talloc_asprintf(mem_ctx, "%s/oc_profiles_schema.ldif", ldif_path);
515         f = fopen(filename, "r");
516         MAPI_RETVAL_IF(!f, MAPI_E_NO_ACCESS, mem_ctx);
517
518         talloc_free(filename);
519         while ((ldif = ldb_ldif_read_file(ldb_ctx, f))) {
520                 ldif->msg = ldb_msg_canonicalize(ldb_ctx, ldif->msg);
521                 ret = ldb_add(ldb_ctx, ldif->msg);
522                 if (ret != LDB_SUCCESS) {
523                         fclose(f);
524                         MAPI_RETVAL_IF("ldb_ldif_read_file", MAPI_E_NO_ACCESS, mem_ctx);
525                 }
526
527                 ldb_ldif_read_free(ldb_ctx, ldif);
528         }
529         fclose(f);
530
531         talloc_free(mem_ctx);
532
533         return MAPI_E_SUCCESS;
534 }
535
536
537 /**
538    \details Load a profile from the database
539
540    This function opens a named profile from the database, and fills
541    the mapi_profile structure with common profile information.
542
543    \param profile the resulting profile
544    \param profname the name of the profile to open
545    \param password the password to use with the profile
546
547    \return MAPI_E_SUCCESS on success, otherwise -1.
548
549    \note Developers should call GetLastError() to retrieve the last
550    MAPI error code. Possible MAPI error codes are:
551    - MAPI_E_NOT_ENOUGH_RESOURCES: ldb subsystem initialization failed
552    - MAPI_E_NOT_FOUND: the profile was not found in the profile
553      database
554    - MAPI_E_COLLISION: profname matched more than one entry
555
556    \sa MAPIInitialize, GetLastError
557 */
558 _PUBLIC_ enum MAPISTATUS OpenProfile(struct mapi_profile *profile, const char *profname, const char *password)
559 {
560         TALLOC_CTX      *mem_ctx;
561         enum MAPISTATUS retval;
562
563         MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
564
565         mem_ctx = (TALLOC_CTX *) global_mapi_ctx->session;
566         
567         /* find the profile in ldb store */
568         retval = ldb_load_profile(mem_ctx, global_mapi_ctx->ldb_ctx, profile, profname, password);
569
570         MAPI_RETVAL_IF(retval, retval, NULL);
571
572         return MAPI_E_SUCCESS;  
573 }
574
575 /**
576    \details Load a MAPI Profile and sets its credentials
577
578    This function loads a named MAPI profile and sets the MAPI session
579    credentials.
580
581    \return MAPI_E_SUCCESS on success, otherwise -1.
582
583    \note Developers should call GetLastError() to retrieve the last
584    MAPI error code. Possible MAPI error codes are:
585    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
586    - MAPI_E_INVALID_PARAMETER: The profile parameter is not
587      initialized
588    - MAPI_E_NOT_ENOUGH_RESOURCES: MAPI subsystem failed to allocate
589      the necessary resources to perform the operation
590
591    \sa OpenProfile, GetLastError
592  */
593 _PUBLIC_ enum MAPISTATUS LoadProfile(struct mapi_profile *profile)
594 {
595         TALLOC_CTX *mem_ctx;
596
597         MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
598         MAPI_RETVAL_IF(!profile, MAPI_E_INVALID_PARAMETER, NULL);
599
600         mem_ctx = (TALLOC_CTX *) global_mapi_ctx->session;
601
602         profile->credentials = cli_credentials_init(mem_ctx);
603         MAPI_RETVAL_IF(!profile->credentials, MAPI_E_NOT_ENOUGH_RESOURCES, NULL);
604         cli_credentials_set_username(profile->credentials, profile->username, CRED_SPECIFIED);
605         cli_credentials_set_password(profile->credentials, profile->password, CRED_SPECIFIED);
606         cli_credentials_set_workstation(profile->credentials, profile->workstation, CRED_SPECIFIED);
607         cli_credentials_set_realm(profile->credentials, profile->realm, CRED_SPECIFIED);
608         cli_credentials_set_domain(profile->credentials, profile->domain, CRED_SPECIFIED);
609
610         return MAPI_E_SUCCESS;
611 }
612
613 /**
614    \details Release a profile
615
616    This function releases the credentials associated with the profile.
617
618    \param profile the profile to release.
619
620    \return MAPI_E_SUCCESS on success, otherwise -1.
621
622    \note Developers should call GetLastError() to retrieve the last
623    MAPI error code. Possible MAPI error codes are:
624    - MAPI_E_INVALID_PARAMETER: The profile parameter was not set or
625      not valid
626  */
627 _PUBLIC_ enum MAPISTATUS ShutDown(struct mapi_profile *profile)
628 {
629         MAPI_RETVAL_IF(!profile, MAPI_E_INVALID_PARAMETER, NULL);
630
631         if (profile->credentials) 
632                 talloc_free(profile->credentials);
633         return MAPI_E_SUCCESS;
634 }
635
636
637 /**
638    \details Create a profile in the MAPI profile database
639
640    This function creates a profile named \a profile in the MAPI profile
641    database and sets the specified username in that profile.
642
643    This function may also set the password. If the flags include
644    OC_PROFILE_NOPASSWORD then the password will not be set. Otherwise,
645    the specified password argument will also be saved to the profile.
646
647    \param profile the name of the profile
648    \param username the username of the profile
649    \param password the password for the profile (if used)
650    \param flag the union of the flags. 
651
652    \return MAPI_E_SUCCESS on success, otherwise -1.
653
654    \note Developers should call GetLastError() to retrieve the last
655    MAPI error code. Possible MAPI error codes are:
656    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been
657      initialized. The MAPI subsystem must be initialized (using
658      MAPIInitialize) prior to creating a profile.
659    - MAPI_E_NOT_ENOUGH_RESOURCES: MAPI subsystem failed to allocate
660      the necessary resources to operate properly
661    - MAPI_E_NO_SUPPORT: An error was encountered while setting the
662      MAPI profile attributes in the database.
663
664    \note profile information (including the password, if saved to the
665    profile) is stored unencrypted.
666
667    \sa DeleteProfile, SetDefaultProfile, GetDefaultProfile,
668    ChangeProfilePassword, GetProfileTable, ProcessNetworkProfile,
669    GetLastError
670  */
671 _PUBLIC_ enum MAPISTATUS CreateProfile(const char *profile, const char *username,
672                                        const char *password, uint32_t flag)
673 {
674         enum MAPISTATUS retval;
675         TALLOC_CTX      *mem_ctx;
676
677         MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
678
679         mem_ctx = talloc_init("CreateProfile");
680         retval = ldb_create_profile(mem_ctx, global_mapi_ctx->ldb_ctx, profile);
681         MAPI_RETVAL_IF(retval, retval, mem_ctx);
682
683         retval = mapi_profile_add_string_attr(profile, "username", username);
684         if (flag != OC_PROFILE_NOPASSWORD) {
685                 retval = mapi_profile_add_string_attr(profile, "password", password);
686         }
687         talloc_free(mem_ctx);
688
689         return retval;
690 }
691
692
693 /**
694    \details Delete a profile from the MAPI profile database
695
696    \param profile the name of the profile to delete
697
698    \return MAPI_E_SUCCESS on success, otherwise -1.
699
700    \note Developers should call GetLastError() to retrieve the last
701    MAPI error code. Possible MAPI error codes are:
702    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been
703      initialized. The MAPI subsystem must be initialized (using
704      MAPIInitialize) prior to creating a profile.
705    - MAPI_E_NOT_FOUND: The profile was not found in the database.
706
707    \sa CreateProfile, ChangeProfilePassword, GetProfileTable,
708    GetProfileAttr, ProcessNetworkProfile, GetLastError
709 */
710 _PUBLIC_ enum MAPISTATUS DeleteProfile(const char *profile)
711 {
712         TALLOC_CTX      *mem_ctx;
713         enum MAPISTATUS retval;
714
715         MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
716
717         mem_ctx = talloc_init("DeleteProfile");
718         retval = ldb_delete_profile(mem_ctx, global_mapi_ctx->ldb_ctx, profile);
719         MAPI_RETVAL_IF(retval, retval, mem_ctx);
720         talloc_free(mem_ctx);
721
722         return retval;
723 }
724
725
726 /**
727    \details Change the profile password of an existing MAPI profile
728
729    \param profile the name of the profile to have its password changed
730    \param old_password the old password
731    \param password the new password
732
733    \return MAPI_E_SUCCESS on success, otherwise -1.
734
735    \note Developers should call GetLastError() to retrieve the last
736    MAPI error code. Possible MAPI error codes are:
737    - MAPI_E_INVALID_PARAMETER: One of the following argument was not
738      set: profile, old_password, password
739    - MAPI_E_NOT_FOUND: The profile was not found in the database
740
741    \sa CreateProfile, GetProfileTable, GetProfileAttr,
742    ProcessNetworkProfile, GetLastError
743  */
744 _PUBLIC_ enum MAPISTATUS ChangeProfilePassword(const char *profile, 
745                                                const char *old_password,
746                                                const char *password)
747 {
748         TALLOC_CTX              *mem_ctx;
749         enum MAPISTATUS         retval;
750
751         if (!profile || !old_password | !password) return MAPI_E_INVALID_PARAMETER;
752
753         mem_ctx = talloc_init("ChangeProfilePassword");
754
755         retval = ldb_test_password(mem_ctx, profile, password);
756         MAPI_RETVAL_IF(retval, retval, mem_ctx);
757
758         retval = mapi_profile_modify_string_attr(profile, "password", password);
759         
760         talloc_free(mem_ctx);
761         return retval;
762 }
763
764 /*
765  * Copies a profile
766  */
767 _PUBLIC_ enum MAPISTATUS CopyProfile(const char *old_profile, 
768                                      const char *password,
769                                      const char *profile)
770 {
771         old_profile = NULL;
772         password = NULL;
773         profile = NULL;
774         return MAPI_E_SUCCESS;
775         /* return MAPI_E_LOGON_FAILED => auth failure */
776         /* return MAPI_E_ACCESS_DENIED => the new profile already exists */
777         /* return MAPI_E_NOT_FOUND => old profile doesn't exist */
778 }
779
780 /*
781  * Rename a profile
782  */
783 _PUBLIC_ enum MAPISTATUS RenameProfile(const char *old_profile, 
784                                        const char *password,
785                                        const char *profile)
786 {
787         old_profile = NULL;
788         password = NULL;
789         profile = NULL;
790         return MAPI_E_SUCCESS;
791         /* return MAPI_E_LOGON_FAILED => auth failure*/
792 }
793
794
795 /**
796    \details Set a default profile for the database
797
798    \param profname the name of the profile to make the default profile
799
800    \return MAPI_E_SUCCESS on success, otherwise -1.
801
802    \note Developers should call GetLastError() to retrieve the last
803    MAPI error code. Possible MAPI error codes are:
804    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
805    - MAPI_E_INVALID_PARAMETER: The profile parameter was not set
806      properly.
807    - MAPI_E_NOT_FOUND: The profile was not found in the database
808
809    \sa GetDefaultProfile, GetProfileTable, GetLastError
810  */
811 _PUBLIC_ enum MAPISTATUS SetDefaultProfile(const char *profname)
812 {
813         TALLOC_CTX              *mem_ctx;
814         struct mapi_profile     profile;
815         enum MAPISTATUS         retval;
816
817         MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
818         MAPI_RETVAL_IF(!profname, MAPI_E_INVALID_PARAMETER, NULL);
819
820         mem_ctx = talloc_init("SetDefaultProfile");
821
822         /* open profile */
823         retval = ldb_load_profile(mem_ctx, global_mapi_ctx->ldb_ctx, &profile, profname, NULL);
824         MAPI_RETVAL_IF(retval && retval != MAPI_E_INVALID_PARAMETER, retval, mem_ctx);
825
826         /* search any previous default profile and unset it */
827         retval = ldb_clear_default_profile(mem_ctx);
828
829         /* set profname as the default profile */
830         retval = mapi_profile_modify_string_attr(profname, "PR_DEFAULT_PROFILE", "1");
831
832         talloc_free(mem_ctx);
833
834         return retval;
835 }
836
837
838 /**
839    \details Get the default profile from the database
840
841    \param profname the result of the function (name of the default
842    profile)
843
844    \return MAPI_E_SUCCESS on success, otherwise -1.
845
846    \note Developers should call GetLastError() to retrieve the last
847    MAPI error code. Possible MAPI error codes are:
848    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
849    - MAPI_E_NOT_FOUND: The profile was not found in the database
850
851    \sa SetDefaultProfile, GetProfileTable, GetLastError
852 */
853 _PUBLIC_ enum MAPISTATUS GetDefaultProfile(const char **profname)
854 {
855         enum MAPISTATUS         retval;
856         struct SRowSet          proftable;
857         struct SPropValue       *lpProp;
858         uint32_t                i;
859         
860
861         MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
862         
863         retval = GetProfileTable(&proftable);
864
865         for (i = 0; i < proftable.cRows; i++) {
866                 lpProp = get_SPropValue_SRow(&(proftable.aRow[i]), PR_DEFAULT_PROFILE);
867                 if (lpProp && (lpProp->value.l == 1)) {
868                         lpProp = get_SPropValue_SRow(&(proftable.aRow[i]), PR_DISPLAY_NAME);
869                         if (lpProp) {
870                                 *profname = lpProp->value.lpszA;
871                                 talloc_free(proftable.aRow);
872                                 return MAPI_E_SUCCESS;
873                         }
874                 }
875         }
876         
877         MAPI_RETVAL_IF("GetDefaultProfile", MAPI_E_NOT_FOUND, proftable.aRow);
878 }
879
880 /**
881    \details Retrieve a pointer on the mapi_profile structure used in
882    the given session
883  */
884 _PUBLIC_ enum MAPISTATUS GetProfilePtr(struct mapi_profile *profile)
885 {
886         MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
887
888         profile = global_mapi_ctx->session->profile;
889
890         return MAPI_E_SUCCESS;
891 }
892
893
894 /**
895    \details Retrieve the profile table
896
897    This function retrieves the profile table. Two fields are returned:
898    - PR_DISPLAY_NAME: The profile name stored as a UTF8 string
899    - PR_DEFAULT_PROFILE: Whether the profile is the default one(1) or
900      not(0), stored as an integer
901
902    \param proftable the result of the call
903
904    \return MAPI_E_SUCCESS on success, otherwise -1.
905
906    \note Developers should call GetLastError() to retrieve the last
907    MAPI error code. Possible MAPI error codes are:
908    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
909    - MAPI_E_NOT_FOUND: The profile was not found in the database
910
911    \sa SetDefaultProfile, GetProfileTable, GetLastError
912  */
913 _PUBLIC_ enum MAPISTATUS GetProfileTable(struct SRowSet *proftable)
914 {
915         TALLOC_CTX                      *mem_ctx;
916         enum ldb_scope                  scope = LDB_SCOPE_SUBTREE;
917         struct ldb_context              *ldb_ctx;
918         struct ldb_result               *res;
919         struct ldb_message              *msg;
920         struct ldb_dn                   *basedn;
921         const char                      *attrs[] = {"cn", "PR_DEFAULT_PROFILE", NULL};
922         int                             ret;
923         uint32_t                        count;
924
925         MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
926
927         ldb_ctx = global_mapi_ctx->ldb_ctx;
928         mem_ctx = (TALLOC_CTX *)ldb_ctx;
929
930         basedn = ldb_dn_new(ldb_ctx, ldb_ctx, "CN=Profiles");
931         ret = ldb_search(ldb_ctx, mem_ctx, &res, basedn, scope, attrs, "(cn=*)");
932         MAPI_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NOT_FOUND, NULL);
933
934         /* Allocate Arow */
935         proftable->cRows = res->count;
936         proftable->aRow = talloc_array(mem_ctx, struct SRow, res->count);
937
938         /* Build Arow array */
939         for (count = 0; count < res->count; count++) {
940                 msg = res->msgs[count];
941                 
942                 proftable->aRow[count].lpProps = talloc_array(mem_ctx, struct SPropValue, 2);
943                 proftable->aRow[count].cValues = 2;
944
945                 proftable->aRow[count].lpProps[0].ulPropTag = PR_DISPLAY_NAME;
946                 proftable->aRow[count].lpProps[0].value.lpszA = ldb_msg_find_attr_as_string(msg, "cn", NULL);
947
948                 proftable->aRow[count].lpProps[1].ulPropTag = PR_DEFAULT_PROFILE;
949                 proftable->aRow[count].lpProps[1].value.l = ldb_msg_find_attr_as_int(msg, "PR_DEFAULT_PROFILE", 0);
950         }
951
952         return MAPI_E_SUCCESS;
953 }
954
955
956 /**
957    \details Retrieve attribute values from a profile
958
959    This function retrieves all the attribute values from the given
960    profile.  The number of results is stored in \a count and values
961    are stored in an allocated string array in the \a value parameter
962    that needs to be free'd using MAPIFreeBuffer().
963    
964    \param profile the name of the profile to retrieve attributes from
965    \param attribute the attribute(s) to search for
966    \param count the number of results
967    \param value the resulting values
968    
969    \return MAPI_E_SUCCESS on success, otherwise -1.
970
971    \note Developers should call GetLastError() to retrieve the last
972    MAPI error code. Possible MAPI error codes are:
973    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
974    - MAPI_E_INVALID_PARAMETER: Either profile or attribute was not set
975      properly
976    - MAPI_E_NOT_FOUND: The profile was not found in the database
977
978    \sa SetDefaultProfile, GetDefaultProfile, MAPIFreeBuffer,
979    GetProfileTable, GetLastError
980 */
981 _PUBLIC_ enum MAPISTATUS GetProfileAttr(struct mapi_profile *profile, 
982                                         const char *attribute, 
983                                         unsigned int *count,
984                                         char ***value)
985 {
986         TALLOC_CTX                      *mem_ctx;
987         struct ldb_context              *ldb_ctx;
988         struct ldb_result               *res;
989         struct ldb_message              *msg;
990         struct ldb_message_element      *ldb_element;
991         struct ldb_dn                   *basedn;
992         const char                      *attrs[] = {"*", NULL};
993         int                             ret;
994         uint32_t                        i;
995
996         MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
997         MAPI_RETVAL_IF(!profile, MAPI_E_INVALID_PARAMETER, NULL);
998         MAPI_RETVAL_IF(!attribute, MAPI_E_INVALID_PARAMETER, NULL);
999
1000         mem_ctx = (TALLOC_CTX *)global_mapi_ctx->ldb_ctx;
1001         ldb_ctx = global_mapi_ctx->ldb_ctx;
1002
1003         basedn = ldb_dn_new(ldb_ctx, ldb_ctx, "CN=Profiles");
1004
1005         ret = ldb_search(ldb_ctx, mem_ctx, &res, basedn, LDB_SCOPE_SUBTREE, attrs, "(cn=%s)", profile->profname);
1006         MAPI_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NOT_FOUND, NULL);
1007
1008         msg = res->msgs[0];
1009         ldb_element = ldb_msg_find_element(msg, attribute);
1010         if (!ldb_element) {
1011                 DEBUG(3, ("ldb_msg_find_element: NULL\n"));
1012                 return MAPI_E_NOT_FOUND;
1013         }
1014
1015         *count = ldb_element[0].num_values;
1016         value[0] = talloc_array(mem_ctx, char *, *count);
1017
1018         if (*count == 1) {
1019                 value[0][0] = talloc_strdup(value[0], 
1020                                                 ldb_msg_find_attr_as_string(msg, attribute, NULL));
1021         } else {
1022                 for (i = 0; i < *count; i++) {
1023                         value[0][i] = talloc_strdup(mem_ctx, (char *)ldb_element->values[i].data);
1024                 }
1025         }
1026
1027         return MAPI_E_SUCCESS;
1028 }
1029
1030 /**
1031    \details Search the value of an attribute within a given profile
1032  */
1033 _PUBLIC_ enum MAPISTATUS FindProfileAttr(struct mapi_profile *profile, const char *attribute, const char *value)
1034 {
1035         TALLOC_CTX                      *mem_ctx;
1036         struct ldb_context              *ldb_ctx;
1037         struct ldb_result               *res;
1038         struct ldb_message              *msg;
1039         struct ldb_message_element      *ldb_element;
1040         struct ldb_val                  val;
1041         struct ldb_dn                   *basedn;
1042         const char                      *attrs[] = {"*", NULL};
1043         int                             ret;
1044
1045         MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1046         MAPI_RETVAL_IF(!profile, MAPI_E_INVALID_PARAMETER, NULL);
1047         MAPI_RETVAL_IF(!attribute, MAPI_E_INVALID_PARAMETER, NULL);
1048         MAPI_RETVAL_IF(!value, MAPI_E_INVALID_PARAMETER, NULL);
1049
1050         mem_ctx = (TALLOC_CTX *)global_mapi_ctx->ldb_ctx;
1051         ldb_ctx = global_mapi_ctx->ldb_ctx;
1052
1053         basedn = ldb_dn_new(ldb_ctx, ldb_ctx, "CN=Profiles");
1054
1055         ret = ldb_search(ldb_ctx, mem_ctx, &res, basedn, LDB_SCOPE_SUBTREE, attrs, "(CN=%s)", profile->profname);
1056         MAPI_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NOT_FOUND, NULL);
1057         MAPI_RETVAL_IF(!res->count, MAPI_E_NOT_FOUND, NULL);
1058
1059         msg = res->msgs[0];
1060         ldb_element = ldb_msg_find_element(msg, attribute);
1061         MAPI_RETVAL_IF(!ldb_element, MAPI_E_NOT_FOUND, NULL);
1062
1063         val.data = (uint8_t *)talloc_strdup(mem_ctx, value);
1064         val.length = strlen(value);
1065         MAPI_RETVAL_IF(!ldb_msg_find_val(ldb_element, &val), MAPI_E_NOT_FOUND, NULL);
1066
1067         return MAPI_E_SUCCESS;
1068 }
1069
1070 /**
1071    Create the profile 
1072  */
1073
1074 static bool set_profile_attribute(const char *profname, struct SRowSet rowset, 
1075                                   uint32_t index, uint32_t property, const char *attr)
1076 {
1077         struct SPropValue       *lpProp;
1078         enum MAPISTATUS         ret;
1079
1080         lpProp = get_SPropValue_SRow(&(rowset.aRow[index]), property);
1081
1082         if (!lpProp) {
1083                 DEBUG(3, ("MAPI Property %s not set\n", attr));
1084                 return true;
1085         }
1086
1087         ret = mapi_profile_add_string_attr(profname, attr, lpProp->value.lpszA);
1088
1089         if (ret != MAPI_E_SUCCESS) {
1090                 DEBUG(3, ("Problem adding attribute %s in profile %s\n", attr, profname));
1091                 return false;
1092         }
1093         return true;
1094 }
1095
1096 static bool set_profile_mvstr_attribute(const char *profname, struct SRowSet rowset,
1097                                         uint32_t index, uint32_t property, const char *attr)
1098 {
1099         struct SPropValue       *lpProp;
1100         enum MAPISTATUS         ret;
1101         uint32_t                i;
1102
1103         lpProp = get_SPropValue_SRow(&(rowset.aRow[index]), property);
1104
1105         if (!lpProp) {
1106                 DEBUG(3, ("MAPI Property %s not set\n", attr));
1107                 return true;
1108         }
1109
1110         for (i = 0; i < lpProp->value.MVszA.cValues; i++) {
1111                 ret = mapi_profile_add_string_attr(profname, attr, lpProp->value.MVszA.lppszA[i]);
1112                 if (ret != MAPI_E_SUCCESS) {
1113                         DEBUG(3, ("Problem adding attribute %s in profile %s\n", attr, profname));
1114                         return false;
1115                 }
1116         }
1117         return true;
1118 }
1119
1120
1121 /**
1122    \details Process a full and automated MAPI profile creation
1123
1124    This function process a full and automated MAPI profile creation
1125    using the \a username pattern passed as a parameter. The functions
1126    takes a callback parameter which will be called when the username
1127    checked matches several usernames. Private data needed by the
1128    callback can be supplied using the private_data pointer.
1129
1130    \code
1131    typedef int (*mapi_callback_t) callback(struct SRowSet *, void *private_data);
1132    \endcode
1133    
1134    The callback returns the SRow element index within the SRowSet
1135    structure.  If the user cancels the operation the callback return
1136    value should be SRowSet->cRows or more.
1137
1138    \param session the session context
1139    \param username the username for the network profile
1140    \param callback function pointer callback function
1141    \param private_data context data that will be provided to the callback
1142
1143    \return MAPI_E_SUCCESS on success, otherwise -1.
1144
1145    \note Developers should call GetLastError() to retrieve the last
1146    MAPI error code. Possible MAPI error codes are:
1147
1148    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been
1149      initialized. The MAPI subsystem must be initialized (using
1150      MAPIInitialize) prior to creating a profile.
1151    - MAPI_E_END_OF_SESSION: The NSPI session has not been initialized
1152    - MAPI_E_CANCEL_USER: The user has aborted the operation
1153    - MAPI_E_INVALID_PARAMETER: The profile parameter was not set
1154      properly.
1155    - MAPI_E_NOT_FOUND: One of the mandatory field was not found during
1156      the profile creation process.
1157
1158    \sa OpenProfileStore, MAPILogonProvider, GetLastError
1159 */
1160 _PUBLIC_ enum MAPISTATUS ProcessNetworkProfile(struct mapi_session *session, const char *username,
1161                                                mapi_profile_callback_t callback, const void *private_data)
1162 {
1163         enum MAPISTATUS         retval;
1164         struct nspi_context     *nspi;
1165         struct SPropTagArray    *SPropTagArray = NULL;
1166         struct Restriction_r    Filter;
1167         struct SRowSet          *SRowSet;
1168         struct SPropValue       *lpProp = NULL;
1169         struct SPropTagArray    *MIds = NULL;
1170         struct SPropTagArray    MIds2;
1171         struct SPropTagArray    *MId_server = NULL;
1172         struct StringsArray_r   pNames;
1173         const char              *profname;
1174         uint32_t                instance_key = 0;
1175         uint32_t                index = 0;
1176
1177         MAPI_RETVAL_IF(!session, MAPI_E_NOT_INITIALIZED, NULL);
1178         MAPI_RETVAL_IF(!session->nspi->ctx, MAPI_E_END_OF_SESSION, NULL);
1179         
1180         nspi = (struct nspi_context *) session->nspi->ctx;
1181         profname = session->profile->profname;
1182         index = 0;
1183
1184         SRowSet = talloc_zero(nspi->mem_ctx, struct SRowSet);
1185         retval = nspi_GetSpecialTable(nspi, 0x0, &SRowSet);
1186         MAPIFreeBuffer(SRowSet);
1187         if (retval != MAPI_E_SUCCESS) return retval;
1188
1189         SPropTagArray = set_SPropTagArray(nspi->mem_ctx, 0xc,
1190                                           PR_DISPLAY_NAME,
1191                                           PR_OFFICE_TELEPHONE_NUMBER,
1192                                           PR_OFFICE_LOCATION,
1193                                           PR_TITLE,
1194                                           PR_COMPANY_NAME,
1195                                           PR_ACCOUNT,
1196                                           PR_ADDRTYPE,
1197                                           PR_ENTRYID,
1198                                           PR_OBJECT_TYPE,
1199                                           PR_DISPLAY_TYPE,
1200                                           PR_INSTANCE_KEY,
1201                                           PR_EMAIL_ADDRESS
1202                                           );
1203
1204         /* Retrieve the username to match */
1205         if (!username) {
1206                 username = cli_credentials_get_username(nspi->cred);
1207                 MAPI_RETVAL_IF(!username, MAPI_E_INVALID_PARAMETER, NULL);
1208         }
1209
1210         /* Build the restriction we want for NspiGetMatches */
1211         lpProp = talloc_zero(nspi->mem_ctx, struct SPropValue);
1212         lpProp->ulPropTag = PR_ANR_UNICODE;
1213         lpProp->dwAlignPad = 0;
1214         lpProp->value.lpszW = username;
1215
1216         Filter.rt = RES_PROPERTY;
1217         Filter.res.resProperty.relop = RES_PROPERTY;
1218         Filter.res.resProperty.ulPropTag = PR_ANR_UNICODE;
1219         Filter.res.resProperty.lpProp = lpProp;
1220
1221         SRowSet = talloc_zero(nspi->mem_ctx, struct SRowSet);
1222         MIds = talloc_zero(nspi->mem_ctx, struct SPropTagArray);
1223         retval = nspi_GetMatches(nspi, SPropTagArray, &Filter, &SRowSet, &MIds);
1224         MAPIFreeBuffer(SPropTagArray);
1225         MAPIFreeBuffer(lpProp);
1226         if (retval != MAPI_E_SUCCESS) {
1227                 MAPIFreeBuffer(MIds);
1228                 MAPIFreeBuffer(SRowSet);
1229                 return retval;
1230         }
1231
1232         /* if there's no match */
1233         MAPI_RETVAL_IF(!SRowSet, MAPI_E_NOT_FOUND, NULL);
1234         MAPI_RETVAL_IF(!SRowSet->cRows, MAPI_E_NOT_FOUND, NULL);
1235         MAPI_RETVAL_IF(!MIds, MAPI_E_NOT_FOUND, NULL);
1236
1237         /* if SRowSet count is superior than 1 an callback is specified, call it */
1238         if (SRowSet->cRows > 1 && callback) {
1239                 index = callback(SRowSet, private_data);
1240                 MAPI_RETVAL_IF((index >= SRowSet->cRows), MAPI_E_USER_CANCEL, NULL);
1241                 instance_key = MIds->aulPropTag[index];
1242         } else {
1243                 instance_key = MIds->aulPropTag[0];
1244         }
1245         MAPIFreeBuffer(MIds);
1246         
1247         MIds2.cValues = 0x1;
1248         MIds2.aulPropTag = &instance_key;
1249
1250         set_profile_attribute(profname, *SRowSet, index, PR_EMAIL_ADDRESS, "EmailAddress");
1251         set_profile_attribute(profname, *SRowSet, index, PR_DISPLAY_NAME, "DisplayName");
1252         set_profile_attribute(profname, *SRowSet, index, PR_ACCOUNT, "Account");
1253         set_profile_attribute(profname, *SRowSet, index, PR_ADDRTYPE, "AddrType");
1254
1255         SPropTagArray = set_SPropTagArray(nspi->mem_ctx, 0x7,
1256                                           PR_DISPLAY_NAME,
1257                                           PR_EMAIL_ADDRESS,
1258                                           PR_DISPLAY_TYPE,
1259                                           PR_EMS_AB_HOME_MDB,
1260                                           PR_ATTACH_NUM,
1261                                           PR_PROFILE_HOME_SERVER_ADDRS,
1262                                           PR_EMS_AB_PROXY_ADDRESSES
1263                                           );
1264
1265         nspi->pStat->CurrentRec = 0x0;
1266         nspi->pStat->Delta = 0x0;
1267         nspi->pStat->NumPos = 0x0;
1268         nspi->pStat->TotalRecs = 0x1;
1269
1270         MAPIFreeBuffer(SRowSet);
1271         SRowSet = talloc(nspi->mem_ctx, struct SRowSet);
1272         retval = nspi_QueryRows(nspi, SPropTagArray, &MIds2, 1, &SRowSet);
1273         MAPIFreeBuffer(SPropTagArray);
1274         if (retval != MAPI_E_SUCCESS) return retval;
1275
1276         lpProp = get_SPropValue_SRowSet(SRowSet, PR_EMS_AB_HOME_MDB);
1277         MAPI_RETVAL_IF(!lpProp, MAPI_E_NOT_FOUND, NULL);
1278
1279         nspi->org = x500_get_dn_element(nspi->mem_ctx, lpProp->value.lpszA, ORG);
1280         nspi->org_unit = x500_get_dn_element(nspi->mem_ctx, lpProp->value.lpszA, ORG_UNIT);
1281         
1282         MAPI_RETVAL_IF(!nspi->org_unit, MAPI_E_INVALID_PARAMETER, NULL);
1283         MAPI_RETVAL_IF(!nspi->org, MAPI_E_INVALID_PARAMETER, NULL);
1284
1285         retval = mapi_profile_add_string_attr(profname, "Organization", nspi->org);
1286         retval = mapi_profile_add_string_attr(profname, "OrganizationUnit", nspi->org_unit);
1287
1288         nspi->servername = x500_get_servername(lpProp->value.lpszA);
1289         mapi_profile_add_string_attr(profname, "ServerName", nspi->servername);
1290         set_profile_attribute(profname, *SRowSet, 0, PR_EMS_AB_HOME_MDB, "HomeMDB");
1291         set_profile_mvstr_attribute(profname, *SRowSet, 0, PR_EMS_AB_PROXY_ADDRESSES, "ProxyAddress");
1292         MAPIFreeBuffer(SRowSet);
1293
1294         pNames.Count = 0x1;
1295         pNames.Strings = (const char **) talloc_array(nspi->mem_ctx, char **, 1);
1296         pNames.Strings[0] = (const char *) talloc_asprintf(nspi->mem_ctx, SERVER_DN, 
1297                                                            nspi->org, nspi->org_unit, 
1298                                                            nspi->servername);
1299         MId_server = talloc_zero(nspi->mem_ctx, struct SPropTagArray);
1300         retval = nspi_DNToMId(nspi, &pNames, &MId_server);
1301         MAPIFreeBuffer((char *)pNames.Strings[0]);
1302         MAPIFreeBuffer((char **)pNames.Strings);
1303         if (retval != MAPI_E_SUCCESS) return retval;
1304
1305         SRowSet = talloc_zero(nspi->mem_ctx, struct SRowSet);
1306         SPropTagArray = set_SPropTagArray(nspi->mem_ctx, 0x1, PR_EMS_AB_NETWORK_ADDRESS);
1307         retval = nspi_GetProps(nspi, SPropTagArray, MId_server, &SRowSet);
1308         MAPIFreeBuffer(SPropTagArray);
1309         MAPIFreeBuffer(MId_server);
1310         if (retval != MAPI_E_SUCCESS) {
1311                 MAPIFreeBuffer(SRowSet);
1312                 return retval;
1313         }
1314
1315         set_profile_mvstr_attribute(profname, *SRowSet, 0, PR_EMS_AB_NETWORK_ADDRESS, "NetworkAddress");
1316         MAPIFreeBuffer(SRowSet);
1317
1318         return MAPI_E_SUCCESS;
1319 }