xref: /netbsd-src/crypto/external/bsd/openssh/dist/ldapauth.c (revision f5a3e1b0221655db9f9a8f38b0311a438f5544ec)
1*f5a3e1b0Schristos /*	$NetBSD: ldapauth.c,v 1.8 2021/08/14 16:17:57 christos Exp $	*/
2aef795aaSadam 
3aef795aaSadam /*
4aef795aaSadam  *
5aef795aaSadam  * Copyright (c) 2005, Eric AUGE <eau@phear.org>
6aef795aaSadam  * All rights reserved.
7aef795aaSadam  *
8aef795aaSadam  * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
9aef795aaSadam  *
10aef795aaSadam  * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
11aef795aaSadam  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
12aef795aaSadam  * Neither the name of the phear.org nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
13aef795aaSadam  *
14aef795aaSadam  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
15aef795aaSadam  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16aef795aaSadam  * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
17aef795aaSadam  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18aef795aaSadam  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
19aef795aaSadam  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
20aef795aaSadam  *
21aef795aaSadam  *
22aef795aaSadam  */
23aef795aaSadam #include "includes.h"
24*f5a3e1b0Schristos __RCSID("$NetBSD: ldapauth.c,v 1.8 2021/08/14 16:17:57 christos Exp $");
25aef795aaSadam 
26aef795aaSadam #ifdef WITH_LDAP_PUBKEY
27aef795aaSadam #include <stdarg.h>
28aef795aaSadam #include <stdio.h>
29aef795aaSadam #include <stdlib.h>
30aef795aaSadam #include <unistd.h>
31aef795aaSadam #include <string.h>
32aef795aaSadam 
33aef795aaSadam #include "ldapauth.h"
34aef795aaSadam #include "log.h"
35aef795aaSadam 
36aef795aaSadam /* filter building infos */
37aef795aaSadam #define FILTER_GROUP_PREFIX "(&(objectclass=posixGroup)"
38aef795aaSadam #define FILTER_OR_PREFIX "(|"
39aef795aaSadam #define FILTER_OR_SUFFIX ")"
40aef795aaSadam #define FILTER_CN_PREFIX "(cn="
41aef795aaSadam #define FILTER_CN_SUFFIX ")"
42aef795aaSadam #define FILTER_UID_FORMAT "(memberUid=%s)"
43aef795aaSadam #define FILTER_GROUP_SUFFIX ")"
44aef795aaSadam #define FILTER_GROUP_SIZE(group) (size_t) (strlen(group)+(ldap_count_group(group)*5)+52)
45aef795aaSadam 
46aef795aaSadam /* just filter building stuff */
47aef795aaSadam #define REQUEST_GROUP_SIZE(filter, uid) (size_t) (strlen(filter)+strlen(uid)+1)
48aef795aaSadam #define REQUEST_GROUP(buffer, prefilter, pwname) \
49aef795aaSadam     buffer = (char *) calloc(REQUEST_GROUP_SIZE(prefilter, pwname), sizeof(char)); \
50aef795aaSadam     if (!buffer) { \
51aef795aaSadam         perror("calloc()"); \
52aef795aaSadam         return FAILURE; \
53aef795aaSadam     } \
54aef795aaSadam     snprintf(buffer, REQUEST_GROUP_SIZE(prefilter,pwname), prefilter, pwname)
55aef795aaSadam /*
56aef795aaSadam XXX OLD group building macros
57aef795aaSadam #define REQUEST_GROUP_SIZE(grp, uid) (size_t) (strlen(grp)+strlen(uid)+46)
58aef795aaSadam #define REQUEST_GROUP(buffer,pwname,grp) \
59aef795aaSadam     buffer = (char *) calloc(REQUEST_GROUP_SIZE(grp, pwname), sizeof(char)); \
60aef795aaSadam     if (!buffer) { \
61aef795aaSadam         perror("calloc()"); \
62aef795aaSadam         return FAILURE; \
63aef795aaSadam     } \
64aef795aaSadam     snprintf(buffer,REQUEST_GROUP_SIZE(grp,pwname),"(&(objectclass=posixGroup)(cn=%s)(memberUid=%s))",grp,pwname)
65aef795aaSadam     */
66aef795aaSadam 
67aef795aaSadam /*
68aef795aaSadam XXX stock upstream version without extra filter support
69aef795aaSadam #define REQUEST_USER_SIZE(uid) (size_t) (strlen(uid)+64)
70aef795aaSadam #define REQUEST_USER(buffer, pwname) \
71aef795aaSadam     buffer = (char *) calloc(REQUEST_USER_SIZE(pwname), sizeof(char)); \
72aef795aaSadam     if (!buffer) { \
73aef795aaSadam         perror("calloc()"); \
74aef795aaSadam         return NULL; \
75aef795aaSadam     } \
76aef795aaSadam     snprintf(buffer,REQUEST_USER_SIZE(pwname),"(&(objectclass=posixAccount)(objectclass=ldapPublicKey)(uid=%s))",pwname)
77aef795aaSadam    */
78aef795aaSadam 
79aef795aaSadam #define REQUEST_USER_SIZE(uid, filter) (size_t) (strlen(uid)+64+(filter != NULL ? strlen(filter) : 0))
80aef795aaSadam #define REQUEST_USER(buffer, pwname, customfilter) \
81aef795aaSadam     buffer = (char *) calloc(REQUEST_USER_SIZE(pwname, customfilter), sizeof(char)); \
82aef795aaSadam     if (!buffer) { \
83aef795aaSadam         perror("calloc()"); \
84aef795aaSadam         return NULL; \
85aef795aaSadam     } \
86aef795aaSadam     snprintf(buffer, REQUEST_USER_SIZE(pwname, customfilter), \
87aef795aaSadam     	"(&(objectclass=posixAccount)(objectclass=ldapPublicKey)(uid=%s)%s)", \
88aef795aaSadam 	pwname, (customfilter != NULL ? customfilter : ""))
89aef795aaSadam 
90aef795aaSadam /* some portable and working tokenizer, lame though */
tokenize(char ** o,size_t size,char * input)91aef795aaSadam static int tokenize(char ** o, size_t size, char * input) {
92aef795aaSadam     unsigned int i = 0, num;
93aef795aaSadam     const char * charset = " \t";
94aef795aaSadam     char * ptr = input;
95aef795aaSadam 
96aef795aaSadam     /* leading white spaces are ignored */
97aef795aaSadam     num = strspn(ptr, charset);
98aef795aaSadam     ptr += num;
99aef795aaSadam 
100aef795aaSadam     while ((num = strcspn(ptr, charset))) {
101aef795aaSadam         if (i < size-1) {
102aef795aaSadam             o[i++] = ptr;
103aef795aaSadam             ptr += num;
104aef795aaSadam             if (*ptr)
105aef795aaSadam                 *ptr++ = '\0';
106aef795aaSadam         }
107aef795aaSadam     }
108aef795aaSadam     o[i] = NULL;
109aef795aaSadam     return SUCCESS;
110aef795aaSadam }
111aef795aaSadam 
ldap_close(ldap_opt_t * ldap)112aef795aaSadam void ldap_close(ldap_opt_t * ldap) {
113aef795aaSadam 
114aef795aaSadam     if (!ldap)
115aef795aaSadam         return;
116aef795aaSadam 
117aef795aaSadam     if ( ldap_unbind_ext(ldap->ld, NULL, NULL) < 0)
118aef795aaSadam 	ldap_perror(ldap->ld, "ldap_unbind()");
119aef795aaSadam 
120aef795aaSadam     ldap->ld = NULL;
121aef795aaSadam     FLAG_SET_DISCONNECTED(ldap->flags);
122aef795aaSadam 
123aef795aaSadam     return;
124aef795aaSadam }
125aef795aaSadam 
126aef795aaSadam /* init && bind */
ldap_xconnect(ldap_opt_t * ldap)127*f5a3e1b0Schristos int ldap_xconnect(ldap_opt_t * ldap) {
128aef795aaSadam     int version = LDAP_VERSION3;
129aef795aaSadam 
130aef795aaSadam     if (!ldap->servers)
131aef795aaSadam         return FAILURE;
132aef795aaSadam 
133aef795aaSadam     /* Connection Init and setup */
134aef795aaSadam     ldap->ld = ldap_init(ldap->servers, LDAP_PORT);
135aef795aaSadam     if (!ldap->ld) {
136aef795aaSadam         ldap_perror(ldap->ld, "ldap_init()");
137aef795aaSadam         return FAILURE;
138aef795aaSadam     }
139aef795aaSadam 
140aef795aaSadam     if ( ldap_set_option(ldap->ld, LDAP_OPT_PROTOCOL_VERSION, &version) != LDAP_OPT_SUCCESS) {
141aef795aaSadam         ldap_perror(ldap->ld, "ldap_set_option(LDAP_OPT_PROTOCOL_VERSION)");
142aef795aaSadam         return FAILURE;
143aef795aaSadam     }
144aef795aaSadam 
145aef795aaSadam     /* Timeouts setup */
146aef795aaSadam     if (ldap_set_option(ldap->ld, LDAP_OPT_NETWORK_TIMEOUT, &ldap->b_timeout) != LDAP_SUCCESS) {
147aef795aaSadam         ldap_perror(ldap->ld, "ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT)");
148aef795aaSadam     }
149aef795aaSadam     if (ldap_set_option(ldap->ld, LDAP_OPT_TIMEOUT, &ldap->s_timeout) != LDAP_SUCCESS) {
150aef795aaSadam         ldap_perror(ldap->ld, "ldap_set_option(LDAP_OPT_TIMEOUT)");
151aef795aaSadam     }
152aef795aaSadam 
153aef795aaSadam     /* TLS support */
154aef795aaSadam     if ( (ldap->tls == -1) || (ldap->tls == 1) ) {
155aef795aaSadam         if (ldap_start_tls_s(ldap->ld, NULL, NULL ) != LDAP_SUCCESS) {
156aef795aaSadam             /* failed then reinit the initial connect */
157*f5a3e1b0Schristos             ldap_perror(ldap->ld, "ldap_xconnect: (TLS) ldap_start_tls()");
158aef795aaSadam             if (ldap->tls == 1)
159aef795aaSadam                 return FAILURE;
160aef795aaSadam 
161aef795aaSadam             ldap->ld = ldap_init(ldap->servers, LDAP_PORT);
162aef795aaSadam             if (!ldap->ld) {
163aef795aaSadam                 ldap_perror(ldap->ld, "ldap_init()");
164aef795aaSadam                 return FAILURE;
165aef795aaSadam             }
166aef795aaSadam 
167aef795aaSadam             if ( ldap_set_option(ldap->ld, LDAP_OPT_PROTOCOL_VERSION, &version) != LDAP_OPT_SUCCESS) {
168aef795aaSadam                  ldap_perror(ldap->ld, "ldap_set_option()");
169aef795aaSadam                  return FAILURE;
170aef795aaSadam             }
171aef795aaSadam         }
172aef795aaSadam     }
173aef795aaSadam 
174aef795aaSadam 
175aef795aaSadam     if ( ldap_simple_bind_s(ldap->ld, ldap->binddn, ldap->bindpw) != LDAP_SUCCESS) {
176aef795aaSadam         ldap_perror(ldap->ld, "ldap_simple_bind_s()");
177aef795aaSadam         return FAILURE;
178aef795aaSadam     }
179aef795aaSadam 
180aef795aaSadam     /* says it is connected */
181aef795aaSadam     FLAG_SET_CONNECTED(ldap->flags);
182aef795aaSadam 
183aef795aaSadam     return SUCCESS;
184aef795aaSadam }
185aef795aaSadam 
186aef795aaSadam /* must free allocated ressource */
ldap_build_host(char * host,int port)187aef795aaSadam static char * ldap_build_host(char *host, int port) {
188aef795aaSadam     unsigned int size = strlen(host)+11;
189aef795aaSadam     char * h = (char *) calloc (size, sizeof(char));
190aef795aaSadam     int rc;
191aef795aaSadam     if (!h)
192aef795aaSadam          return NULL;
193aef795aaSadam 
194aef795aaSadam     rc = snprintf(h, size, "%s:%d ", host, port);
195aef795aaSadam     if (rc == -1)
196aef795aaSadam         return NULL;
197aef795aaSadam     return h;
198aef795aaSadam }
199aef795aaSadam 
ldap_count_group(const char * input)200aef795aaSadam static int ldap_count_group(const char * input) {
201aef795aaSadam     const char * charset = " \t";
202aef795aaSadam     const char * ptr = input;
203aef795aaSadam     unsigned int count = 0;
204aef795aaSadam     unsigned int num;
205aef795aaSadam 
206aef795aaSadam     num = strspn(ptr, charset);
207aef795aaSadam     ptr += num;
208aef795aaSadam 
209aef795aaSadam     while ((num = strcspn(ptr, charset))) {
210aef795aaSadam     count++;
211aef795aaSadam     ptr += num;
212aef795aaSadam     ptr++;
213aef795aaSadam     }
214aef795aaSadam 
215aef795aaSadam     return count;
216aef795aaSadam }
217aef795aaSadam 
218aef795aaSadam /* format filter */
ldap_parse_groups(const char * groups)219aef795aaSadam char * ldap_parse_groups(const char * groups) {
220aef795aaSadam     unsigned int buffer_size = FILTER_GROUP_SIZE(groups);
221aef795aaSadam     char * buffer = (char *) calloc(buffer_size, sizeof(char));
222aef795aaSadam     char * g = NULL;
223aef795aaSadam     char * garray[32];
224aef795aaSadam     unsigned int i = 0;
225aef795aaSadam 
226aef795aaSadam     if ((!groups)||(!buffer))
227aef795aaSadam         return NULL;
228aef795aaSadam 
229aef795aaSadam     g = strdup(groups);
230aef795aaSadam     if (!g) {
231aef795aaSadam         free(buffer);
232aef795aaSadam         return NULL;
233aef795aaSadam     }
234aef795aaSadam 
235aef795aaSadam     /* first separate into n tokens */
236aef795aaSadam     if ( tokenize(garray, sizeof(garray)/sizeof(*garray), g) < 0) {
237aef795aaSadam         free(g);
238aef795aaSadam         free(buffer);
239aef795aaSadam         return NULL;
240aef795aaSadam     }
241aef795aaSadam 
242aef795aaSadam     /* build the final filter format */
243aef795aaSadam     strlcat(buffer, FILTER_GROUP_PREFIX, buffer_size);
244aef795aaSadam     strlcat(buffer, FILTER_OR_PREFIX, buffer_size);
245aef795aaSadam     i = 0;
246aef795aaSadam     while (garray[i]) {
247aef795aaSadam         strlcat(buffer, FILTER_CN_PREFIX, buffer_size);
248aef795aaSadam         strlcat(buffer, garray[i], buffer_size);
249aef795aaSadam         strlcat(buffer, FILTER_CN_SUFFIX, buffer_size);
250aef795aaSadam         i++;
251aef795aaSadam     }
252aef795aaSadam     strlcat(buffer, FILTER_OR_SUFFIX, buffer_size);
253aef795aaSadam     strlcat(buffer, FILTER_UID_FORMAT, buffer_size);
254aef795aaSadam     strlcat(buffer, FILTER_GROUP_SUFFIX, buffer_size);
255aef795aaSadam 
256aef795aaSadam     free(g);
257aef795aaSadam     return buffer;
258aef795aaSadam }
259aef795aaSadam 
260aef795aaSadam /* a bit dirty but leak free  */
ldap_parse_servers(const char * servers)261aef795aaSadam char * ldap_parse_servers(const char * servers) {
262aef795aaSadam     char * s = NULL;
263aef795aaSadam     char * tmp = NULL, *urls[32];
264aef795aaSadam     unsigned int num = 0 , i = 0 , asize = 0;
265aef795aaSadam     LDAPURLDesc *urld[32];
266aef795aaSadam 
267aef795aaSadam     if (!servers)
268aef795aaSadam         return NULL;
269aef795aaSadam 
270aef795aaSadam     /* local copy of the arg */
271aef795aaSadam     s = strdup(servers);
272aef795aaSadam     if (!s)
273aef795aaSadam         return NULL;
274aef795aaSadam 
275aef795aaSadam     /* first separate into URL tokens */
276aef795aaSadam     if ( tokenize(urls, sizeof(urls)/sizeof(*urls), s) < 0)
277aef795aaSadam         return NULL;
278aef795aaSadam 
279aef795aaSadam     i = 0;
280aef795aaSadam     while (urls[i]) {
281aef795aaSadam         if (! ldap_is_ldap_url(urls[i]) ||
282aef795aaSadam            (ldap_url_parse(urls[i], &urld[i]) != 0)) {
283aef795aaSadam                 return NULL;
284aef795aaSadam         }
285aef795aaSadam         i++;
286aef795aaSadam     }
287aef795aaSadam 
288aef795aaSadam     /* now free(s) */
289aef795aaSadam     free (s);
290aef795aaSadam 
291aef795aaSadam     /* how much memory do we need */
292aef795aaSadam     num = i;
293aef795aaSadam     for (i = 0 ; i < num ; i++)
294aef795aaSadam         asize += strlen(urld[i]->lud_host)+11;
295aef795aaSadam 
296aef795aaSadam     /* alloc */
297aef795aaSadam     s = (char *) calloc( asize+1 , sizeof(char));
298aef795aaSadam     if (!s) {
299aef795aaSadam         for (i = 0 ; i < num ; i++)
300aef795aaSadam             ldap_free_urldesc(urld[i]);
301aef795aaSadam         return NULL;
302aef795aaSadam     }
303aef795aaSadam 
304aef795aaSadam     /* then build the final host string */
305aef795aaSadam     for (i = 0 ; i < num ; i++) {
306aef795aaSadam         /* built host part */
307aef795aaSadam         tmp = ldap_build_host(urld[i]->lud_host, urld[i]->lud_port);
308aef795aaSadam         strncat(s, tmp, strlen(tmp));
309aef795aaSadam         ldap_free_urldesc(urld[i]);
310aef795aaSadam         free(tmp);
311aef795aaSadam     }
312aef795aaSadam 
313aef795aaSadam     return s;
314aef795aaSadam }
315aef795aaSadam 
ldap_options_print(ldap_opt_t * ldap)316aef795aaSadam void ldap_options_print(ldap_opt_t * ldap) {
317aef795aaSadam     debug("ldap options:");
318aef795aaSadam     debug("servers: %s", ldap->servers);
319aef795aaSadam     if (ldap->u_basedn)
320aef795aaSadam         debug("user basedn: %s", ldap->u_basedn);
321aef795aaSadam     if (ldap->g_basedn)
322aef795aaSadam         debug("group basedn: %s", ldap->g_basedn);
323aef795aaSadam     if (ldap->binddn)
324aef795aaSadam         debug("binddn: %s", ldap->binddn);
325aef795aaSadam     if (ldap->bindpw)
326aef795aaSadam         debug("bindpw: %s", ldap->bindpw);
327aef795aaSadam     if (ldap->sgroup)
328aef795aaSadam         debug("group: %s", ldap->sgroup);
329aef795aaSadam     if (ldap->filter)
330aef795aaSadam         debug("filter: %s", ldap->filter);
331aef795aaSadam }
332aef795aaSadam 
ldap_options_free(ldap_opt_t * l)333aef795aaSadam void ldap_options_free(ldap_opt_t * l) {
334aef795aaSadam     if (!l)
335aef795aaSadam         return;
336aef795aaSadam     if (l->servers)
337aef795aaSadam         free(l->servers);
338aef795aaSadam     if (l->u_basedn)
339aef795aaSadam         free(l->u_basedn);
340aef795aaSadam     if (l->g_basedn)
341aef795aaSadam         free(l->g_basedn);
342aef795aaSadam     if (l->binddn)
343aef795aaSadam         free(l->binddn);
344aef795aaSadam     if (l->bindpw)
345aef795aaSadam         free(l->bindpw);
346aef795aaSadam     if (l->sgroup)
347aef795aaSadam         free(l->sgroup);
348aef795aaSadam     if (l->fgroup)
349aef795aaSadam         free(l->fgroup);
350aef795aaSadam     if (l->filter)
351aef795aaSadam         free(l->filter);
352aef795aaSadam     if (l->l_conf)
353aef795aaSadam         free(l->l_conf);
354aef795aaSadam     free(l);
355aef795aaSadam }
356aef795aaSadam 
357aef795aaSadam /* free keys */
ldap_keys_free(ldap_key_t * k)358aef795aaSadam void ldap_keys_free(ldap_key_t * k) {
359aef795aaSadam     ldap_value_free_len(k->keys);
360aef795aaSadam     free(k);
361aef795aaSadam     return;
362aef795aaSadam }
363aef795aaSadam 
ldap_getuserkey(ldap_opt_t * l,const char * user)364aef795aaSadam ldap_key_t * ldap_getuserkey(ldap_opt_t *l, const char * user) {
365aef795aaSadam     ldap_key_t * k = (ldap_key_t *) calloc (1, sizeof(ldap_key_t));
366aef795aaSadam     LDAPMessage *res, *e;
367aef795aaSadam     char * filter;
368aef795aaSadam     int i;
369aef795aaSadam     char *attrs[] = {
370aef795aaSadam       l->pub_key_attr,
371aef795aaSadam       NULL
372aef795aaSadam     };
373aef795aaSadam 
374aef795aaSadam     if ((!k) || (!l))
375aef795aaSadam          return NULL;
376aef795aaSadam 
377aef795aaSadam     /* Am i still connected ? RETRY n times */
378aef795aaSadam     /* XXX TODO: setup some conf value for retrying */
379aef795aaSadam     if (!(l->flags & FLAG_CONNECTED))
380aef795aaSadam         for (i = 0 ; i < 2 ; i++)
381*f5a3e1b0Schristos             if (ldap_xconnect(l) == 0)
382aef795aaSadam                 break;
383aef795aaSadam 
384aef795aaSadam     /* quick check for attempts to be evil */
385aef795aaSadam     if ((strchr(user, '(') != NULL) || (strchr(user, ')') != NULL) ||
386aef795aaSadam         (strchr(user, '*') != NULL) || (strchr(user, '\\') != NULL))
387aef795aaSadam         return NULL;
388aef795aaSadam 
389aef795aaSadam     /* build  filter for LDAP request */
390aef795aaSadam     REQUEST_USER(filter, user, l->filter);
391aef795aaSadam 
392aef795aaSadam     if ( ldap_search_st( l->ld,
393aef795aaSadam         l->u_basedn,
394aef795aaSadam         LDAP_SCOPE_SUBTREE,
395aef795aaSadam         filter,
396aef795aaSadam         attrs, 0, &l->s_timeout, &res ) != LDAP_SUCCESS) {
397aef795aaSadam 
398aef795aaSadam         ldap_perror(l->ld, "ldap_search_st()");
399aef795aaSadam 
400aef795aaSadam         free(filter);
401aef795aaSadam         free(k);
402aef795aaSadam 
403aef795aaSadam         /* XXX error on search, timeout etc.. close ask for reconnect */
404aef795aaSadam         ldap_close(l);
405aef795aaSadam 
406aef795aaSadam         return NULL;
407aef795aaSadam     }
408aef795aaSadam 
409aef795aaSadam     /* free */
410aef795aaSadam     free(filter);
411aef795aaSadam 
412aef795aaSadam     /* check if any results */
413aef795aaSadam     i = ldap_count_entries(l->ld,res);
414aef795aaSadam     if (i <= 0) {
415aef795aaSadam         ldap_msgfree(res);
416aef795aaSadam         free(k);
417aef795aaSadam         return NULL;
418aef795aaSadam     }
419aef795aaSadam 
420aef795aaSadam     if (i > 1)
421aef795aaSadam         debug("[LDAP] duplicate entries, using the FIRST entry returned");
422aef795aaSadam 
423aef795aaSadam     e = ldap_first_entry(l->ld, res);
424aef795aaSadam     k->keys = ldap_get_values_len(l->ld, e, l->pub_key_attr);
425aef795aaSadam     k->num = ldap_count_values_len(k->keys);
426aef795aaSadam 
427aef795aaSadam     ldap_msgfree(res);
428aef795aaSadam     return k;
429aef795aaSadam }
430aef795aaSadam 
431aef795aaSadam 
432aef795aaSadam /* -1 if trouble
433aef795aaSadam    0 if user is NOT member of current server group
434aef795aaSadam    1 if user IS MEMBER of current server group
435aef795aaSadam  */
ldap_ismember(ldap_opt_t * l,const char * user)436aef795aaSadam int ldap_ismember(ldap_opt_t * l, const char * user) {
437aef795aaSadam     LDAPMessage *res;
438aef795aaSadam     char * filter;
439aef795aaSadam     int i;
440aef795aaSadam 
441aef795aaSadam     if ((!l->sgroup) || !(l->g_basedn))
442aef795aaSadam         return 1;
443aef795aaSadam 
444aef795aaSadam     /* Am i still connected ? RETRY n times */
445aef795aaSadam     /* XXX TODO: setup some conf value for retrying */
446aef795aaSadam     if (!(l->flags & FLAG_CONNECTED))
447aef795aaSadam         for (i = 0 ; i < 2 ; i++)
448*f5a3e1b0Schristos             if (ldap_xconnect(l) == 0)
449aef795aaSadam                  break;
450aef795aaSadam 
451aef795aaSadam     /* quick check for attempts to be evil */
452aef795aaSadam     if ((strchr(user, '(') != NULL) || (strchr(user, ')') != NULL) ||
453aef795aaSadam         (strchr(user, '*') != NULL) || (strchr(user, '\\') != NULL))
454aef795aaSadam         return FAILURE;
455aef795aaSadam 
456aef795aaSadam     /* build filter for LDAP request */
457aef795aaSadam     REQUEST_GROUP(filter, l->fgroup, user);
458aef795aaSadam 
459aef795aaSadam     if (ldap_search_st( l->ld,
460aef795aaSadam         l->g_basedn,
461aef795aaSadam         LDAP_SCOPE_SUBTREE,
462aef795aaSadam         filter,
463aef795aaSadam         NULL, 0, &l->s_timeout, &res) != LDAP_SUCCESS) {
464aef795aaSadam 
465aef795aaSadam         ldap_perror(l->ld, "ldap_search_st()");
466aef795aaSadam 
467aef795aaSadam         free(filter);
468aef795aaSadam 
469aef795aaSadam         /* XXX error on search, timeout etc.. close ask for reconnect */
470aef795aaSadam         ldap_close(l);
471aef795aaSadam 
472aef795aaSadam         return FAILURE;
473aef795aaSadam     }
474aef795aaSadam 
475aef795aaSadam     free(filter);
476aef795aaSadam 
477aef795aaSadam     /* check if any results */
478aef795aaSadam     if (ldap_count_entries(l->ld, res) > 0) {
479aef795aaSadam         ldap_msgfree(res);
480aef795aaSadam         return 1;
481aef795aaSadam     }
482aef795aaSadam 
483aef795aaSadam     ldap_msgfree(res);
484aef795aaSadam     return 0;
485aef795aaSadam }
486aef795aaSadam 
487aef795aaSadam /*
488aef795aaSadam  * ldap.conf simple parser
489aef795aaSadam  * XXX TODO:  sanity checks
490aef795aaSadam  * must either
491aef795aaSadam  * - free the previous ldap_opt_before replacing entries
492aef795aaSadam  * - free each necessary previously parsed elements
493aef795aaSadam  * ret:
494aef795aaSadam  * -1 on FAILURE, 0 on SUCCESS
495aef795aaSadam  */
ldap_parse_lconf(ldap_opt_t * l)496aef795aaSadam int ldap_parse_lconf(ldap_opt_t * l) {
497aef795aaSadam     FILE * lcd; /* ldap.conf descriptor */
498aef795aaSadam     char buf[BUFSIZ];
499aef795aaSadam     char * s = NULL, * k = NULL, * v = NULL;
500aef795aaSadam     int li, len;
501aef795aaSadam 
502aef795aaSadam     lcd = fopen (l->l_conf, "r");
503aef795aaSadam     if (lcd == NULL) {
504aef795aaSadam         /* debug("Cannot open %s", l->l_conf); */
505aef795aaSadam         perror("ldap_parse_lconf()");
506aef795aaSadam         return FAILURE;
507aef795aaSadam     }
508aef795aaSadam 
509aef795aaSadam     while (fgets (buf, sizeof (buf), lcd) != NULL) {
510aef795aaSadam 
511aef795aaSadam         if (*buf == '\n' || *buf == '#')
512aef795aaSadam             continue;
513aef795aaSadam 
514aef795aaSadam         k = buf;
515aef795aaSadam         v = k;
516aef795aaSadam         while (*v != '\0' && *v != ' ' && *v != '\t')
517aef795aaSadam             v++;
518aef795aaSadam 
519aef795aaSadam         if (*v == '\0')
520aef795aaSadam             continue;
521aef795aaSadam 
522aef795aaSadam         *(v++) = '\0';
523aef795aaSadam 
524aef795aaSadam         while (*v == ' ' || *v == '\t')
525aef795aaSadam             v++;
526aef795aaSadam 
527aef795aaSadam         li = strlen (v) - 1;
528aef795aaSadam         while (v[li] == ' ' || v[li] == '\t' || v[li] == '\n')
529aef795aaSadam             --li;
530aef795aaSadam         v[li + 1] = '\0';
531aef795aaSadam 
532aef795aaSadam         if (!strcasecmp (k, "uri")) {
533aef795aaSadam             if ((l->servers = ldap_parse_servers(v)) == NULL) {
534aef795aaSadam                 fatal("error in ldap servers");
535aef795aaSadam             return FAILURE;
536aef795aaSadam             }
537aef795aaSadam 
538aef795aaSadam         }
539aef795aaSadam         else if (!strcasecmp (k, "base")) {
540aef795aaSadam             s = strchr (v, '?');
541aef795aaSadam             if (s != NULL) {
542aef795aaSadam                 len = s - v;
543aef795aaSadam                 l->u_basedn = malloc (len + 1);
544aef795aaSadam                 strncpy (l->u_basedn, v, len);
545aef795aaSadam                 l->u_basedn[len] = '\0';
546aef795aaSadam             } else {
547aef795aaSadam                 l->u_basedn = strdup (v);
548aef795aaSadam             }
549aef795aaSadam         }
550aef795aaSadam         else if (!strcasecmp (k, "binddn")) {
551aef795aaSadam             l->binddn = strdup (v);
552aef795aaSadam         }
553aef795aaSadam         else if (!strcasecmp (k, "bindpw")) {
554aef795aaSadam             l->bindpw = strdup (v);
555aef795aaSadam         }
556aef795aaSadam         else if (!strcasecmp (k, "timelimit")) {
557aef795aaSadam             l->s_timeout.tv_sec = atoi (v);
558aef795aaSadam                 }
559aef795aaSadam         else if (!strcasecmp (k, "bind_timelimit")) {
560aef795aaSadam             l->b_timeout.tv_sec = atoi (v);
561aef795aaSadam         }
562aef795aaSadam         else if (!strcasecmp (k, "ssl")) {
563aef795aaSadam             if (!strcasecmp (v, "start_tls"))
564aef795aaSadam                 l->tls = 1;
565aef795aaSadam         }
566aef795aaSadam     }
567aef795aaSadam 
568aef795aaSadam     fclose (lcd);
569aef795aaSadam     return SUCCESS;
570aef795aaSadam }
571aef795aaSadam 
572aef795aaSadam #endif /* WITH_LDAP_PUBKEY */
573