Back to index

courier  0.68.2
libldapsearch.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2006, Double Precision Inc.
00003 **
00004 ** See COPYING for distribution information.
00005 */
00006 
00007 #include "libldapsearch.h"
00008 #include <stdlib.h>
00009 #include <errno.h>
00010 #include <time.h>
00011 #if TIME_WITH_SYS_TIME
00012 # include <sys/time.h>
00013 # include <time.h>
00014 #else
00015 # if HAVE_SYS_TIME_H
00016 #  include <sys/time.h>
00017 # else
00018 #  include <time.h>
00019 # endif
00020 #endif
00021 
00022 /*
00023 ** Allocate and deallocate the ldapsearch struct.
00024 */
00025 
00026 struct ldapsearch *l_search_alloc(const char *host,
00027                               int port,
00028                               const char *userid,
00029                               const char *password,
00030                               const char *base)
00031 {
00032        char *buf;
00033 
00034        struct ldapsearch *p=(struct ldapsearch *)
00035               malloc(sizeof(struct ldapsearch));
00036 
00037        if (!p)
00038               return NULL;
00039 
00040        if ((p->base=strdup(base)) == NULL)
00041        {
00042               free(p);
00043               return NULL;
00044        }
00045 
00046        if ((buf=malloc(strlen(host)+100)) == NULL)
00047        {
00048               free(p->base);
00049               free(p);
00050               return NULL;
00051        }
00052 
00053        sprintf(buf, "ldap://%s:%d", host, port);
00054 
00055        if (ldap_initialize(&p->handle, buf) != LDAP_SUCCESS)
00056        {
00057               free(buf);
00058               free(p->base);
00059               free(p);
00060               return NULL;
00061        }
00062        free(buf);
00063 
00064        if (userid && *userid)
00065        {
00066               struct berval cred;
00067 
00068               cred.bv_len=password && *password ? strlen(password):0;
00069               cred.bv_val=password && *password ? (char *)password:NULL;
00070 
00071               if (ldap_sasl_bind_s(p->handle, userid, NULL, &cred, NULL,
00072                                  NULL, NULL))
00073               {
00074                      l_search_free(p);
00075                      errno=EPERM;
00076                      return NULL;
00077               }
00078        }
00079 
00080        return p;
00081 }
00082 
00083 void l_search_free(struct ldapsearch *s)
00084 {
00085        if (s->handle)
00086               ldap_unbind_ext(s->handle, NULL, NULL);
00087        free(s->base);
00088        free(s);
00089 }
00090 
00091 /*
00092 ** See RFC 2254 section 4.
00093 */
00094 
00095 static char *encode_key(const char *lookupkey)
00096 {
00097        const char *cp;
00098 
00099        char *p=NULL, *q;
00100        int pass;
00101        size_t l=0;
00102 
00103        for (pass=0; pass<2; pass++)
00104        {
00105               if (pass)
00106               {
00107                      p=malloc(l);
00108                      if (!p)
00109                             return NULL;
00110               }
00111               l=1;
00112               q=p;
00113               for (cp=lookupkey; *cp; cp++)
00114               {
00115                      const char *h;
00116 
00117                      switch (*cp) {
00118                      case '*':
00119                             h="\\2a";
00120                             break;
00121                      case '(':
00122                             h="\\28";
00123                             break;
00124                      case ')':
00125                             h="\\29";
00126                             break;
00127                      case '\\':
00128                             h="\\5c";
00129                             break;
00130                      default:
00131                             if (pass)
00132                                    *q++= *cp;
00133                             ++l;
00134                             continue;
00135                      }
00136 
00137                      if (pass)
00138                             while ((*q++ = *h++) != 0)
00139                                    ;
00140                      l += 3;
00141               }
00142               if (pass)
00143                      *q=0;
00144        }
00145        return p;
00146 }
00147 
00148 /*
00149 ** Insert lookup key into the search filter.
00150 */
00151 
00152 static char *make_search_key(const char *filter, const char *lookupkey)
00153 {
00154        size_t l=strlen(filter)+1;
00155        char *p, *q;
00156        const char *cp;
00157 
00158        for (cp=filter; *cp; cp++)
00159               if (*cp == '@')
00160                      l += strlen(lookupkey);
00161 
00162        p=malloc(l);
00163        if (!p)
00164               return NULL;
00165 
00166        for (q=p, cp=filter; *cp; cp++)
00167        {
00168               if (*cp == '@')
00169               {
00170                      const char *k=lookupkey;
00171 
00172                      while ( (*q++ = *k++ ) != 0)
00173                             ;
00174                      --q;
00175                      continue;
00176               }
00177               *q++ = *cp;
00178        }
00179        *q=0;
00180        return p;
00181 }
00182 
00183 static int l_search_do_filter(struct ldapsearch *s,
00184 
00185                            int (*callback_func)(const char *utf8_name,
00186                                              const char *address,
00187                                              void *callback_arg),
00188                            void *callback_arg,
00189 
00190                            const char *filter,
00191                            const char *lookup_key,
00192                            int *found);
00193 
00194 
00195 int l_search_do(struct ldapsearch *s,
00196               const char *lookupkey,
00197 
00198               int (*callback_func)(const char *utf8_name,
00199                                  const char *address,
00200                                  void *callback_arg),
00201               void *callback_arg)
00202 {
00203        char *k;
00204        const char *filter;
00205        int rc_code;
00206        int found;
00207 
00208        k=encode_key(lookupkey);
00209        if (!k)
00210               return -1;
00211 
00212        filter=getenv("LDAP_SEARCH_FILTER_EXACT");
00213        if (!filter)
00214               filter="(|(uid=@)(sn=@)(cn=@))";
00215 
00216        rc_code=l_search_do_filter(s, callback_func, callback_arg,
00217                                filter, k, &found);
00218 
00219        if (rc_code == 0 && !found)
00220        {
00221               filter=getenv("LDAP_SEARCH_FILTER_APPROX");
00222               if (!filter)
00223                      filter="(|(uid=@*)(sn=@*)(mail=@*)(cn=@*))";
00224 
00225               rc_code=l_search_do_filter(s, callback_func, callback_arg,
00226                                       filter, k, &found);
00227        }
00228        free(k);
00229        return rc_code;
00230 }
00231 
00232 static int l_search_do_filter(struct ldapsearch *s,
00233                            int (*callback_func)(const char *utf8_name,
00234                                              const char *address,
00235                                              void *callback_arg),
00236                            void *callback_arg,
00237                            const char *filter,
00238                            const char *lookup_key,
00239                            int *found)
00240 {
00241        char *kk;
00242        struct timeval tv;
00243        LDAPMessage *result;
00244        char *attrs[3];
00245        int rc_code=0;
00246        int msgidp;
00247 
00248        *found=0;
00249 
00250        kk=make_search_key(filter, lookup_key);
00251 
00252        if (!kk)
00253               return -1;
00254 
00255        if (s->handle == NULL)
00256        {
00257               errno=ETIMEDOUT;  /* Timeout previously */
00258               return -1;
00259        }
00260 
00261 
00262        attrs[0]="cn";
00263        attrs[1]="mail";
00264        attrs[2]=NULL;
00265 
00266        tv.tv_sec=60*60;
00267        tv.tv_usec=0;
00268 
00269        if (ldap_search_ext(s->handle, s->base, LDAP_SCOPE_SUBTREE,
00270                          kk, attrs, 0, NULL, NULL, &tv, 1000000, &msgidp)
00271            != LDAP_SUCCESS)
00272               return -1;
00273 
00274        do
00275        {
00276               int rc;
00277               LDAPMessage *msg;
00278 
00279               const char *timeout=getenv("LDAP_SEARCH_TIMEOUT");
00280 
00281               tv.tv_sec=atoi(timeout ? timeout:"30");
00282               tv.tv_usec=0;
00283 
00284               rc=ldap_result(s->handle, msgidp, 0, &tv, &result);
00285 
00286               if (rc <= 0)
00287               {
00288                      if (rc == 0)
00289                             errno=ETIMEDOUT;
00290 
00291                      ldap_unbind_ext(s->handle, NULL, NULL);
00292                      s->handle=NULL;
00293                      rc_code= -1;
00294                      break;
00295               }
00296 
00297               if (rc == LDAP_RES_SEARCH_RESULT)
00298               {
00299                      ldap_msgfree(result);
00300                      break; /* End of search */
00301               }
00302 
00303               if (rc != LDAP_RES_SEARCH_ENTRY)
00304               {
00305                      ldap_msgfree(result);
00306                      continue;
00307               }
00308 
00309               for (msg=ldap_first_message(s->handle, result); msg;
00310                    msg=ldap_next_message(s->handle, msg))
00311               {
00312                      struct berval **n_val=
00313                             ldap_get_values_len(s->handle, msg, "cn");
00314                      struct berval **a_val=
00315                             ldap_get_values_len(s->handle, msg, "mail");
00316 
00317                      if (n_val && a_val)
00318                      {
00319                             size_t i, j;
00320 
00321                             for (i=0; n_val[i]; i++)
00322                                    for (j=0; a_val[j]; j++)
00323                                    {
00324                                           char *p=malloc(n_val[i]->bv_len
00325                                                         +1);
00326                                           char *q=malloc(a_val[j]->bv_len
00327                                                         +1);
00328 
00329                                           if (!p || !q)
00330                                           {
00331                                                  if (p) free(p);
00332                                                  if (q) free(q);
00333                                                  rc_code= -1;
00334                                                  break;
00335                                           }
00336 
00337                                           memcpy(p, n_val[i]->bv_val,
00338                                                  n_val[i]->bv_len);
00339                                           p[n_val[i]->bv_len]=0;
00340 
00341                                           memcpy(q, a_val[j]->bv_val,
00342                                                  a_val[j]->bv_len);
00343                                           q[a_val[j]->bv_len]=0;
00344 
00345                                           rc_code=(*callback_func)
00346                                                  (p, q, callback_arg);
00347                                           free(p);
00348                                           free(q);
00349                                           if (rc_code)
00350                                                  break;
00351                                           *found=1;
00352                                    }
00353                      }
00354                      if (n_val)
00355                             ldap_value_free_len(n_val);
00356                      if (a_val)
00357                             ldap_value_free_len(a_val);
00358               }
00359 
00360               ldap_msgfree(result);
00361        } while (rc_code == 0);
00362        return rc_code;
00363 }
00364 
00365 int l_search_ping(struct ldapsearch *s)
00366 {
00367        char *attrs[2];
00368        struct timeval tv;
00369        LDAPMessage *result;
00370        int rc;
00371        int msgid;
00372 
00373        if (s->handle == NULL)
00374        {
00375               errno=ETIMEDOUT;  /* Timeout previously */
00376               return -1;
00377        }
00378 
00379        attrs[0]="objectClass";
00380        attrs[1]=NULL;
00381 
00382        tv.tv_sec=60*60;
00383        tv.tv_usec=0;
00384 
00385        if (ldap_search_ext(s->handle, s->base, LDAP_SCOPE_BASE,
00386                          "objectClass=*", attrs, 0, NULL, NULL, &tv,
00387                          1000000, &msgid) < 0)
00388               return -1;
00389 
00390        do
00391        {
00392               const char *timeout=getenv("LDAP_SEARCH_TIMEOUT");
00393 
00394               tv.tv_sec=atoi(timeout ? timeout:"30");
00395               tv.tv_usec=0;
00396 
00397               rc=ldap_result(s->handle, msgid, 0, &tv, &result);
00398 
00399               if (rc <= 0)
00400               {
00401                      if (rc == 0)
00402                             errno=ETIMEDOUT;
00403 
00404                      ldap_unbind_ext(s->handle, NULL, NULL);
00405                      s->handle=NULL;
00406 
00407                      return -1;
00408               }
00409 
00410               ldap_msgfree(result);
00411        } while (rc != LDAP_RES_SEARCH_RESULT);
00412        return 0;
00413 }
00414 
00415 #if 0
00416 
00417 #include <stdio.h>
00418 
00419 static int cb(const char *utf8_name,
00420              const char *address,
00421              void *callback_arg)
00422 {
00423        printf("\"%s\" <%s>\n", utf8_name, address);
00424        return 0;
00425 }
00426 
00427 int main(int argc, char **argv)
00428 {
00429        struct ldapsearch *s=l_search_alloc("localhost", 389,
00430                                        "dc=courier-mta,dc=com");
00431        int n;
00432 
00433        if (!s)
00434        {
00435               perror("l_search_alloc");
00436               exit(1);
00437        }
00438 
00439        for (n=1; n<argc; n++)
00440        {
00441               if (l_search_do(s, argv[n], cb, NULL) != 0)
00442               {
00443                      printf("l_search_do: error\n");
00444               }
00445        }
00446        l_search_free(s);
00447        return 0;
00448 }
00449 #endif