1 /*
2  * jabberd - Jabber Open Source Server
3  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4  *                    Ryan Eatmon, Robert Norris
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19  */
20 
21 /*
22  * Written by Nikita Smirnov in 2004
23  * on basis of authreg_ldap.c and storage_fs.c
24  */
25 
26 #include "storage.h"
27 
28 #ifdef STORAGE_LDAP
29 
30 #define LDAP_DEPRECATED 1
31 #include <ldap.h>
32 #include <time.h>
33 #include <regex.h>
34 
35 #define LDAPVCARD_SRVTYPE_LDAP 1
36 #define LDAPVCARD_SRVTYPE_AD 2
37 
38 #define LDAPVCARD_SEARCH_MAX_RETRIES 1
39 
40 extern int _ldap_get_lderrno(LDAP *ld);
41 
42 /** internal structure, holds our data */
43 typedef struct drvdata_st {
44     LDAP *ld;
45     const char *uri;
46 
47     const char *realm; // server id to be appended to uid
48 
49     const char *binddn;
50     const char *bindpw;
51     const char *basedn;
52 
53     const char *objectclass; // objectclass of jabber users
54     const char *uidattr; // search attribute for users
55     const char *validattr; // search attribute for valid
56     const char *pwattr; // attribute which holds password
57     const char *groupattr; // attribute with group name for published-roster in jabberuser entry
58     const char *groupattr_regex; // regex to create a new group attribute based on groupattr
59     const char *publishedattr; // can we publish it?
60 
61     const char *groupsdn; // base dn for group names search
62     const char *groupsoc; // objectclass for group names search
63     const char *groupsidattr; // search attribute for group names
64     const char *groupnameattr; // attribute with text group name
65 
66     int srvtype;
67     int mappedgroups;
68 
69 #ifndef NO_SM_CACHE
70     os_t cache;
71     time_t cache_time;
72     time_t cache_ttl;
73 #endif
74 } *drvdata_t;
75 
76 typedef struct {
77     char *ldapentry, *vcardentry;
78     os_type_t ot;
79 } ldapvcard_entry_st;
80 
81 ldapvcard_entry_st ldapvcard_entry[] =
82 {
83     {"displayName","fn",os_type_STRING},
84     {"cn","nickname",os_type_STRING},
85     {"labeledURI","url",os_type_STRING},
86     {"telephoneNumber","tel",os_type_STRING},
87     {"mail","email",os_type_STRING},
88     {"title","title",os_type_STRING},
89     {"role","role",os_type_STRING},
90     {"dateOfBirth","bday",os_type_UNKNOWN}, /* fake type. TODO: os_type_DATE? */
91 //    {"birthDate","bday",os_type_UNKNOWN}, /* http://tools.ietf.org/html/draft-gryphon-ldap-schema-vcard4-00 */
92     {"description","desc",os_type_STRING},
93     {"givenName","n-given",os_type_STRING},
94     {"jpegPhoto","photo-binval",os_type_STRING},
95     {"sn","n-family",os_type_STRING},
96     {"initials","n-middle",os_type_STRING},
97     {"st","adr-street",os_type_STRING},
98     {"zip","adr-extadd",os_type_STRING},
99     {"l","adr-locality",os_type_STRING},
100 //    {"","adr-region",os_type_STRING},
101     {"postalCode","adr-pcode",os_type_STRING},
102     {"c","adr-country",os_type_STRING},
103     {"o","org-orgname",os_type_STRING},
104     {"ou","org-orgunit",os_type_STRING},
105     {NULL,NULL,0}
106 };
107 
processregex(char * src,const char * regex,int patterngroups,int wantedgroup,char * dest,size_t dest_size,st_driver_t drv)108 static int processregex(char *src, const char *regex, int patterngroups, int wantedgroup, char *dest, size_t dest_size, st_driver_t drv) {
109   regex_t preg;
110   regmatch_t pmatch[patterngroups];
111   //log_debug(ZONE,"processregex: src='%s' regex='%s'", src, regex);
112   if (regcomp(&preg, regex, REG_ICASE|REG_EXTENDED) !=0) {
113         log_write(drv->st->log, LOG_ERR, "ldapvcard: regex compile failed on '%s'", regex);
114 	return -1;
115   }
116   if (regexec(&preg, src, patterngroups, pmatch, 0) !=0) {
117         log_write(drv->st->log, LOG_ERR, "ldapvcard: regexec failed");
118 	return -2;
119   }
120   regfree(&preg);
121   int len = pmatch[wantedgroup].rm_eo-pmatch[wantedgroup].rm_so>dest_size?dest_size:pmatch[wantedgroup].rm_eo-pmatch[wantedgroup].rm_so;
122   memcpy(dest, src+pmatch[wantedgroup].rm_so, len);
123   dest[len<dest_size?len:dest_size]='\0';
124   //log_debug(ZONE,"processregex: dest='%s'", dest);
125   return 0;
126 }
127 
128 #ifndef NO_SM_CACHE
os_copy(os_t src,os_t dst)129 void os_copy(os_t src, os_t dst) {
130     os_object_t o,dsto;
131     char *key;
132     void *val, *cval;
133     os_type_t ot;
134 
135     if(os_iter_first(src)) {
136         do {
137             //log_write(log, LOG_ERR, "reading object");
138             o = os_iter_object(src);
139             dsto = os_object_new(dst);
140             if( os_object_iter_first(o)) {
141                 do {
142                     os_object_iter_get(o,&key,&val,&ot);
143                     switch(ot) {
144                         case os_type_BOOLEAN:
145                         case os_type_INTEGER:
146                             cval = &val;
147                             break;
148                         default:
149                             cval = val;
150                     }
151                     os_object_put(dsto,key,cval,ot);
152                     //log_write(log, LOG_ERR, "wrote.");
153                 } while(os_object_iter_next(o));
154             }
155         } while(os_iter_next(src));
156     } else { // ! os_iter_first(src)
157         log_debug(ZONE,"os_copy: cannot read source object");
158     }
159 }
160 #endif
161 
162 /** utility function to get ld_errno */
_st_ldapvcard_get_lderrno(LDAP * ld)163 static int _st_ldapvcard_get_lderrno(LDAP *ld)
164 {
165   int ld_errno;
166   ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
167   return ld_errno;
168 }
169 
170 /** entry-point function for following referrals, required in some cases by Active Directory */
rebindProc(LDAP * ld,LDAP_CONST char * url,ber_tag_t request,ber_int_t msgid,void * mdata)171 static int rebindProc(LDAP *ld, LDAP_CONST char *url, ber_tag_t request, ber_int_t msgid, void *mdata)
172 {
173     drvdata_t data = mdata;
174     data->ld = ld;
175     if(ldap_simple_bind_s(data->ld, data->binddn, data->bindpw)) {
176         log_debug(ZONE, "ldapvcard: bind failed (to %s): %s", url, ldap_err2string(_ldap_get_lderrno(data->ld)));
177         ldap_unbind_s(data->ld);
178         data->ld = NULL;
179         return LDAP_INAPPROPRIATE_AUTH;
180     }
181 
182     return LDAP_SUCCESS;
183 }
184 
185 /** connect to the ldap host */
_st_ldapvcard_connect(st_driver_t drv)186 static int _st_ldapvcard_connect(st_driver_t drv)
187 {
188   drvdata_t data = (drvdata_t) drv->private;
189   int ldapversion = LDAP_VERSION3;
190   int rc;
191 
192   if(data->ld != NULL)
193     ldap_unbind_s(data->ld);
194 
195   rc = ldap_initialize( &(data->ld), data->uri);
196   if( rc != LDAP_SUCCESS )
197   {
198     log_write(drv->st->log, LOG_ERR, "ldapvcard: ldap_initialize failed (uri=%s): %s", data->uri, ldap_err2string(rc));
199     return 1;
200   }
201 
202   if (ldap_set_option(data->ld, LDAP_OPT_PROTOCOL_VERSION, &ldapversion) != LDAP_SUCCESS)
203   {
204     log_write(drv->st->log, LOG_ERR, "ldapvcard: couldn't set v3 protocol");
205     return 1;
206   }
207   if (ldap_set_option(data->ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON) != LDAP_SUCCESS)
208   {
209     log_write(drv->st->log, LOG_ERR, "ldapvcard: couldn't set LDAP_OPT_REFERRALS");
210   }
211 
212   return 0;
213 }
214 
215 /** unbind and clear variables */
_st_ldapvcard_unbind(st_driver_t drv)216 static int _st_ldapvcard_unbind(st_driver_t drv) {
217   drvdata_t data = (drvdata_t) drv->private;
218   ldap_unbind_s(data->ld);
219   data->ld = NULL;
220   return 0;
221 }
222 
223 /** connect to ldap and bind as data->binddn */
_st_ldapvcard_connect_bind(st_driver_t drv)224 static int _st_ldapvcard_connect_bind(st_driver_t drv) {
225   drvdata_t data = (drvdata_t) drv->private;
226 
227   if(data->ld != NULL ) {
228     return 0;
229   }
230 
231   if( _st_ldapvcard_connect(drv) ) {
232     return 1;
233   }
234   if(ldap_simple_bind_s(data->ld, data->binddn, data->bindpw))
235   {
236     log_write(drv->st->log, LOG_ERR, "ldapvcard: bind as %s failed: %s", data->binddn, ldap_err2string(_st_ldapvcard_get_lderrno(data->ld)));
237     _st_ldapvcard_unbind(drv);
238     return 1;
239   }
240   return 0;
241 }
242 
_st_ldapvcard_add_type(st_driver_t drv,const char * type)243 static st_ret_t _st_ldapvcard_add_type(st_driver_t drv, const char *type) {
244     drvdata_t data = (drvdata_t) drv->private;
245 
246     if( strncmp(type,"vcard",6) &&
247         strncmp(type,"published-roster",17) &&
248         strncmp(type,"published-roster-groups",24)
249         ) {
250         log_write(drv->st->log, LOG_ERR, "ldapvcard: only vcard,published-roster,published-roster-groups types supperted for now");
251         return st_FAILED;
252     } else {
253         if( !strncmp(type,"published-roster-groups",24) ) {
254             if( !data->mappedgroups ) {
255                 log_write(drv->st->log, LOG_ERR, "ldapvcard: published-roster-groups is not enabled by map-groups config option in ldapvcard section");
256                 return st_FAILED;
257             }
258         }
259         return st_SUCCESS;
260     }
261 
262     return st_SUCCESS;
263 }
264 
_st_ldapvcard_get(st_driver_t drv,const char * type,const char * owner,const char * filter,os_t * os)265 static st_ret_t _st_ldapvcard_get(st_driver_t drv, const char *type, const char *owner, const char *filter, os_t *os) {
266     drvdata_t data = (drvdata_t) drv->private;
267     os_object_t o;
268     char validfilter[256], ldapfilter[1024], **vals;
269     char *attrs_vcard[sizeof(ldapvcard_entry)/sizeof(ldapvcard_entry_st)];
270     const char *attrs_pr[] = { data->uidattr, data->groupattr, "sn", "displayName", "initials", NULL };
271     const char *attrs_prg[] = { data->groupnameattr, NULL };
272     LDAPMessage *result, *entry;
273     ldapvcard_entry_st le;
274     int i,ival;
275     int tried = 0;
276     char jid[2048], group[1024], name[2048]; // name is sn[1024] + ' ' + initials[1024]
277 
278     if( _st_ldapvcard_connect_bind(drv) ) {
279         return st_FAILED;
280     }
281 
282     if( strncmp(type,"vcard",6) == 0 ) {
283         // prepare need attributes
284         i = 0;
285         do {
286             le = ldapvcard_entry[i];
287             attrs_vcard[i++] = le.ldapentry;
288         } while ( le.ldapentry != NULL );
289 
290         snprintf(ldapfilter, 1024, "(&(objectClass=%s)(%s=%s))", data->objectclass, data->uidattr, owner);
291         log_debug(ZONE, "search filter: %s", ldapfilter);
292 
293         if(ldap_set_rebind_proc(data->ld, &rebindProc, data))
294         {
295             log_write(drv->st->log, LOG_ERR, "ldap: set_rebind_proc failed: %s", ldap_err2string(_st_ldapvcard_get_lderrno(data->ld)));
296             ldap_unbind_s(data->ld);
297             data->ld = NULL;
298             return st_FAILED;
299         }
300 
301         if(ldap_search_s(data->ld, data->basedn, LDAP_SCOPE_SUBTREE, ldapfilter, attrs_vcard, 0, &result))
302         {
303             log_write(drv->st->log, LOG_ERR, "ldapvcard: search %s failed: %s", ldapfilter, ldap_err2string(_st_ldapvcard_get_lderrno(data->ld)));
304             _st_ldapvcard_unbind(drv);
305             return st_FAILED;
306         }
307 
308         entry = ldap_first_entry(data->ld, result);
309         if(entry == NULL)
310         {
311             ldap_msgfree(result);
312             return st_FAILED;
313         }
314 
315         *os = os_new();
316 
317         o = os_object_new(*os);
318 
319         i = 0;
320         le = ldapvcard_entry[i];
321         while( le.ldapentry != NULL ) {
322             if ( (strlen(le.ldapentry) == 9) && (!strncmp("jpegPhoto",le.ldapentry,9)))
323             {
324                 struct berval **valphoto=(struct berval **)ldap_get_values_len(data->ld,entry,le.ldapentry);
325                 if ( ldap_count_values_len(valphoto) > 0 )
326                 {
327                     char *VALJPG = b64_encode(valphoto[0]->bv_val, valphoto[0]->bv_len);
328                     os_object_put(o, "photo-binval", VALJPG, os_type_STRING);
329                     if( !strncmp(VALJPG, "/9j/4", 5) ) {
330                         os_object_put(o, "photo-type", "image/jpeg", os_type_STRING);
331                     } else if( !strncmp(VALJPG, "iVBOR", 5) ) {
332                         os_object_put(o, "photo-type", "image/png", os_type_STRING);
333                     } else if( !strncmp(VALJPG, "R0lGO", 5) ) {
334                         os_object_put(o, "photo-type", "image/gif", os_type_STRING);
335                     } else {
336                         log_write(drv->st->log, LOG_ERR, "ldap: unknown photo fprmat photo %s", VALJPG);
337                         os_object_put(o, "photo-type", "image/jpeg", os_type_STRING);
338                     }
339                     free(VALJPG);
340                 }
341                 ldap_value_free_len(valphoto);
342             } else {
343                 vals=(char **)ldap_get_values(data->ld,entry,le.ldapentry);
344                 if( ldap_count_values(vals) > 0  ) {
345                     switch(le.ot) {
346                         case os_type_BOOLEAN:
347                         case os_type_INTEGER:
348                             ival=atoi(vals[0]);
349                             os_object_put(o, le.vcardentry, &ival, le.ot);
350                             break;
351                         case os_type_STRING:
352                             os_object_put(o, le.vcardentry, vals[0], le.ot);
353                             break;
354                         case os_type_UNKNOWN: /* TODO: os_type_DATE? */
355                             if( strlen(vals[0])==15 && vals[0][14]=='Z' ) { /* YYYYMMDDHHmmssZ */
356                                 /* convert generalizedTime to ISO-8601 date */
357                                 vals[0][10]='\0';
358                                 vals[0][9]=vals[0][7];
359                                 vals[0][8]=vals[0][6];
360                                 vals[0][7]='-';
361                                 vals[0][6]=vals[0][5];
362                                 vals[0][5]=vals[0][4];
363                                 vals[0][4]='-';
364                                 os_object_put(o, le.vcardentry, vals[0], os_type_STRING);
365                             }
366                             break;
367                         case os_type_NAD:
368                             log_write(drv->st->log, LOG_ERR, "ldapvcard: got unsupported os_type_NAD");
369                             break;
370                     }
371                 }
372                 ldap_value_free(vals);
373             }
374             le = ldapvcard_entry[++i];
375         }
376         ldap_msgfree(result);
377     } else if( strncmp(type,"published-roster",17) == 0 ) {
378 #ifndef NO_SM_CACHE
379         if( data->cache_ttl && data->cache && (time(NULL) - data->cache_time < data->cache_ttl) ) {
380             *os = os_new();
381             os_copy(data->cache, *os);
382         } else {
383 #endif
384             validfilter[0] = '\0';
385             if( data->srvtype == LDAPVCARD_SRVTYPE_AD ) {
386                 if( data->validattr ) {
387                     snprintf(validfilter, 256, "(%s=TRUE)(%s=TRUE)", data->publishedattr, data->validattr);
388                 } else {
389                     snprintf(validfilter, 256, "(%s=TRUE)", data->publishedattr);
390                 }
391             } else {
392                 if( data->validattr ) {
393                     snprintf(validfilter, 256, "(&(%s=*)(!(%s=0)))(%s=1)", data->publishedattr, data->publishedattr, data->validattr);
394                 } else {
395                     snprintf(validfilter, 256, "(&(%s=*)(!(%s=0)))", data->publishedattr, data->publishedattr);
396                 }
397             }
398 
399             snprintf(ldapfilter, 1024, "(&%s(objectClass=%s)(%s=*))", validfilter, data->objectclass, data->uidattr);
400 
401             log_debug(ZONE, "search filter: %s", ldapfilter);
402 
403 retry_pubrost:
404             if(ldap_search_s(data->ld, data->basedn, LDAP_SCOPE_SUBTREE, ldapfilter, (char**)attrs_pr, 0, &result))
405             {
406                 if( tried++ < LDAPVCARD_SEARCH_MAX_RETRIES ) {
407                     log_debug(ZONE, "ldapvcard: search fail, will retry; %s: %s", ldapfilter, ldap_err2string(_st_ldapvcard_get_lderrno(data->ld)));
408                     _st_ldapvcard_unbind(drv);
409                     if( _st_ldapvcard_connect_bind(drv) == 0 ) {
410                         goto retry_pubrost;
411                     } else {
412                         return st_FAILED;
413                     }
414                 }
415                 log_write(drv->st->log, LOG_ERR, "ldapvcard: search %s failed: %s", ldapfilter, ldap_err2string(_st_ldapvcard_get_lderrno(data->ld)));
416                 _st_ldapvcard_unbind(drv);
417                 return st_FAILED;
418             }
419 
420             entry = ldap_first_entry(data->ld, result);
421             if(entry == NULL)
422             {
423                 ldap_msgfree(result);
424                 return st_FAILED;
425             }
426 
427             *os = os_new();
428 
429             do {
430                 vals = (char **)ldap_get_values(data->ld,entry,data->groupattr);
431                 if( ldap_count_values(vals) <= 0 ) {
432                     ldap_value_free(vals);
433                     continue;
434                 }
435                 if (data->groupattr_regex == NULL || processregex(vals[0],data->groupattr_regex,2,1,group,sizeof(group),drv) !=0) {
436                     // if there is no regex defined or processing the regex failed - take value as is
437                     strncpy(group,vals[0],sizeof(group)-1);
438                 }
439                 group[sizeof(group)-1]='\0';
440                 ldap_value_free(vals);
441 
442                 vals = (char **)ldap_get_values(data->ld,entry,data->uidattr);
443                 if( ldap_count_values(vals) <= 0 ) {
444                     ldap_value_free(vals);
445                     continue;
446                 }
447                 if( data->realm == NULL ) {
448                     strncpy(jid,vals[0],sizeof(jid)-1); jid[sizeof(jid)-1]='\0';
449                 } else {
450                     snprintf(jid, 2048, "%s@%s", vals[0], data->realm);
451                 }
452 
453                 ldap_value_free(vals);
454 
455                 vals = (char **)ldap_get_values(data->ld,entry,"displayName");
456                 if( ldap_count_values(vals) <= 0 ) {
457                     ldap_value_free(vals);
458                     vals = (char **)ldap_get_values(data->ld,entry,"cn");
459                     if( ldap_count_values(vals) <= 0 ) {
460                         strncpy(name,jid,sizeof(name)-1); name[sizeof(name)-1]='\0';
461                     } else {
462                         strncpy(name,vals[0],sizeof(name)-1); name[sizeof(name)-1]='\0';
463                     }
464                 } else {
465                     strncpy(name,vals[0],1023); name[1023]='\0';
466                 }
467                 ldap_value_free(vals);
468 
469                 o = os_object_new(*os);
470                 os_object_put(o,"jid",jid,os_type_STRING);
471                 os_object_put(o,"group",group,os_type_STRING);
472                 os_object_put(o,"name",name,os_type_STRING);
473                 ival=1;
474                 os_object_put(o,"to",&ival,os_type_BOOLEAN);
475                 os_object_put(o,"from",&ival,os_type_BOOLEAN);
476                 ival=0;
477                 os_object_put(o,"ask",&ival,os_type_INTEGER);
478             } while( (entry = ldap_next_entry(data->ld, entry)) );
479             ldap_msgfree(result);
480 #ifndef NO_SM_CACHE
481             if( data->cache_ttl ) {
482                 if( data->cache ) {
483                     os_free(data->cache);
484                 }
485                 data->cache = os_new();
486                 os_copy(*os, data->cache);
487                 data->cache_time = time(NULL);
488             }
489 #endif
490 #ifndef NO_SM_CACHE
491         } // if !cached
492 #endif
493     } else if( strncmp(type,"published-roster-groups",24) == 0 ) {
494         snprintf(ldapfilter, 1024, "(&(objectClass=%s)(%s=%s))", data->groupsoc, data->groupsidattr, owner);
495         log_debug(ZONE, "search filter: %s", ldapfilter);
496 retry_pubrostgr:
497         if(ldap_search_s(data->ld, data->basedn, LDAP_SCOPE_SUBTREE, ldapfilter, (char**)attrs_prg, 0, &result))
498         {
499             if( tried++ < LDAPVCARD_SEARCH_MAX_RETRIES ) {
500                 log_debug(ZONE, "ldapvcard: search fail, will retry; %s: %s", ldapfilter, ldap_err2string(_st_ldapvcard_get_lderrno(data->ld)));
501                 _st_ldapvcard_unbind(drv);
502                 if( _st_ldapvcard_connect_bind(drv) == 0 ) {
503                     goto retry_pubrostgr;
504                 } else {
505                     return st_FAILED;
506                 }
507             }
508             log_write(drv->st->log, LOG_ERR, "ldapvcard: search %s failed: %s", ldapfilter, ldap_err2string(_st_ldapvcard_get_lderrno(data->ld)));
509             _st_ldapvcard_unbind(drv);
510             return st_FAILED;
511         }
512 
513         entry = ldap_first_entry(data->ld, result);
514         if(entry == NULL)
515         {
516             ldap_msgfree(result);
517             return st_FAILED;
518         }
519 
520         *os = os_new();
521 
522         // use only the first found entry and the first found attribute value
523         vals = (char **)ldap_get_values(data->ld,entry,data->groupnameattr);
524         if( ldap_count_values(vals) <= 0 ) {
525             ldap_value_free(vals);
526             ldap_msgfree(result);
527             return st_FAILED;
528         }
529         strncpy(group,vals[0],sizeof(group)-1); group[sizeof(group)-1]='\0';
530         ldap_value_free(vals);
531         ldap_msgfree(result);
532 
533         o = os_object_new(*os);
534         os_object_put(o,"groupname",group,os_type_STRING);
535     } else {
536         log_write(drv->st->log, LOG_ERR, "ldapvcard: unknown storage type: '%s'", type);
537         return st_FAILED;
538     }
539 
540     return st_SUCCESS;
541 }
542 
_st_ldapvcard_put(st_driver_t drv,const char * type,const char * owner,os_t os)543 static st_ret_t _st_ldapvcard_put(st_driver_t drv, const char *type, const char *owner, os_t os) {
544     return st_FAILED;
545 }
_st_ldapvcard_delete(st_driver_t drv,const char * type,const char * owner,const char * filter)546 static st_ret_t _st_ldapvcard_delete(st_driver_t drv, const char *type, const char *owner, const char *filter) {
547     return st_SUCCESS;
548 }
_st_ldapvcard_replace(st_driver_t drv,const char * type,const char * owner,const char * filter,os_t os)549 static st_ret_t _st_ldapvcard_replace(st_driver_t drv, const char *type, const char *owner, const char *filter, os_t os) {
550     return st_FAILED;
551 }
552 
_st_ldapvcard_free(st_driver_t drv)553 static void _st_ldapvcard_free(st_driver_t drv) {
554     drvdata_t data = (drvdata_t) drv->private;
555     if( data->ld ) {
556         _st_ldapvcard_unbind(drv);
557     }
558     free(data);
559 }
560 
st_init(st_driver_t drv)561 DLLEXPORT st_ret_t st_init(st_driver_t drv)
562 {
563     drvdata_t data;
564     const char *uri, *realm, *basedn, *srvtype_s;
565     int srvtype_i;
566 
567     log_write(drv->st->log, LOG_NOTICE, "ldapvcard: initializing");
568 
569     uri = config_get_one(drv->st->config, "storage.ldapvcard.uri", 0);
570     if(uri == NULL) {
571         log_write(drv->st->log, LOG_ERR, "ldapvcard: no uri specified in config file");
572         return st_FAILED;
573     }
574 
575     realm = config_get_one(drv->st->config, "storage.ldapvcard.realm", 0);
576     if(realm != NULL) {
577         log_write(drv->st->log, LOG_NOTICE, "ldapvcard: defined realm %s", realm);
578     }
579 
580     basedn = config_get_one(drv->st->config, "storage.ldapvcard.basedn", 0);
581     if(basedn == NULL) {
582         log_write(drv->st->log, LOG_ERR, "ldapvcard: no basedn specified in config file");
583         return st_FAILED;
584     }
585 
586     srvtype_s = config_get_one(drv->st->config, "storage.ldapvcard.type", 0);
587     if( srvtype_s == NULL ) {
588         srvtype_i = LDAPVCARD_SRVTYPE_LDAP;
589     } else if( !strcmp(srvtype_s, "ldap") ) {
590         srvtype_i = LDAPVCARD_SRVTYPE_LDAP;
591     } else if( !strcmp(srvtype_s, "ad") ) {
592         srvtype_i = LDAPVCARD_SRVTYPE_AD;
593     } else {
594         log_write(drv->st->log, LOG_ERR, "ldapvcard: unknown server type: %s", srvtype_s);
595         return 1;
596     }
597 
598     data = (drvdata_t) calloc(1, sizeof(struct drvdata_st));
599 
600     drv->private = (void *) data;
601 
602     data->uri = uri;
603     data->realm = realm;
604     data->basedn = basedn;
605     data->srvtype = srvtype_i;
606 
607     data->binddn = config_get_one(drv->st->config, "storage.ldapvcard.binddn", 0);
608     if(data->binddn != NULL)
609         data->bindpw = config_get_one(drv->st->config, "storage.ldapvcard.bindpw", 0);
610 
611     data->uidattr = config_get_one(drv->st->config, "storage.ldapvcard.uidattr", 0);
612     if(data->uidattr == NULL)
613         data->uidattr = "uid";
614 
615     data->validattr = config_get_one(drv->st->config, "storage.ldapvcard.validattr", 0);
616 
617     data->groupattr = config_get_one(drv->st->config, "storage.ldapvcard.groupattr", 0);
618     if(data->groupattr == NULL)
619         data->groupattr = "jabberPublishedGroup";
620 
621     data->groupattr_regex = config_get_one(drv->st->config, "storage.ldapvcard.groupattr_regex", 0);
622 
623     data->publishedattr = config_get_one(drv->st->config, "storage.ldapvcard.publishedattr", 0);
624     if(data->publishedattr == NULL)
625         data->publishedattr = "jabberPublishedItem";
626 
627 #ifndef NO_SM_CACHE
628     data->cache_ttl = j_atoi(config_get_one(drv->st->config, "storage.ldapvcard.publishedcachettl", 0), 0);
629     data->cache = NULL;
630     data->cache_time = 0;
631 #endif
632 
633     data->objectclass = config_get_one(drv->st->config, "storage.ldapvcard.objectclass", 0);
634     if(data->objectclass == NULL)
635         data->objectclass = "jabberUser";
636 
637     data->mappedgroups = j_atoi(config_get_one(drv->st->config, "storage.ldapvcard.mapped-groups.map-groups", 0), 0);
638     if( data->mappedgroups ) {
639         data->groupsdn = config_get_one(drv->st->config, "storage.ldapvcard.mapped-groups.basedn", 0);
640         if(data->groupsdn == NULL) {
641             log_write(drv->st->log, LOG_ERR, "ldapvcard: no basedn for mapped-groups specified in config file");
642             return st_FAILED;
643         }
644 
645         data->groupsoc = config_get_one(drv->st->config, "storage.ldapvcard.mapped-groups.objectclass", 0);
646         if(data->groupsoc == NULL)
647             data->groupsoc = "jabberGroup";
648 
649         data->groupsidattr = config_get_one(drv->st->config, "storage.ldapvcard.mapped-groups.idattr", 0);
650         if(data->groupsidattr == NULL)
651             data->groupsidattr = "cn";
652 
653         data->groupnameattr = config_get_one(drv->st->config, "storage.ldapvcard.mapped-groups.nameattr", 0);
654         if(data->groupnameattr == NULL)
655             data->groupnameattr = "description";
656     }
657 
658     drv->add_type = _st_ldapvcard_add_type;
659     drv->put = _st_ldapvcard_put;
660     drv->get = _st_ldapvcard_get;
661     drv->delete = _st_ldapvcard_delete;
662     drv->replace = _st_ldapvcard_replace;
663     drv->free = _st_ldapvcard_free;
664 
665     return st_SUCCESS;
666 }
667 
668 #endif
669