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
24  */
25 
26 /*
27  * !!! this doesn't do any caching. It really should.
28  *
29  * !!! this blocks for every auth.
30  */
31 
32 #include <stdio.h>
33 
34 #define _XOPEN_SOURCE 500	// need this to get crypt()
35 #include "c2s.h"
36 
37 #ifdef STORAGE_LDAP
38 #ifdef HAVE_CRYPT
39 #include <unistd.h>
40 #endif
41 
42 #ifdef HAVE_SSL
43 #include <openssl/rand.h>
44 #include <openssl/evp.h>
45 #endif
46 
47 #include <lber.h>
48 #define LDAP_DEPRECATED 1
49 #include <ldap.h>
50 
51 #define LDAPFULL_PASSBUF_MAX 257
52 #define LDAPFULL_DN_MAX 4096
53 
54 #define LDAPFULL_SRVTYPE_LDAP 1
55 #define LDAPFULL_SRVTYPE_AD 2
56 
57 #define LDAPFULL_SEARCH_MAX_RETRIES 1
58 
59 /** internal structure, holds our data */
60 typedef struct moddata_st
61 {
62     authreg_t ar;
63 
64     LDAP *ld;
65 
66     const char *uri;
67 
68     const char *binddn;
69     const char *bindpw;
70 
71     const char *objectclass;
72     const char *uidattr;
73     const char *validattr;
74     const char *group_dn;
75     const char *pwattr;
76     const char *pwscheme;
77 
78     int fulluid; // use "uid@realm" in ldap searches (1) or just use "uid" (0)
79     int binded; // if we are binded with binddn and bindpw, then 1, otherwise 0
80 
81     int srvtype;
82 
83     xht basedn;
84     const char *default_basedn;
85 } *moddata_t;
86 
87 //////////////////////////////////////////////////////////////////////////////
88 //
89 // Here is stuff for hashing passwords
90 // ideas and some part of code are taken from cyrus-sasl/saslauthd
91 //
92 //////////////////////////////////////////////////////////////////////////////
93 
94 #ifdef HAVE_SSL
95 #include <openssl/evp.h>
96 #include <openssl/des.h>
97 #endif
98 
99 typedef struct _ldapfull_pw_scheme {
100     char *name;
101     char *scheme;
102     char *prefix;
103     int saltlen;
104     int (*check) (moddata_t data, const char *scheme, int salted, const char *hash, const char *passwd);
105     int (*set) (moddata_t data, const char *scheme, const char *prefix, int saltlen, const char *passwd, char *buf, int buflen);
106 } ldapfull_pw_scheme;
107 
108 int _ldapfull_hash_init(); // call it before use of other stuff
109 #ifdef HAVE_SSL
110 static int _ldapfull_chk_hashed(moddata_t data, const char *scheme, int salted, const char *hash, const char *passwd);
111 static int _ldapfull_set_hashed(moddata_t data, const char *scheme, const char *prefix, int saltlen, const char *passwd, char *buf, int buflen);
112 #endif
113 #ifdef HAVE_CRYPT
114 static int _ldapfull_chk_crypt(moddata_t data, const char *scheme, int salted, const char *hash, const char *passwd);
115 static int _ldapfull_set_crypt(moddata_t data, const char *scheme, const char *prefix, int saltlen, const char *passwd, char *buf, int buflen);
116 #endif
117 static int _ldapfull_chk_clear(moddata_t data, const char *scheme, int salted, const char *hash, const char *passwd);
118 static int _ldapfull_set_clear(moddata_t data, const char* scheme, const char* prefix, int saltlen, const char* passwd, char* buf, int buflen);
119 
120 static int _ldapfull_check_passhash(moddata_t data, const char *hash, const char *passwd);
121 static int _ldapfull_set_passhash(moddata_t data, const char* scheme_name, const char* passwd, char* buf, int buflen);
122 static int _ldapfull_check_password_bind(authreg_t ar, const char *username, const char *realm, char password[LDAPFULL_PASSBUF_MAX]);
123 
124 ldapfull_pw_scheme _ldapfull_pw_schemas[] = {
125 #ifdef HAVE_SSL
126     { "sha", "sha1", "{SHA}", 0, _ldapfull_chk_hashed, _ldapfull_set_hashed },
127     { "ssha", "sha1", "{SSHA}", 4, _ldapfull_chk_hashed, _ldapfull_set_hashed },
128 #endif
129 #ifdef HAVE_CRYPT
130     { "crypt", "crypt", "", 2, _ldapfull_chk_crypt, _ldapfull_set_crypt },
131 #endif
132     { "clear", "", "", 0, _ldapfull_chk_clear, _ldapfull_set_clear },
133     { "bind", "", "", 0, NULL, NULL },
134     { NULL, NULL, NULL, 0, NULL, NULL }
135 };
136 
137 
138 // general check_password
139 // returns 1 if password is checked, 0 otherwise
_ldapfull_check_passhash(moddata_t data,const char * hash,const char * passwd)140 int _ldapfull_check_passhash(moddata_t data, const char *hash, const char *passwd) {
141     int n;
142     int plen;
143     int hlen;
144 
145     if( ! hash ) {
146         log_write(data->ar->c2s->log,LOG_ERR,"_ldapfull_check_passhash: hash is NULL");
147         return 0;
148     }
149     if( ! passwd ) {
150         log_write(data->ar->c2s->log,LOG_ERR,"_ldapfull_check_passhash: passwd is NULL");
151         return 0;
152     }
153 
154     hlen = strlen(hash);
155 
156     for( n=0 ; _ldapfull_pw_schemas[n].name != NULL ; n++ ) {
157         plen = strlen(_ldapfull_pw_schemas[n].prefix);
158         if( (plen <= hlen) && !strncmp(hash,_ldapfull_pw_schemas[n].prefix,plen) ) {
159             // if scheme found is cleartext and hash begins with '{', than maybe it is
160             // unknown scheme, so don't pass it
161             if( ! strlen(_ldapfull_pw_schemas[n].scheme) && hlen ) {
162                 if( hash[0] == '{' ) {
163                     continue;
164                 }
165             }
166             if( _ldapfull_pw_schemas[n].check ) {
167               return _ldapfull_pw_schemas[n].check(
168                   data,
169                   _ldapfull_pw_schemas[n].scheme,
170                   _ldapfull_pw_schemas[n].saltlen,
171                   hash + plen,passwd);
172             } else {
173                 log_write(data->ar->c2s->log,LOG_ERR,"_ldapfull_check_passhash: no check function for schema %s",
174                         _ldapfull_pw_schemas[n].name);
175                 return 0;
176             }
177         }
178     }
179     return 0;
180 }
181 
182 // general set_password
183 // returns 1 if password in buf is set, 0 otherwise
184 // must provide with buffer of sufficient length, or it will fail
_ldapfull_set_passhash(moddata_t data,const char * scheme_name,const char * passwd,char * buf,int buflen)185 int _ldapfull_set_passhash(moddata_t data, const char *scheme_name, const char *passwd, char *buf, int buflen) {
186     int n;
187 
188     if( ! passwd ) {
189         log_write(data->ar->c2s->log,LOG_ERR,"_ldapfull_set_passhash: passwd is NULL");
190         return 0;
191     }
192     if( ! buf ) {
193         log_write(data->ar->c2s->log,LOG_ERR,"_ldapfull_set_passhash: buf is NULL");
194         return 0;
195     }
196 
197     for( n=0 ; _ldapfull_pw_schemas[n].name != NULL ; n++ ) {
198         if( !strcmp(scheme_name,_ldapfull_pw_schemas[n].name) ) {
199             if( _ldapfull_pw_schemas[n].set ) {
200               return _ldapfull_pw_schemas[n].set(
201                   data,
202                   _ldapfull_pw_schemas[n].scheme,
203                   _ldapfull_pw_schemas[n].prefix,
204                   _ldapfull_pw_schemas[n].saltlen,
205                   passwd, buf, buflen);
206             } else {
207                 log_write(data->ar->c2s->log,LOG_ERR,"_ldapfull_set_passhash: no set function for schema %s",
208                         _ldapfull_pw_schemas[n].name);
209                 return 0;
210             }
211         }
212     }
213     return 0;
214 }
215 
_ldapfull_chk_clear(moddata_t data,const char * scheme,int salted,const char * hash,const char * passwd)216 int _ldapfull_chk_clear(moddata_t data, const char *scheme, int salted, const char *hash, const char *passwd) {
217     return !strcmp(hash,passwd);
218 }
219 
_ldapfull_set_clear(moddata_t data,const char * scheme,const char * prefix,int saltlen,const char * passwd,char * buf,int buflen)220 int _ldapfull_set_clear(moddata_t data, const char *scheme, const char *prefix, int saltlen, const char *passwd, char *buf, int buflen) {
221     if( buflen <= strlen(passwd) ) {
222         log_write(data->ar->c2s->log,LOG_ERR,"_ldapfull_set_clear: buffer is too short (%i bytes)",buflen);
223         return 0;
224     }
225     strcpy(buf, passwd);
226     return 1;
227 }
228 
229 #ifdef HAVE_SSL
_ldapfull_base64_decode(const char * src,const unsigned char ** ret,int * rlen)230 int _ldapfull_base64_decode( const char *src, const unsigned char **ret, int *rlen ) {
231     int rc, tlen = 0;
232     int i;
233     unsigned char *text;
234 #if OPENSSL_VERSION_NUMBER < 0x10100005L
235     EVP_ENCODE_CTX EVP_ctx;
236 #else
237     EVP_ENCODE_CTX *EVP_ctx;
238 #endif
239 
240     text = (unsigned char *)malloc(((strlen(src)+3)/4 * 3) + 1);
241     if (text == NULL) {
242         return 0;
243     }
244 
245 #if OPENSSL_VERSION_NUMBER < 0x10100005L
246     EVP_DecodeInit(&EVP_ctx);
247     rc = EVP_DecodeUpdate(&EVP_ctx, text, &i, (const unsigned char *)src, strlen(src));
248     if (rc < 0) {
249         free(text);
250         return 0;
251     }
252     tlen+=i;
253     EVP_DecodeFinal(&EVP_ctx, (unsigned char*)text, &i);
254 #else
255     EVP_ctx = EVP_ENCODE_CTX_new();
256     EVP_DecodeInit(EVP_ctx);
257     rc = EVP_DecodeUpdate(EVP_ctx, text, &i, (const unsigned char *)src, strlen(src));
258     if (rc < 0) {
259         free(text);
260         EVP_ENCODE_CTX_free(EVP_ctx);
261         return 0;
262     }
263     tlen+=i;
264     EVP_DecodeFinal(EVP_ctx, (unsigned char*)text, &i);
265 #endif
266 
267     *ret = text;
268     if (rlen != NULL) {
269         *rlen = tlen;
270     }
271 
272 #if !(OPENSSL_VERSION_NUMBER < 0x10100005L)
273     EVP_ENCODE_CTX_free(EVP_ctx);
274 #endif
275     return 1;
276 }
277 
_ldapfull_base64_encode(const unsigned char * src,int srclen,char ** ret,int * rlen)278 static int _ldapfull_base64_encode( const unsigned char *src, int srclen, char **ret, int *rlen ) {
279     int tlen = 0;
280     unsigned char *text;
281 #if OPENSSL_VERSION_NUMBER < 0x10100005L
282     EVP_ENCODE_CTX EVP_ctx;
283 #else
284     EVP_ENCODE_CTX *EVP_ctx;
285 #endif
286 
287     text = (unsigned char *)malloc((srclen*4/3) + 1 );
288     if (text == NULL) {
289         return 0;
290     }
291 
292 #if OPENSSL_VERSION_NUMBER < 0x10100005L
293     EVP_EncodeInit(&EVP_ctx);
294     EVP_EncodeUpdate(&EVP_ctx, text, &tlen, src, srclen);
295     EVP_EncodeFinal(&EVP_ctx, text, &tlen);
296 #else
297     EVP_ctx = EVP_ENCODE_CTX_new();
298     EVP_EncodeInit(EVP_ctx);
299     EVP_EncodeUpdate(EVP_ctx, text, &tlen, src, srclen);
300     EVP_EncodeFinal(EVP_ctx, text, &tlen);
301 #endif
302 
303     *ret = (char*)text;
304     if (rlen != NULL) {
305         *rlen = tlen;
306     }
307 
308 #if !(OPENSSL_VERSION_NUMBER < 0x10100005L)
309     EVP_ENCODE_CTX_free(EVP_ctx);
310 #endif
311     return 1;
312 }
313 
_ldapfull_chk_hashed(moddata_t data,const char * scheme,int salted,const char * hash,const char * passwd)314 int _ldapfull_chk_hashed(moddata_t data, const char *scheme, int salted, const char *hash, const char *passwd) {
315     const unsigned char *bhash; // binary hash, will get it from base64
316     EVP_MD_CTX *mdctx;
317     const EVP_MD *md;
318     unsigned char digest[EVP_MAX_MD_SIZE];
319     int bhlen, rc;
320 
321     md = EVP_get_digestbyname(scheme);
322     if (!md) {
323         return 0;
324     }
325     if( ! _ldapfull_base64_decode(hash, &bhash, &bhlen) ) {
326         return 0;
327     }
328 
329 #if OPENSSL_VERSION_NUMBER < 0x10100005L
330     mdctx = EVP_MD_CTX_create();
331 #else
332     mdctx = EVP_MD_CTX_new();
333 #endif
334     EVP_DigestInit(mdctx, md);
335     EVP_DigestUpdate(mdctx, passwd, strlen(passwd));
336     if (salted) {
337         EVP_DigestUpdate(mdctx, &bhash[EVP_MD_size(md)],
338                 bhlen - EVP_MD_size(md));
339     }
340     EVP_DigestFinal(mdctx, digest, NULL);
341 
342     rc = memcmp((char *)bhash, (char *)digest, EVP_MD_size(md));
343     free((void*)bhash);
344 #if OPENSSL_VERSION_NUMBER < 0x10100005L
345     EVP_MD_CTX_destroy(mdctx);
346 #else
347     EVP_MD_CTX_free(mdctx);
348 #endif
349     return !rc;
350 }
351 
_ldapfull_set_hashed(moddata_t data,const char * scheme,const char * prefix,int saltlen,const char * passwd,char * buf,int buflen)352 int _ldapfull_set_hashed(moddata_t data, const char *scheme, const char *prefix, int saltlen, const char *passwd, char *buf, int buflen) {
353     char *hash = 0; // base64 hash
354     EVP_MD_CTX *mdctx;
355     const EVP_MD *md;
356     unsigned char *digest;
357     unsigned char *salt;
358     int hlen=0;
359     int plen, rc;
360     unsigned int dlen;
361 
362     md = EVP_get_digestbyname(scheme);
363     if (!md) {
364         return 0;
365     }
366 
367 #if OPENSSL_VERSION_NUMBER < 0x10100005L
368     mdctx = EVP_MD_CTX_create();
369 #else
370     mdctx = EVP_MD_CTX_new();
371 #endif
372     EVP_DigestInit(mdctx, md);
373     EVP_DigestUpdate(mdctx, passwd, strlen(passwd));
374     if (saltlen) {
375         salt = (unsigned char *)malloc(saltlen);
376         if( !salt ) {
377 #if OPENSSL_VERSION_NUMBER < 0x10100005L
378             EVP_MD_CTX_destroy(mdctx);
379 #else
380             EVP_MD_CTX_free(mdctx);
381 #endif
382             return 0;
383         }
384         if( !RAND_bytes(salt,saltlen) ) {
385 #if OPENSSL_VERSION_NUMBER < 0x10100005L
386             EVP_MD_CTX_destroy(mdctx);
387 #else
388             EVP_MD_CTX_free(mdctx);
389 #endif
390             free(salt);
391             return 0;
392         }
393         EVP_DigestUpdate(mdctx, salt, saltlen);
394     }
395     digest = (unsigned char *)malloc(EVP_MD_size(md) + saltlen);
396     if( !digest ) {
397         if (saltlen) {
398             free(salt);
399         }
400 #if OPENSSL_VERSION_NUMBER < 0x10100005L
401         EVP_MD_CTX_destroy(mdctx);
402 #else
403         EVP_MD_CTX_free(mdctx);
404 #endif
405         return 0;
406     }
407     EVP_DigestFinal(mdctx, digest, &dlen);
408 
409     memcpy(digest+dlen,salt,saltlen);
410     if (saltlen) {
411         free(salt);
412     }
413     rc = _ldapfull_base64_encode(digest, dlen+saltlen, &hash, &hlen);
414     if( hash[hlen-1] == '\n' ) {
415         hash[--hlen] = '\0';
416     }
417     free(digest);
418     if( !rc ) {
419         free(hash);
420 #if OPENSSL_VERSION_NUMBER < 0x10100005L
421         EVP_MD_CTX_destroy(mdctx);
422 #else
423         EVP_MD_CTX_free(mdctx);
424 #endif
425         return 0;
426     }
427 
428     plen = strlen(prefix);
429     if( hlen + plen >= buflen ) {
430         log_write(data->ar->c2s->log,LOG_ERR,"_ldapfull_set_hashed: buffer is too short (%i bytes)",buflen);
431         free(hash);
432 #if OPENSSL_VERSION_NUMBER < 0x10100005L
433         EVP_MD_CTX_destroy(mdctx);
434 #else
435         EVP_MD_CTX_free(mdctx);
436 #endif
437         return 0;
438     }
439     memcpy(buf,prefix,plen);
440     memcpy(buf+plen,hash,hlen);
441     buf[hlen+plen]='\0';
442     free(hash);
443 #if OPENSSL_VERSION_NUMBER < 0x10100005L
444     EVP_MD_CTX_destroy(mdctx);
445 #else
446     EVP_MD_CTX_free(mdctx);
447 #endif
448 
449     return 1;
450 }
451 #endif // HAVE_SSL
452 
453 #ifdef HAVE_CRYPT
454 /** Check UNIX style crypt hashed password */
_ldapfull_chk_crypt(moddata_t data,const char * scheme,int salted,const char * hash,const char * passwd)455 int _ldapfull_chk_crypt(moddata_t data, const char *scheme, int salted, const char *hash, const char *passwd) {
456     const char *encrypted;
457     char salt[3];
458     if (strlen(hash) != 13) {
459         log_write(data->ar->c2s->log, LOG_ERR, "Invalid crypt hash length %d", strlen(hash));
460         return 0;
461     }
462     salt[0] = hash[0];
463     salt[1] = hash[1];
464     salt[2] = 0;
465     encrypted = crypt(passwd, salt);
466     return !strcmp(encrypted, hash);
467 }
468 
_ldapfull_set_crypt(moddata_t data,const char * scheme,const char * prefix,int saltlen,const char * passwd,char * buf,int buflen)469 int _ldapfull_set_crypt(moddata_t data, const char *scheme, const char *prefix, int saltlen, const char *passwd, char *buf, int buflen) {
470     const char *encrypted;
471     char salt[3];
472     static const char saltchars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
473     if ((saltlen != 2) || (buflen < 14)) {
474         log_write(data->ar->c2s->log, LOG_ERR, "Invalid crypt hash params");
475         return 0;
476     }
477 #ifdef HAVE_SSL
478     if( !RAND_bytes((unsigned char*)salt, saltlen) )
479         return 0;
480     salt[0] = saltchars[salt[0] % 64];
481     salt[1] = saltchars[salt[1] % 64];
482     salt[2] = 0;
483 #else
484     /* Note: This is not a cryptographically secure random number generator */
485     salt[0] = saltchars[random() % 64];
486     salt[1] = saltchars[random() % 64];
487     salt[2] = 0;
488 #endif
489     encrypted = crypt(passwd, salt);
490     strncpy(buf, encrypted, buflen);
491     buf[buflen-1] = 0;
492     return 1;
493 }
494 #endif // HAVE_CRYPT
495 
496 
497 /** Makes a copy of enough LDAP data in order to establish a second connection */
copy_ldap_config(moddata_t from,moddata_t to)498 static void copy_ldap_config(moddata_t from, moddata_t to)
499 {
500     memset(to, 0, sizeof(struct moddata_st));
501     to->uri = from->uri;
502     to->ar = from->ar;
503 }
504 
_ldapfull_hash_init()505 int _ldapfull_hash_init() {
506 #ifdef HAVE_SSL
507     OpenSSL_add_all_digests();
508 #else
509     srandom(time(NULL) ^ getpid());
510 #endif
511     return 1;
512 }
513 //////////////////////////////////////////////////////////////////////////////
514 //
515 // end of stuff for hashing passwords
516 //
517 //////////////////////////////////////////////////////////////////////////////
518 
519 
520 /** utility function to get ld_errno */
_ldapfull_get_lderrno(LDAP * ld)521 static int _ldapfull_get_lderrno(LDAP *ld)
522 {
523     int ld_errno;
524 
525     ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
526 
527     return ld_errno;
528 }
529 
530 /** connect to the ldap host */
_ldapfull_connect(moddata_t data)531 static int _ldapfull_connect(moddata_t data)
532 {
533     int ldapversion = LDAP_VERSION3;
534     int rc;
535 
536     if(data->ld != NULL)
537         ldap_unbind_s(data->ld);
538 
539     data->binded=0;
540 
541     rc = ldap_initialize(&(data->ld), data->uri);
542     if( rc != LDAP_SUCCESS )
543     {
544         log_write(data->ar->c2s->log, LOG_ERR, "ldap: ldap_initialize failed, uri=%s (%d): %s", data->uri, rc, ldap_err2string(rc));
545         return 1;
546     }
547 
548     if (ldap_set_option(data->ld, LDAP_OPT_PROTOCOL_VERSION, &ldapversion) != LDAP_SUCCESS)
549     {
550         log_write(data->ar->c2s->log, LOG_ERR, "ldap: couldn't set v3 protocol");
551         return 1;
552     }
553 
554     if (ldap_set_option(data->ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON) != LDAP_SUCCESS) {
555         log_write(data->ar->c2s->log, LOG_ERR, "ldap: couldn't set LDAP_OPT_REFERRALS");
556     }
557 
558     log_debug(ZONE, "connected to ldap server");
559 
560     return 0;
561 }
562 
563 /** unbind and clear variables */
_ldapfull_unbind(moddata_t data)564 static int _ldapfull_unbind(moddata_t data) {
565     ldap_unbind_s(data->ld);
566     data->ld = NULL;
567     data->binded = 0;
568     log_debug(ZONE, "unbinded from ldap server");
569     return 0;
570 }
571 
572 /** connect to ldap and bind as data->binddn */
_ldapfull_connect_bind(moddata_t data)573 static int _ldapfull_connect_bind(moddata_t data)
574 {
575     if(data->ld != NULL && data->binded ) {
576         return 0;
577     }
578 
579     if( _ldapfull_connect(data) ) {
580         return 1;
581     }
582 
583     if(ldap_simple_bind_s(data->ld, data->binddn, data->bindpw))
584     {
585         log_write(data->ar->c2s->log, LOG_ERR, "ldap: bind as '%s' failed: %s", data->binddn, ldap_err2string(_ldapfull_get_lderrno(data->ld)));
586         _ldapfull_unbind(data);
587         return 1;
588     }
589 
590     log_debug(ZONE, "binded to ldap server");
591     data->binded = 1;
592     return 0;
593 }
594 
595 /** do a search, return the dn */
_ldapfull_search(moddata_t data,const char * realm,const char * username)596 static char *_ldapfull_search(moddata_t data, const char *realm, const char *username)
597 {
598     char validfilter[256], filter[1024], *dn, *no_attrs[] = { NULL };
599     const char *basedn;
600     LDAPMessage *result, *entry;
601     int tried = 0;
602 
603     log_debug(ZONE, "searching for %s", username);
604 
605     basedn = xhash_get(data->basedn, realm);
606     if(basedn == NULL)
607         basedn = data->default_basedn;
608 
609     if(basedn == NULL) {
610         log_write(data->ar->c2s->log, LOG_ERR, "ldap: no basedn specified for realm '%s'", realm);
611         _ldapfull_unbind(data);
612         return NULL;
613     }
614 
615     // for AD validattr should be =TRUE, for [open]ldap =1
616     if( data->validattr ) {
617         validfilter[0] = '\0';
618         if( data->srvtype == LDAPFULL_SRVTYPE_AD ) {
619             snprintf(validfilter, 256, "(%s=TRUE)", data->validattr);
620         } else {
621             snprintf(validfilter, 256, "(%s=1)", data->validattr);
622         }
623         if( data->fulluid ) {
624             snprintf(filter, 1024, "(&(objectClass=%s)%s(%s=%s@%s))", data->objectclass, validfilter, data->uidattr, username, realm);
625         } else {
626             snprintf(filter, 1024, "(&(objectClass=%s)%s(%s=%s))", data->objectclass, validfilter, data->uidattr, username);
627         }
628     } else {
629         if( data->fulluid ) {
630             snprintf(filter, 1024, "(&(objectClass=%s)(%s=%s@%s))", data->objectclass, data->uidattr, username, realm);
631         } else {
632             snprintf(filter, 1024, "(&(objectClass=%s)(%s=%s))", data->objectclass, data->uidattr, username);
633         }
634     }
635 
636     log_debug(ZONE, "search filter: %s", filter);
637 
638 retry:
639     if(ldap_search_s(data->ld, basedn, LDAP_SCOPE_SUBTREE, filter, no_attrs, 0, &result))
640     {
641         if( tried++ < LDAPFULL_SEARCH_MAX_RETRIES ) {
642             log_debug(ZONE, "ldap: search fail, will retry; %s: %s", filter, ldap_err2string(_ldapfull_get_lderrno(data->ld)));
643             _ldapfull_unbind(data);
644             if( _ldapfull_connect_bind(data) == 0 ) {
645                 goto retry;
646             } else {
647                 return NULL;
648             }
649         }
650         log_write(data->ar->c2s->log, LOG_ERR, "ldap: search %s failed: %s", filter, ldap_err2string(_ldapfull_get_lderrno(data->ld)));
651         _ldapfull_unbind(data);
652         return NULL;
653     }
654 
655     entry = ldap_first_entry(data->ld, result);
656     if(entry == NULL)
657     {
658         ldap_msgfree(result);
659 
660         return NULL;
661     }
662 
663     dn = ldap_get_dn(data->ld, entry);
664 
665     ldap_msgfree(result);
666 
667     log_debug(ZONE, "found user %s: dn=%s", username, dn);
668 
669     return dn;
670 }
671 
672 /** Is this user part of the given LDAP group? */
_ldapfull_user_in_group(moddata_t data,const char * user_dn,const char * group_dn)673 static int _ldapfull_user_in_group(moddata_t data, const char *user_dn, const char *group_dn)
674 {
675     LDAPMessage *result, *entry;
676     int tried = 0;
677     char filter[1024];
678 
679     log_debug(ZONE, "checking whether user with dn %s is in group %s", user_dn, group_dn);
680 
681     memset(filter, 0, 1024);
682     snprintf(filter, 1024, "(member=%s)", user_dn); // TODO Check if snprintf result was truncated
683 
684     retry:
685     if(ldap_search_s(data->ld, group_dn, LDAP_SCOPE_BASE, filter, NULL, 0, &result))
686     {
687         if( tried++ < LDAPFULL_SEARCH_MAX_RETRIES ) {
688             log_debug(ZONE, "ldap: group search fail, will retry; %s: %s", filter, ldap_err2string(_ldapfull_get_lderrno(data->ld)));
689             _ldapfull_unbind(data);
690             if( _ldapfull_connect_bind(data) == 0 ) {
691                 goto retry;
692             } else {
693                 return 0;
694             }
695         }
696         log_write(data->ar->c2s->log, LOG_ERR, "ldap: group search %s failed: %s", filter, ldap_err2string(_ldapfull_get_lderrno(data->ld)));
697         _ldapfull_unbind(data);
698         return 0;
699     }
700 
701     entry = ldap_first_entry(data->ld, result);
702     if(entry == NULL)
703     {
704         ldap_msgfree(result);
705 
706         return 0;
707     }
708     else
709     {
710         ldap_msgfree(result);
711 
712         return 1;
713     }
714 }
715 
716 /** Get distinguished name for this user if we have it */
_ldapfull_find_user_dn(moddata_t data,const char * username,const char * realm,const char ** dn)717 static int _ldapfull_find_user_dn(moddata_t data, const char *username, const char *realm, const char **dn)
718 {
719     *dn = NULL;
720     if(_ldapfull_connect_bind(data))
721         return 0; // error
722 
723     log_debug(ZONE, "checking existance of %s", username);
724 
725     *dn = _ldapfull_search(data, realm, username);
726     return *dn != NULL;
727 }
728 
729 /** do we have this user? */
_ldapfull_user_exists(authreg_t ar,sess_t sess,const char * username,const char * realm)730 static int _ldapfull_user_exists(authreg_t ar, sess_t sess, const char *username, const char *realm)
731 {
732     const char *dn;
733     if (_ldapfull_find_user_dn((moddata_t) ar->private, username, realm, &dn)) {
734         if(((moddata_t) ar->private)->group_dn != NULL
735             && !_ldapfull_user_in_group((moddata_t) ar->private, dn, ((moddata_t) ar->private)->group_dn)) {
736             ldap_memfree((void*)dn);
737             return 0;
738             }
739         ldap_memfree((void*)dn);
740         return 1;
741     }
742     return 0;
743 }
744 
745 /** This method determines the DN of the user and does a new simple bind of the LDAP
746 server. If the server allows it, the user has been authenticated.
747 */
_ldapfull_check_password_bind(authreg_t ar,const char * username,const char * realm,char password[LDAPFULL_PASSBUF_MAX])748 static int _ldapfull_check_password_bind(authreg_t ar, const char *username, const char *realm, char password[LDAPFULL_PASSBUF_MAX])
749 {
750     moddata_t data = (moddata_t) ar->private;
751     struct moddata_st bind_data;
752     int invalid;
753     const char *dn;
754 
755     if (!_ldapfull_find_user_dn(data, username, realm, &dn)) {
756         log_debug(ZONE, "User %s not found", username);
757         return 1;
758     }
759 
760     /* Try logging in to the LDAP server as this user's DN */
761     copy_ldap_config(data, &bind_data);
762     bind_data.binddn = dn;
763     bind_data.bindpw = password;
764     invalid = _ldapfull_connect_bind(&bind_data);
765     if (!invalid)
766         _ldapfull_unbind(&bind_data);
767     ldap_memfree((void*)dn);
768     return invalid;
769 }
770 
771 // get password from jabberPassword attribute
_ldapfull_get_password(authreg_t ar,sess_t sess,const char * username,const char * realm,char password[LDAPFULL_PASSBUF_MAX])772 static int _ldapfull_get_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[LDAPFULL_PASSBUF_MAX]) {
773     moddata_t data = (moddata_t) ar->private;
774     LDAPMessage *result, *entry;
775     const char *dn, *no_attrs[] = { data->pwattr, NULL };
776     char **vals;
777 
778     log_debug(ZONE, "getting password for %s", username);
779 
780     if( _ldapfull_connect_bind(data) ) {
781         return 1;
782     }
783 
784     dn = _ldapfull_search(data, realm, username);
785     if(dn == NULL)
786         return 1;
787 
788     if(ldap_search_s(data->ld, dn, LDAP_SCOPE_BASE, "(objectClass=*)", (char**)no_attrs, 0, &result))
789     {
790         log_write(data->ar->c2s->log, LOG_ERR, "ldap: search %s failed: %s", dn, ldap_err2string(_ldapfull_get_lderrno(data->ld)));
791         ldap_memfree((void*)dn);
792         _ldapfull_unbind(data);
793         return 1;
794     }
795 
796     ldap_memfree((void*)dn);
797 
798     entry = ldap_first_entry(data->ld, result);
799     if(entry == NULL)
800     {
801         ldap_msgfree(result);
802         return 1;
803     }
804 
805     vals=ldap_get_values(data->ld,entry,data->pwattr);
806     if( ldap_count_values(vals) <= 0 ) {
807         ldap_value_free(vals);
808         ldap_msgfree(result);
809         return 1;
810     }
811     strncpy(password,vals[0],LDAPFULL_PASSBUF_MAX-1);
812     password[LDAPFULL_PASSBUF_MAX-1] = '\0';
813     ldap_value_free(vals);
814 
815     ldap_msgfree(result);
816 
817     log_debug(ZONE, "found password for %s", username);
818 
819     return 0;
820 }
821 
822 // set password from jabberPassword attribute
_ldapfull_set_password(authreg_t ar,sess_t sess,const char * username,const char * realm,char password[LDAPFULL_PASSBUF_MAX])823 static int _ldapfull_set_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[LDAPFULL_PASSBUF_MAX]) {
824     moddata_t data = (moddata_t) ar->private;
825     LDAPMessage *result, *entry;
826     LDAPMod *mods[2], attr_pw;
827     char buf[LDAPFULL_PASSBUF_MAX];
828     char *pdn, *attrs[] = { NULL }, *pw_mod_vals[] = { buf, NULL };
829     char dn[LDAPFULL_DN_MAX];
830 
831     log_debug(ZONE, "setting password for %s", username);
832 
833     if( ! _ldapfull_set_passhash(data,data->pwscheme,password,buf,LDAPFULL_PASSBUF_MAX) ) {
834         log_debug(ZONE, "password scheme is not defined");
835         return 1;
836     }
837 
838     if( _ldapfull_connect_bind(data) ) {
839         return 1;
840     }
841 
842     pdn = _ldapfull_search(data, realm, username);
843     if(pdn == NULL)
844         return 1;
845 
846     strncpy(dn, pdn, LDAPFULL_DN_MAX-1); dn[LDAPFULL_DN_MAX-1] = '\0';
847     ldap_memfree(pdn);
848 
849     if(ldap_search_s(data->ld, dn, LDAP_SCOPE_BASE, "(objectClass=*)", attrs, 0, &result))
850     {
851         log_write(data->ar->c2s->log, LOG_ERR, "ldap: search %s failed: %s", dn, ldap_err2string(_ldapfull_get_lderrno(data->ld)));
852         _ldapfull_unbind(data);
853         return 1;
854     }
855 
856     entry = ldap_first_entry(data->ld, result);
857     if(entry == NULL)
858     {
859         ldap_msgfree(result);
860         return 1;
861     }
862     ldap_msgfree(result);
863 
864     attr_pw.mod_op = LDAP_MOD_REPLACE;
865     attr_pw.mod_type = (char*)data->pwattr;
866     attr_pw.mod_values = pw_mod_vals;
867 
868     mods[0] = &attr_pw;
869     mods[1] = NULL;
870 
871     if( ldap_modify_s(data->ld, dn, mods) != LDAP_SUCCESS ) {
872         log_write(data->ar->c2s->log, LOG_ERR, "ldap: error modifying %s: %s", dn, ldap_err2string(_ldapfull_get_lderrno(data->ld)));
873         _ldapfull_unbind(data);
874         return 1;
875     }
876 
877     log_debug(ZONE, "password was set for %s", username);
878 
879     return 0;
880 }
881 
882 /** check the password */
_ldapfull_check_password(authreg_t ar,sess_t sess,const char * username,const char * realm,char password[LDAPFULL_PASSBUF_MAX])883 static int _ldapfull_check_password(authreg_t ar, sess_t sess, const char *username, const char *realm, char password[LDAPFULL_PASSBUF_MAX])
884 {
885     moddata_t data = (moddata_t) ar->private;
886     char buf[LDAPFULL_PASSBUF_MAX];
887     const char *dn = NULL;
888 
889     log_debug(ZONE, "checking password for %s", username);
890 
891     if(password[0] == '\0')
892         return 1;
893 
894     if(data->group_dn != NULL) {
895         if (!_ldapfull_find_user_dn(data, username, realm, &dn))
896             return 1;
897     }
898     /* The bind scheme doesn't need the password read first, so short circuit
899        the whole passhash scheme */
900     if (!strcmp(data->pwscheme, "bind")) {
901         if(_ldapfull_check_password_bind(ar, username, realm, password) == 0) {
902             if(data->group_dn != NULL && !_ldapfull_user_in_group(data, dn, data->group_dn)) {
903                 ldap_memfree((void*)dn);
904                 return 1;
905             }
906             else {
907                 ldap_memfree((void*)dn);
908                 return 0;
909             }
910         }
911     }
912 
913     if( _ldapfull_get_password(ar,sess,username,realm,buf) != 0  ) {
914         if(dn != NULL)
915             ldap_memfree((void*)dn);
916         return 1;
917     }
918 
919     if(_ldapfull_check_passhash(data,buf,password)){
920         if(data->group_dn != NULL && !_ldapfull_user_in_group(data, dn, data->group_dn)) {
921             ldap_memfree((void*)dn);
922             return 1;
923         }
924         else {
925             if(dn != NULL)
926                 ldap_memfree((void*)dn);
927             return 0;
928         }
929     }
930     else {
931         if(dn != NULL)
932             ldap_memfree((void*)dn);
933         return 1;
934     }
935 }
936 
_ldapfull_create_user(authreg_t ar,sess_t sess,const char * username,const char * realm)937 static int _ldapfull_create_user(authreg_t ar, sess_t sess, const char *username, const char *realm) {
938     if( _ldapfull_user_exists(ar,sess,username,realm) ) {
939         return 0;
940     } else {
941         return 1;
942     }
943 }
944 
_ldapfull_delete_user(authreg_t ar,sess_t sess,const char * username,const char * realm)945 static int _ldapfull_delete_user(authreg_t ar, sess_t sess, const char *username, const char *realm) {
946     return 0;
947 }
948 
949 /** shut me down */
_ldapfull_free(authreg_t ar)950 static void _ldapfull_free(authreg_t ar)
951 {
952     moddata_t data = (moddata_t) ar->private;
953 
954     _ldapfull_unbind(data);
955 
956     xhash_free(data->basedn);
957     free(data);
958 
959     return;
960 }
961 
962 /** start me up */
ar_init(authreg_t ar)963 DLLEXPORT int ar_init(authreg_t ar)
964 {
965     moddata_t data;
966     const char *uri, *realm, *srvtype_s;
967     config_elem_t basedn;
968     int i,hascheck,srvtype_i;
969 
970     uri = config_get_one(ar->c2s->config, "authreg.ldapfull.uri", 0);
971     if(uri == NULL)
972     {
973         log_write(ar->c2s->log, LOG_ERR, "ldap: no uri specified in config file");
974         return 1;
975     }
976 
977     basedn = config_get(ar->c2s->config, "authreg.ldapfull.basedn");
978     if(basedn == NULL)
979     {
980         log_write(ar->c2s->log, LOG_ERR, "ldap: no basedn specified in config file");
981         return 1;
982     }
983 
984     srvtype_s = config_get_one(ar->c2s->config, "authreg.ldapfull.type", 0);
985     if( srvtype_s == NULL ) {
986         srvtype_i = LDAPFULL_SRVTYPE_LDAP;
987     } else if( !strcmp(srvtype_s, "ldap") ) {
988         srvtype_i = LDAPFULL_SRVTYPE_LDAP;
989     } else if( !strcmp(srvtype_s, "ad") ) {
990         srvtype_i = LDAPFULL_SRVTYPE_AD;
991     } else {
992         log_write(ar->c2s->log, LOG_ERR, "ldap: unknown server type: %s", srvtype_s);
993         return 1;
994     }
995 
996     data = (moddata_t) calloc(1, sizeof(struct moddata_st));
997 
998     data->basedn = xhash_new(101);
999 
1000     for(i = 0; i < basedn->nvalues; i++)
1001     {
1002         realm = (basedn->attrs[i] != NULL) ? j_attr((const char **) basedn->attrs[i], "realm") : NULL;
1003         if(realm == NULL)
1004             data->default_basedn = basedn->values[i];
1005         else
1006             xhash_put(data->basedn, realm, (void*)basedn->values[i]);
1007 
1008         log_debug(ZONE, "realm '%s' has base dn '%s'", realm, basedn->values[i]);
1009     }
1010 
1011     log_write(ar->c2s->log, LOG_NOTICE, "ldap: configured %d realms", i);
1012 
1013     data->uri = uri;
1014 
1015     data->srvtype = srvtype_i;
1016 
1017     data->binddn = config_get_one(ar->c2s->config, "authreg.ldapfull.binddn", 0);
1018     if(data->binddn != NULL)
1019         data->bindpw = config_get_one(ar->c2s->config, "authreg.ldapfull.bindpw", 0);
1020 
1021     data->uidattr = config_get_one(ar->c2s->config, "authreg.ldapfull.uidattr", 0);
1022     if(data->uidattr == NULL)
1023         data->uidattr = "uid";
1024 
1025     data->validattr = config_get_one(ar->c2s->config, "authreg.ldapfull.validattr", 0);
1026 
1027     data->group_dn = config_get_one(ar->c2s->config, "authreg.ldapfull.group_dn", 0);
1028 
1029     data->pwattr = config_get_one(ar->c2s->config, "authreg.ldapfull.pwattr", 0);
1030     if(data->pwattr == NULL)
1031         data->pwattr = "jabberPassword";
1032 
1033     data->pwscheme = config_get_one(ar->c2s->config, "authreg.ldapfull.pwscheme", 0);
1034     if(data->pwscheme == NULL) {
1035         data->pwscheme = "clear";
1036         hascheck=0;
1037     } else {
1038         hascheck=1;
1039     }
1040 
1041     data->objectclass = config_get_one(ar->c2s->config, "authreg.ldapfull.objectclass", 0);
1042     if(data->objectclass == NULL)
1043         data->objectclass = "jabberUser";
1044 
1045     if( (char *)config_get_one(ar->c2s->config, "authreg.ldapfull.fulluid", 0) != NULL ) {
1046       data->fulluid = 1;
1047     }
1048 
1049     data->ar = ar;
1050 
1051     if(_ldapfull_connect_bind(data))
1052     {
1053         xhash_free(data->basedn);
1054         free(data);
1055         return 1;
1056     }
1057 
1058     _ldapfull_hash_init();
1059 
1060     ar->private = data;
1061 
1062     ar->user_exists = _ldapfull_user_exists;
1063     ar->create_user = _ldapfull_create_user;
1064     ar->delete_user = _ldapfull_delete_user;
1065     ar->set_password = _ldapfull_set_password;
1066     if( hascheck ) {
1067         ar->check_password = _ldapfull_check_password;
1068     } else {
1069         ar->get_password = _ldapfull_get_password;
1070     }
1071 
1072     ar->free = _ldapfull_free;
1073 
1074     return 0;
1075 }
1076 
1077 #endif // STORAGE_LDAP
1078