1 /*
2 * mod_ldap - LDAP password lookup module for ProFTPD
3 * Copyright (c) 1999-2013, John Morrissey <jwm@horde.net>
4 * Copyright (c) 2013-2020 The ProFTPD Project
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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
19 *
20 * Furthermore, John Morrissey gives permission to link this program with
21 * OpenSSL, and distribute the resulting executable, without including the
22 * source code for OpenSSL in the source distribution.
23 *
24 * -----DO NOT EDIT BELOW THIS LINE-----
25 * $Libraries: -lldap -llber$
26 */
27
28 #include "conf.h"
29 #include "privs.h"
30
31 #define MOD_LDAP_VERSION "mod_ldap/2.9.5"
32
33 #if PROFTPD_VERSION_NUMBER < 0x0001030103
34 # error MOD_LDAP_VERSION " requires ProFTPD 1.3.4rc1 or later"
35 #endif
36
37 #if defined(HAVE_CRYPT_H) && !defined(AIX4) && !defined(AIX5)
38 # include <crypt.h>
39 #endif
40
41 #include <lber.h>
42 #include <ldap.h>
43 #if defined(HAVE_SASL_SASL_H)
44 # include <sasl/sasl.h>
45 #endif /* HAVE_SASL_SASL_H */
46
47 extern xaset_t *server_list;
48
49 module ldap_module;
50
51 static int ldap_logfd = -1;
52 static pool *ldap_pool = NULL;
53
54 static const char *trace_channel = "ldap";
55 #if defined(LBER_OPT_LOG_PRINT_FN)
56 static const char *libtrace_channel = "ldap.library";
57 #endif
58
59 #if LDAP_API_VERSION >= 2000
60 # define HAS_LDAP_SASL_BIND_S
61 #endif
62
63 #if defined(LDAP_SASL_QUIET)
64 # define HAS_LDAP_SASL_INTERACTIVE_BIND_S
65 #endif /* LDAP_SASL_QUIET */
66
67 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_VENDOR_VERSION >= 192)
68 # define HAS_LDAP_UNBIND_EXT_S
69 #endif
70
71 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_VENDOR_VERSION >= 19905)
72 # define HAS_LDAP_INITIALIZE
73 #endif
74
75 #ifdef HAS_LDAP_UNBIND_EXT_S
76 # define LDAP_UNBIND(ld) (ldap_unbind_ext_s(ld, NULL, NULL))
77 #else
78 # define LDAP_UNBIND(ld) (ldap_unbind_s(ld))
79 static char *ldap_server;
80 static int ldap_port = LDAP_PORT;
81 #endif
82
83 /* On some systems LDAP_OPT_DIAGNOSTIC_MESSAGE isn't there (e.g. OpenLDAP-2.3.x)
84 * but LDAP_OPT_ERROR_STRING is.
85 */
86 #ifndef LDAP_OPT_DIAGNOSTIC_MESSAGE
87 # ifdef LDAP_OPT_ERROR_STRING
88 # define LDAP_OPT_DIAGNOSTIC_MESSAGE LDAP_OPT_ERROR_STRING
89 # endif
90 #endif
91
92 #if LDAP_API_VERSION >= 2000
93 # define LDAP_VALUE_T struct berval
94 # define LDAP_GET_VALUES(ld, entry, attr) ldap_get_values_len(ld, entry, attr)
95 # define LDAP_VALUE(values, i) (values[i]->bv_val)
96 # define LDAP_COUNT_VALUES(values) (ldap_count_values_len(values))
97 # define LDAP_VALUE_FREE(values) (ldap_value_free_len(values))
98 # define LDAP_SEARCH(ld, base, scope, filter, attrs, timeout, sizelimit, res) \
99 ldap_search_ext_s(ld, base, scope, filter, attrs, 0, NULL, NULL, \
100 timeout, sizelimit, res)
101 #else /* LDAP_API_VERSION >= 2000 */
102 # define LDAP_VALUE_T char
103 # define LDAP_GET_VALUES(ld, entry, attr) ldap_get_values(ld, entry, attr)
104 # define LDAP_VALUE(values, i) (values[i])
105 # define LDAP_COUNT_VALUES(values) (ldap_count_values(values))
106 # define LDAP_VALUE_FREE(values) (ldap_value_free(values))
107
pr_ldap_set_sizelimit(LDAP * limit_ld,int limit)108 static void pr_ldap_set_sizelimit(LDAP *limit_ld, int limit) {
109 #ifdef LDAP_OPT_SIZELIMIT
110 int res;
111
112 res = ldap_set_option(limit_ld, LDAP_OPT_SIZELIMIT, (void *) &limit);
113 if (res != LDAP_OPT_SUCCESS) {
114 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
115 "failed to set LDAP option for search query size limit to %d entries: %s",
116 limit, ldap_err2string(res));
117
118 } else {
119 pr_trace_msg(trace_channel, 5,
120 "set search query size limit to %d entries", limit);
121 }
122
123 #else
124 limit_ld->ld_sizelimit = limit;
125
126 pr_trace_msg(trace_channel, 5,
127 "set search query size limit to %d entries", limit);
128 #endif
129 }
130
131 static int
LDAP_SEARCH(LDAP * ld,char * base,int scope,char * filter,char * attrs[],struct timeval * timeout,int sizelimit,LDAPMessage ** res)132 LDAP_SEARCH(LDAP *ld, char *base, int scope, char *filter, char *attrs[],
133 struct timeval *timeout, int sizelimit, LDAPMessage **res) {
134 pr_ldap_set_sizelimit(ld, sizelimit);
135 return ldap_search_st(ld, base, scope, filter, attrs, 0, timeout, res);
136 }
137 #endif /* LDAP_API_VERSION >= 2000 */
138
139 /* Thanks, Sun. */
140 #ifndef LDAP_OPT_SUCCESS
141 # define LDAP_OPT_SUCCESS LDAP_SUCCESS
142 #endif
143 #ifndef LDAP_URL_SUCCESS
144 # define LDAP_URL_SUCCESS LDAP_SUCCESS
145 #endif
146 #ifndef LDAP_SCOPE_DEFAULT
147 # define LDAP_SCOPE_DEFAULT LDAP_SCOPE_SUBTREE
148 #endif
149
150 /* Config entries */
151
152 struct server_info {
153 const char *info_text;
154 char *host;
155 int port;
156 char *port_text;
157 LDAPURLDesc *url_desc;
158 char *url_text;
159 int use_starttls;
160
161 /* For configuring the SSL/TLS session to the LDAP server. */
162 const char *ssl_cert_file;
163 const char *ssl_key_file;
164 const char *ssl_ca_file;
165 const char *ssl_ciphers;
166 int ssl_verify;
167 const char *ssl_verify_text;
168 };
169
170 struct sasl_info {
171 pool *pool;
172
173 /* SASL_AUTHCID from ldap.conf */
174 const char *authentication_id;
175
176 /* SASL_AUTHZID from ldap.conf */
177 const char *authorization_id;
178
179 const char *password;
180
181 /* SASL_REALM from ldap.conf */
182 const char *realm;
183 };
184
185 static array_header *ldap_servers = NULL;
186 static struct server_info *curr_server_info = NULL;
187 static unsigned int curr_server_index = 0;
188
189 static char *ldap_dn, *ldap_dnpass, *ldap_sasl_mechs = NULL,
190 *ldap_user_basedn = NULL, *ldap_user_name_filter = NULL,
191 *ldap_user_uid_filter = NULL,
192 *ldap_gid_basedn = NULL, *ldap_group_gid_filter = NULL,
193 *ldap_group_name_filter = NULL, *ldap_group_member_filter = NULL,
194 *ldap_defaultauthscheme = "crypt", *ldap_authbind_dn = NULL,
195 *ldap_genhdir_prefix = NULL, *ldap_default_quota = NULL,
196 *ldap_attr_uid = "uid",
197 *ldap_attr_uidnumber = "uidNumber",
198 *ldap_attr_gidnumber = "gidNumber",
199 *ldap_attr_homedirectory = "homeDirectory",
200 *ldap_attr_userpassword = "userPassword",
201 *ldap_attr_loginshell = "loginShell",
202 *ldap_attr_cn = "cn",
203 *ldap_attr_memberuid = "memberUid",
204 *ldap_attr_ftpquota = "ftpQuota",
205 *ldap_attr_ftpquota_profiledn = "ftpQuotaProfileDN",
206 *ldap_attr_ssh_pubkey = "sshPublicKey";
207
208 static int ldap_do_users = FALSE, ldap_do_groups = FALSE,
209 ldap_authbinds = TRUE, ldap_querytimeout = 0,
210 ldap_genhdir = FALSE, ldap_genhdir_prefix_nouname = FALSE,
211 ldap_forcedefaultuid = FALSE, ldap_forcedefaultgid = FALSE,
212 ldap_forcegenhdir = FALSE, ldap_protocol_version = 3,
213 ldap_dereference = LDAP_DEREF_NEVER,
214 ldap_search_scope = LDAP_SCOPE_SUBTREE;
215
216 static size_t ldap_dnpasslen = 0;
217
218 static struct timeval ldap_querytimeout_tv;
219 #define PR_LDAP_QUERY_TIMEOUT_DEFAULT 5
220
221 static uid_t ldap_defaultuid = -1;
222 static gid_t ldap_defaultgid = -1;
223 static LDAP *ld = NULL;
224 static array_header *cached_quota = NULL;
225 static array_header *cached_ssh_pubkeys = NULL;
226
227 /* Necessary prototypes */
228 static int ldap_sess_init(void);
229 static struct sasl_info *sasl_info_create(pool *, LDAP *);
230 static void sasl_info_get_authcid_from_dn(struct sasl_info *, const char *);
231
pr_ldap_unbind(void)232 static void pr_ldap_unbind(void) {
233 int res;
234
235 if (ld == NULL) {
236 return;
237 }
238
239 res = LDAP_UNBIND(ld);
240 if (res != LDAP_SUCCESS) {
241 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
242 "error unbinding connection: %s", ldap_err2string(res));
243
244 } else {
245 pr_trace_msg(trace_channel, 8, "connection successfully unbound");
246 }
247
248 ld = NULL;
249 }
250
log_sasl_mechs(LDAP * conn_ld,const char * url_text)251 static void log_sasl_mechs(LDAP *conn_ld, const char *url_text) {
252 #if defined(LDAP_OPT_X_SASL_MECHLIST)
253 char **sasl_mechs = NULL;
254
255 if (ldap_get_option(conn_ld, LDAP_OPT_X_SASL_MECHLIST,
256 &sasl_mechs) == LDAP_OPT_SUCCESS) {
257 if (sasl_mechs != NULL) {
258 register unsigned int i;
259
260 for (i = 0; sasl_mechs[i]; i++) {
261 pr_trace_msg(trace_channel, 22,
262 "%s: LDAP supported SASL mechanism = %s", url_text, sasl_mechs[i]);
263 }
264 }
265 }
266 #endif /* LDAP_OPT_X_SASL_MECHLIST */
267 }
268
do_ldap_prepare(LDAP ** conn_ld)269 static int do_ldap_prepare(LDAP **conn_ld) {
270 #if defined(HAS_LDAP_INITIALIZE)
271 int res;
272 char *url_text = NULL;
273
274 if (curr_server_info != NULL) {
275 url_text = curr_server_info->url_text;
276 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
277 "attempting connection to URL %s", url_text);
278
279 } else {
280 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
281 "attempting connection (see ldap.conf for details)");
282 }
283
284 res = ldap_initialize(conn_ld, url_text);
285 if (res != LDAP_SUCCESS) {
286 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
287 "ldap_initialize() to URL %s failed: %s",
288 url_text ? url_text : "(null)", ldap_err2string(res));
289
290 *conn_ld = NULL;
291 return -1;
292 }
293
294 ldap_search_scope = curr_server_info->url_desc->lud_scope;
295
296 #else
297 char *host = NULL;
298 int port = LDAP_PORT;
299
300 if (curr_server_info != NULL) {
301 host = curr_server_info->host;
302 port = curr_server_info->port;
303
304 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
305 "attempting connection to %s:%d", host, port);
306
307 } else {
308 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
309 "attempting connection (see ldap.conf for details)");
310 }
311
312 *conn_ld = ldap_init(host, port);
313 if (*conn_ld == NULL) {
314 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
315 "ldap_init() to %s:%d failed: %s", host ? host : "(null)", port,
316 strerror(errno));
317 return -1;
318 }
319 #endif /* HAS_LDAP_INITIALIZE */
320
321 log_sasl_mechs(*conn_ld, curr_server_info->info_text);
322 return 0;
323 }
324
sasl_interact_cb(LDAP * conn_ld,unsigned int flags,void * user_data,void * interact_data)325 static int sasl_interact_cb(LDAP *conn_ld, unsigned int flags, void *user_data,
326 void *interact_data) {
327 int res = LDAP_OPERATIONS_ERROR;
328
329 #if defined(HAS_LDAP_SASL_INTERACTIVE_BIND_S) && \
330 defined(HAVE_SASL_SASL_H)
331 sasl_interact_t *interacts;
332 struct sasl_info *sasl;
333
334 interacts = interact_data;
335 sasl = user_data;
336
337 while (interacts->id != SASL_CB_LIST_END) {
338 pr_signals_handle();
339
340 switch (interacts->id) {
341 case SASL_CB_AUTHNAME:
342 interacts->result = sasl->authentication_id;
343 interacts->len = strlen(interacts->result);
344 pr_trace_msg(trace_channel, 19, "SASL interaction: CB_AUTHNAME = '%s'",
345 (char *) interacts->result);
346 break;
347
348 case SASL_CB_GETREALM:
349 /* The cyrus-sasl library works just fine with an empty string for our
350 * currently supported mechanisms.
351 */
352 interacts->result = sasl->realm;
353 interacts->len = strlen(interacts->result);
354 pr_trace_msg(trace_channel, 19, "SASL interaction: CB_GETREALM = '%s'",
355 (char *) interacts->result);
356 break;
357
358 case SASL_CB_PASS:
359 interacts->result = sasl->password;
360 interacts->len = strlen(interacts->result);
361 pr_trace_msg(trace_channel, 19, "SASL interaction: CB_PASS = '...'");
362 break;
363
364 case SASL_CB_USER:
365 /* The cyrus-sasl library handles this as the "authorization ID",
366 * and works just fine with an empty string for our currently
367 * supported mechanisms.
368 */
369 interacts->result = sasl->authorization_id;
370 interacts->len = strlen(interacts->result);
371 pr_trace_msg(trace_channel, 19, "SASL interaction: CB_USER = '%s'",
372 (char *) interacts->result);
373 break;
374
375 case SASL_CB_ECHOPROMPT:
376 case SASL_CB_NOECHOPROMPT:
377 /* Ignore */
378 break;
379
380 default:
381 break;
382 }
383
384 interacts++;
385 }
386
387 res = LDAP_SUCCESS;
388 #else
389 pr_log_debug(DEBUG0, MOD_LDAP_VERSION
390 ": interactive SASL authentication unsupported");
391 res = LDAP_OPERATIONS_ERROR;
392 #endif /* HAS_LDAP_SASL_INTERACTIVE_BIND_S and HAVE_SASL_SASL_H */
393
394 return res;
395 }
396
do_ldap_bind(LDAP * conn_ld)397 static int do_ldap_bind(LDAP *conn_ld) {
398 int res;
399
400 #if defined(HAS_LDAP_SASL_INTERACTIVE_BIND_S)
401 if (ldap_sasl_mechs != NULL) {
402 int sasl_flags;
403 struct sasl_info *sasl;
404
405 pr_trace_msg(trace_channel, 17, "performing bind using SASL mechs: '%s'",
406 ldap_sasl_mechs);
407
408 sasl = sasl_info_create(session.pool, conn_ld);
409 sasl_info_get_authcid_from_dn(sasl, ldap_dn);
410 sasl->password = ldap_dnpass;
411
412 sasl_flags = LDAP_SASL_QUIET;
413
414 res = ldap_sasl_interactive_bind_s(conn_ld, ldap_dn, ldap_sasl_mechs,
415 NULL, NULL, sasl_flags, sasl_interact_cb, sasl);
416
417 destroy_pool(sasl->pool);
418
419 } else {
420 struct berval bindcred;
421
422 bindcred.bv_val = ldap_dnpass;
423 bindcred.bv_len = ldap_dnpasslen;
424
425 res = ldap_sasl_bind_s(conn_ld, ldap_dn, NULL, &bindcred, NULL, NULL, NULL);
426
427 if (res == LDAP_SUCCESS) {
428 if (ldap_dnpasslen > 0) {
429 pr_trace_msg(trace_channel, 9,
430 "bind to '%s' used simple authentication",
431 curr_server_info->info_text);
432
433 } else {
434 pr_trace_msg(trace_channel, 9,
435 "bind to '%s' used anonymous authentication",
436 curr_server_info->info_text);
437 }
438 }
439 }
440 #else /* HAS_LDAP_SASL_BIND_S */
441 res = ldap_simple_bind_s(conn_ld, ldap_dn, ldap_dnpass);
442 #endif /* HAS_LDAP_SASL_BIND_S */
443
444 if (res != LDAP_SUCCESS) {
445 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
446 "bind as DN '%s' failed for '%s': %s",
447 ldap_dn ? ldap_dn : "(anonymous)", curr_server_info->info_text,
448 ldap_err2string(res));
449 return -1;
450 }
451
452 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
453 "successfully bound as DN '%s' with password %s for '%s'",
454 ldap_dn ? ldap_dn : "(anonymous)",
455 ldap_dnpass ? "(see config)" : "(none)", curr_server_info->info_text);
456
457 return 0;
458 }
459
do_ldap_connect(LDAP ** conn_ld,int do_bind)460 static int do_ldap_connect(LDAP **conn_ld, int do_bind) {
461 int res, version;
462
463 /* Note that because we use ldap_init(3)/ldap_initialize(3), the first
464 * actual TCP connection does not occur until the first operation is
465 * requested.
466 */
467 res = do_ldap_prepare(conn_ld);
468 if (res < 0) {
469 return -1;
470 }
471
472 version = LDAP_VERSION3;
473 if (ldap_protocol_version == 2) {
474 version = LDAP_VERSION2;
475 }
476
477 res = ldap_set_option(*conn_ld, LDAP_OPT_PROTOCOL_VERSION, &version);
478 if (res != LDAP_OPT_SUCCESS) {
479 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
480 "error setting LDAP protocol version option to %d: %s", version,
481 ldap_err2string(res));
482 pr_ldap_unbind();
483 return -1;
484 }
485
486 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
487 "set LDAP protocol version to %d", version);
488
489 if (curr_server_info->use_starttls == TRUE) {
490 #if defined(LDAP_OPT_X_TLS)
491 # if defined(LDAP_OPT_X_TLS_CACERTFILE)
492 if (curr_server_info->ssl_ca_file != NULL) {
493 res = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
494 curr_server_info->ssl_ca_file);
495 if (res != LDAP_OPT_SUCCESS) {
496 pr_log_debug(DEBUG5, MOD_LDAP_VERSION
497 ": error setting LDAP_OPT_X_TLS_CACERTFILE = %s: %s",
498 curr_server_info->ssl_ca_file, ldap_err2string(res));
499
500 } else {
501 pr_trace_msg(trace_channel, 17,
502 "set LDAP_OPT_X_TLS_CACERTFILE = %s for '%s'",
503 curr_server_info->ssl_ca_file, curr_server_info->info_text);
504 }
505 }
506 # endif /* LDAP_OPT_X_TLS_CACERTFILE */
507
508 # if defined(LDAP_OPT_X_TLS_CERTFILE)
509 if (curr_server_info->ssl_cert_file != NULL) {
510 res = ldap_set_option(NULL, LDAP_OPT_X_TLS_CERTFILE,
511 curr_server_info->ssl_cert_file);
512 if (res != LDAP_OPT_SUCCESS) {
513 pr_log_debug(DEBUG5, MOD_LDAP_VERSION
514 ": error setting LDAP_OPT_X_TLS_CERTFILE = %s: %s",
515 curr_server_info->ssl_cert_file, ldap_err2string(res));
516
517 } else {
518 pr_trace_msg(trace_channel, 17,
519 "set LDAP_OPT_X_TLS_CERTFILE = %s for '%s'",
520 curr_server_info->ssl_cert_file, curr_server_info->info_text);
521 }
522 }
523 # endif /* LDAP_OPT_X_TLS_CERTFILE */
524
525 # if defined(LDAP_OPT_X_TLS_KEYFILE)
526 if (curr_server_info->ssl_key_file != NULL) {
527 res = ldap_set_option(NULL, LDAP_OPT_X_TLS_KEYFILE,
528 curr_server_info->ssl_key_file);
529 if (res != LDAP_OPT_SUCCESS) {
530 pr_log_debug(DEBUG5, MOD_LDAP_VERSION
531 ": error setting LDAP_OPT_X_TLS_KEYFILE = %s: %s",
532 curr_server_info->ssl_key_file, ldap_err2string(res));
533
534 } else {
535 pr_trace_msg(trace_channel, 17,
536 "set LDAP_OPT_X_TLS_KEYFILE = %s for '%s'",
537 curr_server_info->ssl_key_file, curr_server_info->info_text);
538 }
539 }
540 # endif /* LDAP_OPT_X_TLS_KEYFILE */
541
542 # if defined(LDAP_OPT_X_TLS_CIPHER_SUITE)
543 if (curr_server_info->ssl_ciphers != NULL) {
544 res = ldap_set_option(NULL, LDAP_OPT_X_TLS_CIPHER_SUITE,
545 curr_server_info->ssl_ciphers);
546 if (res != LDAP_OPT_SUCCESS) {
547 pr_log_debug(DEBUG5, MOD_LDAP_VERSION
548 ": error setting LDAP_OPT_X_TLS_CIPHER_SUITE = %s: %s",
549 curr_server_info->ssl_ciphers, ldap_err2string(res));
550
551 } else {
552 pr_trace_msg(trace_channel, 17,
553 "set LDAP_OPT_X_TLS_CIPHER_SUITE = %s for '%s'",
554 curr_server_info->ssl_ciphers, curr_server_info->info_text);
555 }
556 }
557 # endif /* LDAP_OPT_X_TLS_CIPHER_SUITE */
558
559 # if defined(LDAP_OPT_X_TLS_REQUIRE_CERT)
560 if (curr_server_info->ssl_verify != -1) {
561 res = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT,
562 &(curr_server_info->ssl_verify));
563 if (res != LDAP_OPT_SUCCESS) {
564 pr_log_debug(DEBUG5, MOD_LDAP_VERSION
565 ": error setting LDAP_OPT_X_TLS_REQUIRE_CERT = %s: %s",
566 curr_server_info->ssl_verify_text, ldap_err2string(res));
567
568 } else {
569 pr_trace_msg(trace_channel, 17,
570 "set LDAP_OPT_X_TLS_REQUIRE_CERT = %s for '%s'",
571 curr_server_info->ssl_verify_text, curr_server_info->info_text);
572 }
573 }
574 # endif /* LDAP_OPT_X_TLS_REQUIRE_CERT */
575
576 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
577 "LDAPUseTLS in effect, performing STARTTLS handshake on '%s'",
578 curr_server_info->info_text);
579 res = ldap_start_tls_s(*conn_ld, NULL, NULL);
580 if (res != LDAP_SUCCESS) {
581 char *diag_msg = NULL;
582
583 (void) ldap_get_option(*conn_ld, LDAP_OPT_DIAGNOSTIC_MESSAGE,
584 (void *) &diag_msg);
585
586 if (diag_msg != NULL) {
587 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
588 "failed to start TLS: %s: %s", ldap_err2string(res), diag_msg);
589 ldap_memfree(diag_msg);
590
591 } else {
592 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
593 "failed to start TLS: %s", ldap_err2string(res));
594 }
595
596 pr_ldap_unbind();
597 return -1;
598 }
599
600 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
601 "enabled TLS for connection to '%s'", curr_server_info->info_text);
602 }
603 #endif /* LDAP_OPT_X_TLS */
604
605 if (do_bind == TRUE) {
606 res = do_ldap_bind(*conn_ld);
607 if (res < 0) {
608 pr_ldap_unbind();
609 return -1;
610 }
611 }
612
613 #ifdef LDAP_OPT_DEREF
614 res = ldap_set_option(*conn_ld, LDAP_OPT_DEREF, (void *) &ldap_dereference);
615 if (res != LDAP_OPT_SUCCESS) {
616 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
617 "failed to set LDAP option for dereference to %d: %s", ldap_dereference,
618 ldap_err2string(res));
619 pr_ldap_unbind();
620 return -1;
621 }
622
623 #else
624 deref_ld->ld_deref = ldap_dereference;
625 #endif
626
627 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
628 "set dereferencing to %d", ldap_dereference);
629
630 ldap_querytimeout_tv.tv_sec = (ldap_querytimeout > 0 ? ldap_querytimeout :
631 PR_LDAP_QUERY_TIMEOUT_DEFAULT);
632 ldap_querytimeout_tv.tv_usec = 0;
633
634 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
635 "set query timeout to %u secs", (unsigned int) ldap_querytimeout_tv.tv_sec);
636
637 return 0;
638 }
639
640 #if defined(LBER_OPT_LOG_PRINT_FN)
ldap_tracelog_cb(const char * msg)641 static void ldap_tracelog_cb(const char *msg) {
642 (void) pr_trace_msg(libtrace_channel, 1, "%s", msg);
643 }
644 #endif /* no LBER_OPT_LOG_PRINT_FN */
645
pr_ldap_connect(LDAP ** conn_ld,int do_bind)646 static int pr_ldap_connect(LDAP **conn_ld, int do_bind) {
647 unsigned int start_server_index;
648
649 start_server_index = curr_server_index;
650 do {
651 int res, debug_level = -1;
652
653 pr_signals_handle();
654
655 /* Note that ldap_servers might be NULL if no LDAPServer directive was
656 * specified. We fall back to using the SDK default.
657 */
658 if (ldap_servers != NULL) {
659 curr_server_info = ((struct server_info **) ldap_servers->elts)[curr_server_index];
660 }
661
662 res = do_ldap_connect(conn_ld, do_bind);
663 if (res < 0) {
664 ++curr_server_index;
665 if (curr_server_index >= ldap_servers->nelts) {
666 curr_server_index = 0;
667 }
668
669 continue;
670 }
671
672 /* This debug level value should be LDAP_DEBUG_ANY, but that macro is, I
673 * think, OpenLDAP-specific.
674 */
675 res = ldap_set_option(*conn_ld, LDAP_OPT_DEBUG_LEVEL, &debug_level);
676 if (res != LDAP_OPT_SUCCESS) {
677 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
678 "error setting DEBUG_ANY debug level: %s", ldap_err2string(res));
679 }
680
681 return 0;
682
683 } while (curr_server_index != start_server_index);
684
685 return -1;
686 }
687
pr_ldap_interpolate_filter(pool * p,char * template,const char * value)688 static const char *pr_ldap_interpolate_filter(pool *p, char *template,
689 const char *value) {
690 const char *escaped_value, *filter;
691
692 escaped_value = sreplace(p, (char *) value,
693 "\\", "\\\\",
694 "*", "\\*",
695 "(", "\\(",
696 ")", "\\)",
697 NULL
698 );
699
700 if (escaped_value == NULL) {
701 return NULL;
702 }
703
704 filter = sreplace(p, template,
705 "%u", escaped_value,
706 "%v", escaped_value,
707 NULL
708 );
709
710 if (filter == NULL) {
711 return NULL;
712 }
713
714 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
715 "generated filter %s from template %s and value %s", filter, template,
716 value);
717 return filter;
718 }
719
pr_ldap_search(const char * basedn,const char * filter,char * attrs[],int sizelimit,int retry)720 static LDAPMessage *pr_ldap_search(const char *basedn, const char *filter,
721 char *attrs[], int sizelimit, int retry) {
722 int res;
723 LDAPMessage *result;
724
725 if (basedn == NULL) {
726 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
727 "no LDAP base DN specified for search filter %s, declining request",
728 filter ? filter : "(null)");
729 return NULL;
730 }
731
732 /* If the LDAP connection has gone away or hasn't been established
733 * yet, attempt to establish it now.
734 */
735 if (ld == NULL) {
736 /* If we _still_ can't connect, give up and return NULL. */
737 if (pr_ldap_connect(&ld, TRUE) < 0) {
738 return NULL;
739 }
740 }
741
742 res = LDAP_SEARCH(ld, basedn, ldap_search_scope, filter, attrs,
743 &ldap_querytimeout_tv, sizelimit, &result);
744 if (res != LDAP_SUCCESS) {
745 if (res != LDAP_SERVER_DOWN) {
746 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
747 "LDAP search use DN '%s', filter '%s' failed: %s", basedn, filter,
748 ldap_err2string(res));
749 return NULL;
750 }
751
752 if (!retry) {
753 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
754 "LDAP connection went away, search failed");
755 pr_ldap_unbind();
756 return NULL;
757 }
758
759 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
760 "LDAP connection went away, retrying search operation");
761 pr_ldap_unbind();
762 return pr_ldap_search(basedn, filter, attrs, sizelimit, FALSE);
763 }
764
765 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
766 "searched under base DN %s using filter %s", basedn,
767 filter ? filter : "(null)");
768 return result;
769 }
770
pr_ldap_user_lookup(pool * p,char * filter_template,const char * replace,const char * basedn,char * attrs[],char ** user_dn)771 static struct passwd *pr_ldap_user_lookup(pool *p, char *filter_template,
772 const char *replace, const char *basedn, char *attrs[], char **user_dn) {
773 const char *filter;
774 char *dn;
775 int i = 0;
776 struct passwd *pw;
777 LDAPMessage *result, *e;
778 LDAP_VALUE_T **values;
779
780 filter = pr_ldap_interpolate_filter(p, filter_template, replace);
781 if (filter == NULL) {
782 return NULL;
783 }
784
785 result = pr_ldap_search(basedn, filter, attrs, 2, TRUE);
786 if (result == NULL) {
787 return NULL;
788 }
789
790 if (ldap_count_entries(ld, result) > 1) {
791 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
792 "LDAP search returned multiple entries during user lookup, "
793 "aborting query");
794 ldap_msgfree(result);
795 return NULL;
796 }
797
798 e = ldap_first_entry(ld, result);
799 if (e == NULL) {
800 ldap_msgfree(result);
801
802 /* No LDAP entries for this user. */
803 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
804 "no entries for filter %s under base DN %s", filter, basedn);
805 return NULL;
806 }
807
808 pw = pcalloc(ldap_pool, sizeof(struct passwd));
809 while (attrs[i] != NULL) {
810 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
811 "fetching values for attribute %s", attrs[i]);
812
813 values = LDAP_GET_VALUES(ld, e, attrs[i]);
814 if (values == NULL) {
815 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
816 "no values for attribute %s, trying defaults", attrs[i]);
817
818 /* Apply default values for attrs with no explicit values. */
819
820 /* If we can't find the [ug]idNumber attrs, just fill the passwd
821 * struct in with default values from the config file.
822 */
823 if (strcasecmp(attrs[i], ldap_attr_uidnumber) == 0) {
824 if (ldap_defaultuid == (uid_t) -1) {
825 dn = ldap_get_dn(ld, e);
826
827 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
828 "no %s attribute for DN %s found, and LDAPDefaultUID not "
829 "configured", ldap_attr_uidnumber, dn);
830 free(dn);
831 return NULL;
832 }
833
834 pw->pw_uid = ldap_defaultuid;
835 ++i;
836
837 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
838 "using LDAPDefaultUID %s", pr_uid2str(NULL, pw->pw_uid));
839 continue;
840 }
841
842 if (strcasecmp(attrs[i], ldap_attr_gidnumber) == 0) {
843 if (ldap_defaultgid == (gid_t) -1) {
844 dn = ldap_get_dn(ld, e);
845
846 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
847 "no %s attribute found for DN %s, and LDAPDefaultGID not "
848 "configured", ldap_attr_gidnumber, dn);
849 free(dn);
850 return NULL;
851 }
852
853 pw->pw_gid = ldap_defaultgid;
854 ++i;
855
856 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
857 "using LDAPDefaultGID %s", pr_gid2str(NULL, pw->pw_gid));
858 continue;
859 }
860
861 if (strcasecmp(attrs[i], ldap_attr_homedirectory) == 0) {
862 if (ldap_genhdir == FALSE ||
863 ldap_genhdir_prefix == NULL) {
864 dn = ldap_get_dn(ld, e);
865
866 if (ldap_genhdir == FALSE) {
867 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
868 "no %s attribute for DN %s, LDAPGenerateHomedir not enabled",
869 ldap_attr_homedirectory, dn);
870
871 } else {
872 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
873 "no %s attribute for DN %s, LDAPGenerateHomedir enabled but "
874 "LDAPGenerateHomedirPrefix not configured",
875 ldap_attr_homedirectory, dn);
876 }
877
878 free(dn);
879 return NULL;
880 }
881
882 if (ldap_genhdir_prefix_nouname == TRUE) {
883 pw->pw_dir = pstrcat(session.pool, ldap_genhdir_prefix, NULL);
884
885 } else {
886 LDAP_VALUE_T **canon_username;
887 canon_username = LDAP_GET_VALUES(ld, e, ldap_attr_uid);
888 if (canon_username == NULL) {
889 dn = ldap_get_dn(ld, e);
890
891 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
892 "could not get %s attribute for canonical username for DN %s",
893 ldap_attr_uid, dn);
894 free(dn);
895 return NULL;
896 }
897
898 pw->pw_dir = pstrcat(session.pool, ldap_genhdir_prefix, "/",
899 LDAP_VALUE(canon_username, 0), NULL);
900 LDAP_VALUE_FREE(canon_username);
901 }
902
903 ++i;
904
905 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
906 "using default homedir %s", pw->pw_dir);
907 continue;
908 }
909
910 /* Don't worry if we don't have a loginShell attr. */
911 if (strcasecmp(attrs[i], ldap_attr_loginshell) == 0) {
912 /* Prevent a segfault if no loginShell attribute, and
913 * "RequireValidShell on" is in effect.
914 */
915 pw->pw_shell = pstrdup(session.pool, "");
916 ++i;
917 continue;
918 }
919
920 /* We only restart the while loop above if we can fill in alternate
921 * values for certain attributes. If something odd has happened, we
922 * fall through so we can complain.
923 */
924
925 dn = ldap_get_dn(ld, e);
926
927 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
928 "could not get values for attribute %s for DN %s, ignoring request "
929 "(perhaps this DN's entry does not have the attribute?)", attrs[i], dn);
930 free(dn);
931 ldap_msgfree(result);
932 return NULL;
933 }
934
935 /* Now that we've handled default values, fill in the struct as normal;
936 * the if branches below for nonexistent attrs will just never be
937 * called.
938 */
939
940 if (strcasecmp(attrs[i], ldap_attr_uid) == 0) {
941 pw->pw_name = pstrdup(session.pool, LDAP_VALUE(values, 0));
942
943 } else if (strcasecmp(attrs[i], ldap_attr_userpassword) == 0) {
944 pw->pw_passwd = pstrdup(session.pool, LDAP_VALUE(values, 0));
945
946 } else if (strcasecmp(attrs[i], ldap_attr_uidnumber) == 0) {
947 if (ldap_forcedefaultuid == TRUE &&
948 ldap_defaultuid != (uid_t) -1) {
949 pw->pw_uid = ldap_defaultuid;
950
951 } else {
952 pw->pw_uid = (uid_t) strtoul(LDAP_VALUE(values, 0), NULL, 10);
953 }
954
955 } else if (strcasecmp(attrs[i], ldap_attr_gidnumber) == 0) {
956 if (ldap_forcedefaultgid == TRUE &&
957 ldap_defaultgid != (gid_t) -1) {
958 pw->pw_gid = ldap_defaultgid;
959
960 } else {
961 pw->pw_gid = (gid_t) strtoul(LDAP_VALUE(values, 0), NULL, 10);
962 }
963
964 } else if (strcasecmp(attrs[i], ldap_attr_homedirectory) == 0) {
965 if (ldap_forcegenhdir == TRUE) {
966 if (ldap_genhdir == FALSE ||
967 ldap_genhdir_prefix == NULL) {
968
969 if (ldap_genhdir == FALSE) {
970 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
971 "LDAPForceGeneratedHomedir enabled but LDAPGenerateHomedir is "
972 "not enabled");
973
974 } else {
975 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
976 "LDAPForceGeneratedHomedir and LDAPGenerateHomedir enabled, but "
977 "missing required LDAPGenerateHomedirPrefix");
978 }
979
980 return NULL;
981 }
982
983 if (pw->pw_dir != NULL) {
984 pr_trace_msg(trace_channel, 8, "LDAPForceGeneratedHomedir in effect, "
985 "overriding current LDAP home directory '%s'", pw->pw_dir);
986 }
987
988 if (ldap_genhdir_prefix_nouname == TRUE) {
989 pw->pw_dir = pstrdup(session.pool, ldap_genhdir_prefix);
990
991 } else {
992 LDAP_VALUE_T **canon_username;
993 canon_username = LDAP_GET_VALUES(ld, e, ldap_attr_uid);
994 if (canon_username == NULL) {
995 dn = ldap_get_dn(ld, e);
996
997 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
998 "could not get %s attribute for canonical username for DN %s",
999 ldap_attr_uid, dn);
1000 free(dn);
1001 return NULL;
1002 }
1003
1004 pw->pw_dir = pstrcat(session.pool, ldap_genhdir_prefix, "/",
1005 LDAP_VALUE(canon_username, 0), NULL);
1006 LDAP_VALUE_FREE(canon_username);
1007 }
1008
1009 } else {
1010 pw->pw_dir = pstrdup(session.pool, LDAP_VALUE(values, 0));
1011 }
1012
1013 pr_trace_msg(trace_channel, 8, "using LDAP home directory '%s'",
1014 pw->pw_dir);
1015
1016 } else if (strcasecmp(attrs[i], ldap_attr_loginshell) == 0) {
1017 pw->pw_shell = pstrdup(session.pool, LDAP_VALUE(values, 0));
1018
1019 } else {
1020 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1021 "user lookup attribute/value loop found unknown attribute %s",
1022 attrs[i]);
1023 }
1024
1025 LDAP_VALUE_FREE(values);
1026 ++i;
1027 }
1028
1029 /* If we're doing auth binds, save the DN of this entry so we can
1030 * bind to the LDAP server as it later.
1031 */
1032 if (user_dn) {
1033 *user_dn = ldap_get_dn(ld, e);
1034 }
1035
1036 ldap_msgfree(result);
1037
1038 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1039 "found user %s, UID %s, GID %s, homedir %s, shell %s",
1040 pw->pw_name, pr_uid2str(p, pw->pw_uid), pr_gid2str(p, pw->pw_gid),
1041 pw->pw_dir, pw->pw_shell);
1042 return pw;
1043 }
1044
pr_ldap_group_lookup(pool * p,char * filter_template,const char * replace,char * attrs[])1045 static struct group *pr_ldap_group_lookup(pool *p, char *filter_template,
1046 const char *replace, char *attrs[]) {
1047 const char *filter;
1048 char *dn;
1049 int i = 0, value_count = 0, value_offset;
1050 struct group *gr;
1051 LDAPMessage *result, *e;
1052 LDAP_VALUE_T **values;
1053
1054 if (ldap_gid_basedn == NULL) {
1055 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1056 "no LDAP base DN specified for group lookups");
1057 return NULL;
1058 }
1059
1060 filter = pr_ldap_interpolate_filter(p, filter_template, replace);
1061 if (filter == NULL) {
1062 return NULL;
1063 }
1064
1065 result = pr_ldap_search(ldap_gid_basedn, filter, attrs, 2, TRUE);
1066 if (result == NULL) {
1067 return NULL;
1068 }
1069
1070 e = ldap_first_entry(ld, result);
1071 if (e == NULL) {
1072 ldap_msgfree(result);
1073
1074 /* No LDAP entries found for this user. */
1075 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1076 "no group entries for filter %s", filter);
1077 return NULL;
1078 }
1079
1080 gr = pcalloc(session.pool, sizeof(struct group));
1081 while (attrs[i] != NULL) {
1082 pr_signals_handle();
1083
1084 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1085 "fetching values for attribute %s", attrs[i]);
1086
1087 values = LDAP_GET_VALUES(ld, e, attrs[i]);
1088 if (values == NULL) {
1089 if (strcasecmp(attrs[i], ldap_attr_memberuid) == 0) {
1090 gr->gr_mem = palloc(session.pool, 2 * sizeof(char *));
1091 gr->gr_mem[0] = pstrdup(session.pool, "");
1092 gr->gr_mem[1] = NULL;
1093
1094 ++i;
1095 continue;
1096 }
1097
1098 ldap_msgfree(result);
1099 dn = ldap_get_dn(ld, e);
1100
1101 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1102 "could not get values for attribute %s for DN %s, ignoring request "
1103 "(perhaps that DN does not have that attribute?)", attrs[i], dn);
1104 free(dn);
1105 return NULL;
1106 }
1107
1108 if (strcasecmp(attrs[i], ldap_attr_cn) == 0) {
1109 gr->gr_name = pstrdup(session.pool, LDAP_VALUE(values, 0));
1110
1111 } else if (strcasecmp(attrs[i], ldap_attr_gidnumber) == 0) {
1112 gr->gr_gid = strtoul(LDAP_VALUE(values, 0), NULL, 10);
1113
1114 } else if (strcasecmp(attrs[i], ldap_attr_memberuid) == 0) {
1115 value_count = LDAP_COUNT_VALUES(values);
1116 gr->gr_mem = (char **) palloc(session.pool, value_count * sizeof(char *));
1117
1118 for (value_offset = 0; value_offset < value_count; ++value_offset) {
1119 gr->gr_mem[value_offset] =
1120 pstrdup(session.pool, LDAP_VALUE(values, value_offset));
1121 }
1122
1123 } else {
1124 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1125 "group lookup attribute/value loop found unknown attribute %s",
1126 attrs[i]);
1127 }
1128
1129 LDAP_VALUE_FREE(values);
1130 ++i;
1131 }
1132
1133 ldap_msgfree(result);
1134
1135 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1136 "found group %s, GID %s", gr->gr_name, pr_gid2str(NULL, gr->gr_gid));
1137 for (i = 0; i < value_count; ++i) {
1138 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1139 "+ member: %s", gr->gr_mem[i]);
1140 }
1141
1142 return gr;
1143 }
1144
parse_quota(pool * p,const char * replace,char * str)1145 static void parse_quota(pool *p, const char *replace, char *str) {
1146 char **elts, *token;
1147
1148 if (cached_quota == NULL) {
1149 cached_quota = make_array(p, 9, sizeof(char *));
1150 }
1151
1152 elts = (char **) cached_quota->elts;
1153 elts[0] = pstrdup(session.pool, replace);
1154 cached_quota->nelts = 1;
1155
1156 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1157 "parsing ftpQuota attribute value '%s'", str);
1158
1159 while ((token = strsep(&str, ","))) {
1160 pr_signals_handle();
1161 *((char **) push_array(cached_quota)) = pstrdup(session.pool, token);
1162 }
1163 }
1164
pr_ldap_quota_lookup(pool * p,char * filter_template,const char * replace,const char * basedn)1165 static unsigned char pr_ldap_quota_lookup(pool *p, char *filter_template,
1166 const char *replace, const char *basedn) {
1167 const char *filter = NULL;
1168 char *attrs[] = {
1169 ldap_attr_ftpquota, ldap_attr_ftpquota_profiledn, NULL,
1170 };
1171 int orig_scope, res;
1172 LDAPMessage *result, *e;
1173 LDAP_VALUE_T **values;
1174
1175 if (basedn == NULL) {
1176 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1177 "no LDAP base DN specified for quota lookups, declining request");
1178 return FALSE;
1179 }
1180
1181 if (filter_template != NULL) {
1182 filter = pr_ldap_interpolate_filter(p, filter_template, replace);
1183 if (filter == NULL) {
1184 return FALSE;
1185 }
1186 }
1187
1188 result = pr_ldap_search(basedn, filter, attrs, 2, TRUE);
1189 if (result == NULL) {
1190 return FALSE;
1191 }
1192
1193 if (ldap_count_entries(ld, result) > 1) {
1194 ldap_msgfree(result);
1195
1196 if (ldap_default_quota != NULL) {
1197 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1198 "multiple entries found for DN %s, using default quota %s", basedn,
1199 ldap_default_quota);
1200 parse_quota(p, replace, pstrdup(p, ldap_default_quota));
1201 return TRUE;
1202
1203 } else {
1204 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1205 "multiple entries found for DN %s, aborting query", basedn);
1206 }
1207
1208 return FALSE;
1209 }
1210
1211 e = ldap_first_entry(ld, result);
1212 if (e == NULL) {
1213 ldap_msgfree(result);
1214 if (ldap_default_quota == NULL) {
1215 if (filter == NULL) {
1216 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1217 "no entries for DN %s, and no default quota defined", basedn);
1218
1219 } else {
1220 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1221 "no entries for filter %s, and no default quota defined", filter);
1222 }
1223
1224 return FALSE;
1225 }
1226
1227 if (filter == NULL) {
1228 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1229 "no entries for DN %s, using default quota %s", basedn,
1230 ldap_default_quota);
1231
1232 } else {
1233 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1234 "no entries for filter %s, using default quota %s", filter,
1235 ldap_default_quota);
1236 }
1237
1238 parse_quota(p, replace, pstrdup(p, ldap_default_quota));
1239 return TRUE;
1240 }
1241
1242 values = LDAP_GET_VALUES(ld, e, attrs[0]);
1243 if (values != NULL) {
1244 parse_quota(p, replace, pstrdup(p, LDAP_VALUE(values, 0)));
1245 LDAP_VALUE_FREE(values);
1246 ldap_msgfree(result);
1247 return TRUE;
1248 }
1249
1250 if (filter == NULL) {
1251 if (ldap_default_quota == NULL) {
1252 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1253 "referenced DN %s does not have an ftpQuota attribute, and no "
1254 "default quota defined", basedn);
1255 return FALSE;
1256 }
1257
1258 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1259 "no ftpQuota attribute found for DN %s, using default quota %s", basedn,
1260 ldap_default_quota);
1261 parse_quota(p, replace, pstrdup(p, ldap_default_quota));
1262 return TRUE;
1263 }
1264
1265 values = LDAP_GET_VALUES(ld, e, attrs[1]);
1266 if (values != NULL) {
1267 orig_scope = ldap_search_scope;
1268 ldap_search_scope = LDAP_SCOPE_BASE;
1269 res = pr_ldap_quota_lookup(p, NULL, replace, LDAP_VALUE(values, 0));
1270 ldap_search_scope = orig_scope;
1271 LDAP_VALUE_FREE(values);
1272 ldap_msgfree(result);
1273 return res;
1274 }
1275
1276 ldap_msgfree(result);
1277 if (ldap_default_quota != NULL) {
1278 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1279 "no %s or %s attribute, using default quota %s", attrs[0], attrs[1],
1280 ldap_default_quota);
1281 parse_quota(p, replace, pstrdup(p, ldap_default_quota));
1282 return TRUE;
1283 }
1284
1285 /* No quota attributes for this user. */
1286 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1287 "no %s or %s attribute, and no default quota defined", attrs[0], attrs[1]);
1288 return FALSE;
1289 }
1290
pr_ldap_ssh_pubkey_lookup(pool * p,char * filter_template,const char * replace,char * basedn)1291 static unsigned char pr_ldap_ssh_pubkey_lookup(pool *p, char *filter_template,
1292 const char *replace, char *basedn) {
1293 const char *filter;
1294 char *attrs[] = {
1295 ldap_attr_ssh_pubkey, NULL,
1296 };
1297 int num_keys, i;
1298 LDAPMessage *result, *e;
1299 LDAP_VALUE_T **values;
1300
1301 if (basedn == NULL) {
1302 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1303 "no LDAP base DN specified for user lookups, declining SSH publickey "
1304 "lookup request");
1305 return FALSE;
1306 }
1307
1308 filter = pr_ldap_interpolate_filter(p, filter_template, replace);
1309 if (filter == NULL) {
1310 return FALSE;
1311 }
1312
1313 result = pr_ldap_search(basedn, filter, attrs, 2, TRUE);
1314 if (result == NULL) {
1315 return FALSE;
1316 }
1317
1318 if (ldap_count_entries(ld, result) > 1) {
1319 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1320 "LDAP search for SSH publickey using DN %s, filter %s returned multiple "
1321 "entries, aborting query", basedn, filter);
1322 ldap_msgfree(result);
1323 return FALSE;
1324 }
1325
1326 e = ldap_first_entry(ld, result);
1327 if (e == NULL) {
1328 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1329 "LDAP search for SSH publickey using DN %s, filter %s returned "
1330 "no entries", basedn, filter);
1331 ldap_msgfree(result);
1332 return FALSE;
1333 }
1334
1335 values = LDAP_GET_VALUES(ld, e, attrs[0]);
1336 if (values == NULL) {
1337 return FALSE;
1338 }
1339
1340 num_keys = LDAP_COUNT_VALUES(values);
1341 cached_ssh_pubkeys = make_array(p, num_keys, sizeof(char *));
1342 for (i = 0; i < num_keys; ++i) {
1343 *((char **) push_array(cached_ssh_pubkeys)) = pstrdup(p,
1344 LDAP_VALUE(values, i));
1345 }
1346 LDAP_VALUE_FREE(values);
1347
1348 ldap_msgfree(result);
1349 return TRUE;
1350 }
1351
pr_ldap_getgrnam(pool * p,const char * group_name)1352 static struct group *pr_ldap_getgrnam(pool *p, const char *group_name) {
1353 char *group_attrs[] = {
1354 ldap_attr_cn, ldap_attr_gidnumber, ldap_attr_memberuid, NULL,
1355 };
1356
1357 return pr_ldap_group_lookup(p, ldap_group_name_filter, group_name,
1358 group_attrs);
1359 }
1360
pr_ldap_getgrgid(pool * p,gid_t gid)1361 static struct group *pr_ldap_getgrgid(pool *p, gid_t gid) {
1362 const char *gidstr;
1363 char *group_attrs[] = {
1364 ldap_attr_cn, ldap_attr_gidnumber, ldap_attr_memberuid, NULL,
1365 };
1366
1367 gidstr = pr_gid2str(p, gid);
1368 return pr_ldap_group_lookup(p, ldap_group_gid_filter, gidstr, group_attrs);
1369 }
1370
pr_ldap_getpwnam(pool * p,const char * username)1371 static struct passwd *pr_ldap_getpwnam(pool *p, const char *username) {
1372 const char *filter;
1373 char *name_attrs[] = {
1374 ldap_attr_userpassword, ldap_attr_uid, ldap_attr_uidnumber,
1375 ldap_attr_gidnumber, ldap_attr_homedirectory,
1376 ldap_attr_loginshell, NULL,
1377 };
1378
1379 filter = pr_ldap_interpolate_filter(p, ldap_user_basedn, username);
1380 if (filter == NULL) {
1381 return NULL;
1382 }
1383
1384 /* pr_ldap_user_lookup() returns NULL if it doesn't find an entry or
1385 * encounters an error. If everything goes all right, it returns a
1386 * struct passwd, so we can just return its result directly.
1387 *
1388 * We also do some cute stuff here to work around lameness in LDAP servers
1389 * like Sun Directory Services (SDS) 1.x and 3.x. If you request an attr
1390 * that you don't have access to, SDS totally ignores any entries with
1391 * that attribute. Thank you, Sun; how very smart of you. So if we're
1392 * doing auth binds, we don't request the userPassword attr.
1393 *
1394 * NOTE: if the UserPassword directive is configured, mod_auth will pass
1395 * a crypted password to ldap_auth_check(), which will NOT do auth binds
1396 * in order to support UserPassword. (Otherwise, it would try binding to
1397 * the directory and would ignore UserPassword.)
1398 *
1399 * We're reasonably safe in making that assumption as long as we never
1400 * fetch userPassword from the directory if auth binds are enabled. If we
1401 * fetched userPassword, auth binds would never be done because
1402 * ldap_auth_check() would always get a crypted password.
1403 */
1404 return pr_ldap_user_lookup(p, ldap_user_name_filter, username, filter,
1405 ldap_authbinds ? name_attrs + 1 : name_attrs,
1406 ldap_authbinds ? &ldap_authbind_dn : NULL);
1407 }
1408
pr_ldap_getpwuid(pool * p,uid_t uid)1409 static struct passwd *pr_ldap_getpwuid(pool *p, uid_t uid) {
1410 const char *uidstr;
1411 char *uid_attrs[] = {
1412 ldap_attr_uid, ldap_attr_uidnumber, ldap_attr_gidnumber,
1413 ldap_attr_homedirectory, ldap_attr_loginshell, NULL,
1414 };
1415
1416 uidstr = pr_uid2str(p, uid);
1417 return pr_ldap_user_lookup(p, ldap_user_uid_filter, uidstr,
1418 ldap_user_basedn, uid_attrs, ldap_authbinds ? &ldap_authbind_dn : NULL);
1419 }
1420
handle_ldap_quota_lookup(cmd_rec * cmd)1421 MODRET handle_ldap_quota_lookup(cmd_rec *cmd) {
1422 const char *basedn;
1423
1424 basedn = pr_ldap_interpolate_filter(cmd->tmp_pool,
1425 ldap_user_basedn, cmd->argv[0]);
1426 if (basedn == NULL) {
1427 return PR_DECLINED(cmd);
1428 }
1429
1430 if (cached_quota == NULL ||
1431 strcasecmp(((char **) cached_quota->elts)[0], cmd->argv[0]) != 0) {
1432
1433 if (pr_ldap_quota_lookup(cmd->tmp_pool, ldap_user_name_filter,
1434 cmd->argv[0], basedn) == FALSE) {
1435 return PR_DECLINED(cmd);
1436 }
1437
1438 } else {
1439 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1440 "returning cached quota for user %s", (char *) cmd->argv[0]);
1441 }
1442
1443 return mod_create_data(cmd, cached_quota);
1444 }
1445
handle_ldap_ssh_pubkey_lookup(cmd_rec * cmd)1446 MODRET handle_ldap_ssh_pubkey_lookup(cmd_rec *cmd) {
1447 char *user;
1448
1449 if (ldap_do_users == FALSE) {
1450 return PR_DECLINED(cmd);
1451 }
1452
1453 user = cmd->argv[0];
1454
1455 if (cached_ssh_pubkeys != NULL &&
1456 cached_ssh_pubkeys->nelts > 0 &&
1457 strcasecmp(((char **) cached_ssh_pubkeys->elts)[0], user) == 0) {
1458
1459 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1460 "returning cached SSH public keys for user %s", user);
1461 return mod_create_data(cmd, cached_ssh_pubkeys);
1462 }
1463
1464 if (pr_ldap_ssh_pubkey_lookup(cmd->tmp_pool, ldap_user_name_filter,
1465 user, ldap_user_basedn) == FALSE) {
1466 return PR_DECLINED(cmd);
1467 }
1468
1469 return mod_create_data(cmd, cached_ssh_pubkeys);
1470 }
1471
1472 /* Auth handlers */
ldap_auth_setpwent(cmd_rec * cmd)1473 MODRET ldap_auth_setpwent(cmd_rec *cmd) {
1474 if (ldap_do_users == FALSE &&
1475 ldap_do_groups == FALSE) {
1476 return PR_DECLINED(cmd);
1477 }
1478
1479 if (ld == NULL) {
1480 (void) pr_ldap_connect(&ld, TRUE);
1481 }
1482
1483 return PR_HANDLED(cmd);
1484 }
1485
ldap_auth_endpwent(cmd_rec * cmd)1486 MODRET ldap_auth_endpwent(cmd_rec *cmd) {
1487 if (ldap_do_users == FALSE &&
1488 ldap_do_groups == FALSE) {
1489 return PR_DECLINED(cmd);
1490 }
1491
1492 pr_ldap_unbind();
1493 return PR_HANDLED(cmd);
1494 }
1495
ldap_auth_getpwuid(cmd_rec * cmd)1496 MODRET ldap_auth_getpwuid(cmd_rec *cmd) {
1497 struct passwd *pw = NULL;
1498
1499 if (ldap_do_users == FALSE) {
1500 return PR_DECLINED(cmd);
1501 }
1502
1503 pw = pr_ldap_getpwuid(cmd->tmp_pool, *((uid_t *) cmd->argv[0]));
1504 if (pw != NULL) {
1505 return mod_create_data(cmd, pw);
1506 }
1507
1508 return PR_DECLINED(cmd);
1509 }
1510
ldap_auth_getpwnam(cmd_rec * cmd)1511 MODRET ldap_auth_getpwnam(cmd_rec *cmd) {
1512 struct passwd *pw = NULL;
1513
1514 if (ldap_do_users == FALSE) {
1515 return PR_DECLINED(cmd);
1516 }
1517
1518 pw = pr_ldap_getpwnam(cmd->tmp_pool, cmd->argv[0]);
1519 if (pw != NULL) {
1520 return mod_create_data(cmd, pw);
1521 }
1522
1523 return PR_DECLINED(cmd);
1524 }
1525
ldap_auth_getgrnam(cmd_rec * cmd)1526 MODRET ldap_auth_getgrnam(cmd_rec *cmd) {
1527 struct group *gr = NULL;
1528
1529 if (ldap_do_groups == FALSE) {
1530 return PR_DECLINED(cmd);
1531 }
1532
1533 gr = pr_ldap_getgrnam(cmd->tmp_pool, cmd->argv[0]);
1534 if (gr != NULL) {
1535 return mod_create_data(cmd, gr);
1536 }
1537
1538 return PR_DECLINED(cmd);
1539 }
1540
ldap_auth_getgrgid(cmd_rec * cmd)1541 MODRET ldap_auth_getgrgid(cmd_rec *cmd) {
1542 struct group *gr = NULL;
1543
1544 if (ldap_do_groups == FALSE) {
1545 return PR_DECLINED(cmd);
1546 }
1547
1548 gr = pr_ldap_getgrgid(cmd->tmp_pool, *((gid_t *) cmd->argv[0]));
1549 if (gr != NULL) {
1550 return mod_create_data(cmd, gr);
1551 }
1552
1553 return PR_DECLINED(cmd);
1554 }
1555
ldap_auth_getgroups(cmd_rec * cmd)1556 MODRET ldap_auth_getgroups(cmd_rec *cmd) {
1557 const char *filter;
1558 char *w[] = {
1559 ldap_attr_gidnumber, ldap_attr_cn, NULL,
1560 };
1561 struct passwd *pw;
1562 struct group *gr;
1563 LDAPMessage *result = NULL, *e;
1564 LDAP_VALUE_T **gidNumber, **cn;
1565 array_header *gids = (array_header *)cmd->argv[1],
1566 *groups = (array_header *)cmd->argv[2];
1567
1568 if (ldap_do_groups == FALSE) {
1569 return PR_DECLINED(cmd);
1570 }
1571
1572 if (gids == NULL ||
1573 groups == NULL) {
1574 return PR_DECLINED(cmd);
1575 }
1576
1577 pw = pr_ldap_getpwnam(cmd->tmp_pool, cmd->argv[0]);
1578 if (pw != NULL) {
1579 gr = pr_ldap_getgrgid(cmd->tmp_pool, pw->pw_gid);
1580 if (gr != NULL) {
1581 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1582 "adding user %s primary group %s/%s", pw->pw_name, gr->gr_name,
1583 pr_gid2str(NULL, pw->pw_gid));
1584 *((gid_t *) push_array(gids)) = pw->pw_gid;
1585 *((char **) push_array(groups)) = pstrdup(session.pool, gr->gr_name);
1586
1587 } else {
1588 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1589 "unable to determine group name for user %s primary GID %s, skipping",
1590 pw->pw_name, pr_gid2str(NULL, pw->pw_gid));
1591 }
1592 }
1593
1594 if (ldap_gid_basedn == NULL) {
1595 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1596 "no LDAP base DN specified for group lookups");
1597 goto return_groups;
1598 }
1599
1600 filter = pr_ldap_interpolate_filter(cmd->tmp_pool,
1601 ldap_group_member_filter, cmd->argv[0]);
1602 if (filter == NULL) {
1603 return NULL;
1604 }
1605
1606 result = pr_ldap_search(ldap_gid_basedn, filter, w, 0, TRUE);
1607 if (result == NULL) {
1608 return FALSE;
1609 }
1610
1611 if (ldap_count_entries(ld, result) == 0) {
1612 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1613 "no entries found for filter %s", filter);
1614 goto return_groups;
1615 }
1616
1617 for (e = ldap_first_entry(ld, result); e; e = ldap_next_entry(ld, e)) {
1618 gidNumber = LDAP_GET_VALUES(ld, e, w[0]);
1619 if (gidNumber == NULL) {
1620 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1621 "could not get values for %s attribute for getgroups(2), skipping "
1622 "current group", ldap_attr_gidnumber);
1623 continue;
1624 }
1625
1626 cn = LDAP_GET_VALUES(ld, e, w[1]);
1627 if (cn == NULL) {
1628 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1629 "could not get values for %s attribute for getgroups(2), skipping "
1630 "current group", ldap_attr_cn);
1631 continue;
1632 }
1633
1634 if (pw == NULL ||
1635 strtoul(LDAP_VALUE(gidNumber, 0), NULL, 10) != pw->pw_gid) {
1636 *((gid_t *) push_array(gids)) = strtoul(LDAP_VALUE(gidNumber, 0), NULL, 10);
1637 *((char **) push_array(groups)) = pstrdup(session.pool, LDAP_VALUE(cn, 0));
1638
1639 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1640 "added user %s secondary group %s/%s",
1641 (pw && pw->pw_name) ? pw->pw_name : (char *) cmd->argv[0],
1642 LDAP_VALUE(cn, 0), LDAP_VALUE(gidNumber, 0));
1643 }
1644
1645 LDAP_VALUE_FREE(gidNumber);
1646 LDAP_VALUE_FREE(cn);
1647 }
1648
1649 return_groups:
1650 if (result) {
1651 ldap_msgfree(result);
1652 }
1653
1654 if (gids->nelts > 0) {
1655 return mod_create_data(cmd, (void *) &gids->nelts);
1656 }
1657
1658 return PR_DECLINED(cmd);
1659 }
1660
1661 /* cmd->argv[0] : user name
1662 * cmd->argv[1] : cleartext password
1663 */
ldap_auth_auth(cmd_rec * cmd)1664 MODRET ldap_auth_auth(cmd_rec *cmd) {
1665 const char *filter = NULL, *username;
1666 char *pass_attrs[] = {
1667 ldap_attr_userpassword, ldap_attr_uid, ldap_attr_uidnumber,
1668 ldap_attr_gidnumber, ldap_attr_homedirectory,
1669 ldap_attr_loginshell, NULL,
1670 };
1671 struct passwd *pw = NULL;
1672 int res;
1673
1674 if (ldap_do_users == FALSE) {
1675 return PR_DECLINED(cmd);
1676 }
1677
1678 username = cmd->argv[0];
1679
1680 filter = pr_ldap_interpolate_filter(cmd->tmp_pool, ldap_user_basedn,
1681 username);
1682 if (filter == NULL) {
1683 return NULL;
1684 }
1685
1686 /* If anything here fails hard (IOW, we've found an LDAP entry for the
1687 * user, but they appear to have entered the wrong password), fail auth.
1688 * Normally, I'd DECLINE here so other modules could have a shot, but if
1689 * we've found their LDAP entry, chances are that nothing else will be
1690 * able to auth them.
1691 */
1692
1693 pw = pr_ldap_user_lookup(cmd->tmp_pool,
1694 ldap_user_name_filter, username, filter,
1695 ldap_authbinds ? pass_attrs + 1 : pass_attrs,
1696 ldap_authbinds ? &ldap_authbind_dn : NULL);
1697 if (pw == NULL) {
1698 /* Can't find the user in the LDAP directory. */
1699 return PR_DECLINED(cmd);
1700 }
1701
1702 if (ldap_authbinds == FALSE &&
1703 pw->pw_passwd == NULL) {
1704 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1705 "LDAPAuthBinds not enabled, and unable to retrieve password for user %s",
1706 pw->pw_name);
1707 return PR_ERROR_INT(cmd, PR_AUTH_NOPWD);
1708 }
1709
1710 res = pr_auth_check(cmd->tmp_pool, ldap_authbinds ? NULL : pw->pw_passwd,
1711 username, cmd->argv[1]);
1712 if (res != 0) {
1713 if (res == -1) {
1714 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1715 "bad password for user %s: %s", pw->pw_name, strerror(errno));
1716
1717 } else {
1718 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1719 "bad password for user %s", pw->pw_name);
1720 }
1721
1722 return PR_ERROR_INT(cmd, PR_AUTH_BADPWD);
1723 }
1724
1725 session.auth_mech = "mod_ldap.c";
1726 return PR_HANDLED(cmd);
1727 }
1728
1729 /* cmd->argv[0] = hashed password
1730 * cmd->argv[1] = user
1731 * cmd->argv[2] = cleartext
1732 */
ldap_auth_check(cmd_rec * cmd)1733 MODRET ldap_auth_check(cmd_rec *cmd) {
1734 char *pass, *cryptpass, *hash_method, *crypted;
1735 int encname_len, res;
1736 LDAP *ld_auth;
1737 #ifdef HAS_LDAP_SASL_BIND_S
1738 struct berval bindcred;
1739 #endif
1740
1741 if (ldap_do_users == FALSE) {
1742 return PR_DECLINED(cmd);
1743 }
1744
1745 cryptpass = cmd->argv[0];
1746 pass = cmd->argv[2];
1747
1748 /* At this point, any encrypted password must have come from the UserPassword
1749 * directive. Don't perform auth binds in this case, since the crypted
1750 * password specified should override auth binds.
1751 */
1752 if (ldap_authbinds == TRUE &&
1753 cryptpass == NULL) {
1754 /* Don't try to do auth binds with a NULL/empty DN or password. */
1755 if (pass == NULL ||
1756 strlen(pass) == 0) {
1757 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1758 "LDAPAuthBinds is enabled, but no user-supplied cleartext password "
1759 "was found");
1760 return PR_DECLINED(cmd);
1761 }
1762
1763 if (ldap_authbind_dn == NULL ||
1764 strlen(ldap_authbind_dn) == 0) {
1765 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1766 "LDAPAuthBinds is enabled, but no LDAP DN was found");
1767 return PR_DECLINED(cmd);
1768 }
1769
1770 if (pr_ldap_connect(&ld_auth, FALSE) < 0) {
1771 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1772 "unable to check login: LDAP connection failed");
1773 return PR_DECLINED(cmd);
1774 }
1775
1776 #ifdef HAS_LDAP_SASL_BIND_S
1777 bindcred.bv_val = cmd->argv[2];
1778 bindcred.bv_len = strlen(cmd->argv[2]);
1779 res = ldap_sasl_bind_s(ld_auth, ldap_authbind_dn, NULL, &bindcred,
1780 NULL, NULL, NULL);
1781 #else /* HAS_LDAP_SASL_BIND_S */
1782 res = ldap_simple_bind_s(ld_auth, ldap_authbind_dn, cmd->argv[2]);
1783 #endif /* HAS_LDAP_SASL_BIND_S */
1784
1785 if (res != LDAP_SUCCESS) {
1786 if (res != LDAP_INVALID_CREDENTIALS) {
1787 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1788 "unable to check login: bind as %s failed: %s", ldap_authbind_dn,
1789 ldap_err2string(res));
1790 }
1791
1792 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
1793 "invalid credentials used for %s", ldap_authbind_dn);
1794 LDAP_UNBIND(ld_auth);
1795 return PR_ERROR(cmd);
1796 }
1797
1798 LDAP_UNBIND(ld_auth);
1799 session.auth_mech = "mod_ldap.c";
1800 return PR_HANDLED(cmd);
1801 }
1802
1803 /* Get the length of "scheme" in the leading {scheme} so we can skip it
1804 * in the password comparison.
1805 */
1806 encname_len = strcspn(cryptpass + 1, "}");
1807 hash_method = pstrndup(cmd->tmp_pool, cryptpass + 1, encname_len);
1808
1809 /* Check to see how the password is encrypted, and check accordingly. */
1810
1811 if ((size_t) encname_len == strlen(cryptpass + 1)) {
1812 /* No leading {scheme}. */
1813 hash_method = ldap_defaultauthscheme;
1814 encname_len = 0;
1815
1816 } else {
1817 encname_len += 2;
1818 }
1819
1820 /* The {crypt} scheme */
1821 if (strncasecmp(hash_method, "crypt", strlen(hash_method)) == 0) {
1822 crypted = crypt(pass, cryptpass + encname_len);
1823 if (crypted == NULL) {
1824 pr_trace_msg(trace_channel, 19,
1825 "using %s auth scheme, crypt(3) failed: %s", hash_method,
1826 strerror(errno));
1827 return PR_ERROR(cmd);
1828 }
1829
1830 if (strcmp(crypted, cryptpass + encname_len) != 0) {
1831 pr_trace_msg(trace_channel, 19,
1832 "using '%s' auth scheme, comparison failed", hash_method);
1833 return PR_ERROR(cmd);
1834 }
1835
1836 /* The {clear} scheme */
1837 } else if (strncasecmp(hash_method, "clear", strlen(hash_method)) == 0) {
1838 if (strcmp(pass, cryptpass + encname_len) != 0) {
1839 pr_trace_msg(trace_channel, 19,
1840 "using '%s' auth scheme, comparison failed", hash_method);
1841 return PR_ERROR(cmd);
1842 }
1843
1844 } else {
1845 /* Can't find a supported {scheme} */
1846 pr_trace_msg(trace_channel, 3,
1847 "unsupported userPassword auth scheme: %s", hash_method);
1848 return PR_DECLINED(cmd);
1849 }
1850
1851 session.auth_mech = "mod_ldap.c";
1852 return PR_HANDLED(cmd);
1853 }
1854
ldap_auth_uid2name(cmd_rec * cmd)1855 MODRET ldap_auth_uid2name(cmd_rec *cmd) {
1856 struct passwd *pw = NULL;
1857
1858 if (ldap_do_users == FALSE) {
1859 return PR_DECLINED(cmd);
1860 }
1861
1862 pw = pr_ldap_getpwuid(cmd->tmp_pool, *((uid_t *) cmd->argv[0]));
1863 if (pw == NULL) {
1864 /* Can't find the user in the LDAP directory. */
1865 return PR_DECLINED(cmd);
1866 }
1867
1868 return mod_create_data(cmd, pstrdup(permanent_pool, pw->pw_name));
1869 }
1870
ldap_auth_gid2name(cmd_rec * cmd)1871 MODRET ldap_auth_gid2name(cmd_rec *cmd) {
1872 struct group *gr = NULL;
1873
1874 if (ldap_do_groups == FALSE) {
1875 return PR_DECLINED(cmd);
1876 }
1877
1878 gr = pr_ldap_getgrgid(cmd->tmp_pool, *((gid_t *) cmd->argv[0]));
1879 if (gr == NULL) {
1880 /* Can't find the user in the LDAP directory. */
1881 return PR_DECLINED(cmd);
1882 }
1883
1884 return mod_create_data(cmd, pstrdup(permanent_pool, gr->gr_name));
1885 }
1886
ldap_auth_name2uid(cmd_rec * cmd)1887 MODRET ldap_auth_name2uid(cmd_rec *cmd) {
1888 struct passwd *pw = NULL;
1889
1890 if (ldap_do_users == FALSE) {
1891 return PR_DECLINED(cmd);
1892 }
1893
1894 pw = pr_ldap_getpwnam(cmd->tmp_pool, cmd->argv[0]);
1895 if (pw == NULL) {
1896 return PR_DECLINED(cmd);
1897 }
1898
1899 return mod_create_data(cmd, (void *) &pw->pw_uid);
1900 }
1901
ldap_auth_name2gid(cmd_rec * cmd)1902 MODRET ldap_auth_name2gid(cmd_rec *cmd) {
1903 struct group *gr = NULL;
1904
1905 if (ldap_do_groups == FALSE) {
1906 return PR_DECLINED(cmd);
1907 }
1908
1909 gr = pr_ldap_getgrnam(cmd->tmp_pool, cmd->argv[0]);
1910 if (gr == NULL) {
1911 return PR_DECLINED(cmd);
1912 }
1913
1914 return mod_create_data(cmd, (void *) &gr->gr_gid);
1915 }
1916
1917 /* sasl_info functions. */
1918
1919 /* Note: by proving empty strings, rather than NULLs, for the default values,
1920 * we make the logic in sasl_interact_cb() simpler.
1921 */
sasl_info_create(pool * p,LDAP * conn_ld)1922 static struct sasl_info *sasl_info_create(pool *p, LDAP *conn_ld) {
1923 pool *sasl_pool;
1924 struct sasl_info *sasl;
1925
1926 sasl_pool = make_sub_pool(p);
1927 pr_pool_tag(sasl_pool, "SASL Info Pool");
1928
1929 sasl = pcalloc(sasl_pool, sizeof(struct sasl_info));
1930 sasl->pool = sasl_pool;
1931
1932 #if defined(LDAP_OPT_X_SASL_AUTHCID)
1933 {
1934 int res;
1935 char *sasl_authcid = NULL;
1936
1937 res = ldap_get_option(conn_ld, LDAP_OPT_X_SASL_AUTHCID, &sasl_authcid);
1938 if (res == LDAP_OPT_SUCCESS) {
1939 if (sasl_authcid != NULL) {
1940 pr_trace_msg(trace_channel, 12,
1941 "LDAP SASL default authentication ID = %s (see SASL_AUTHCID in "
1942 "ldap.conf)", sasl_authcid);
1943 sasl->authentication_id = pstrdup(sasl_pool, sasl_authcid);
1944 ldap_memfree(sasl_authcid);
1945
1946 } else {
1947 sasl->authentication_id = pstrdup(sasl_pool, "");
1948 }
1949
1950 } else {
1951 pr_trace_msg(trace_channel, 3,
1952 "error retrieving LDAP_OPT_X_SASL_AUTHCID: %s", ldap_err2string(res));
1953 }
1954 }
1955 #endif /* LDAP_OPT_X_SASL_AUTHCID */
1956
1957 #if defined(LDAP_OPT_X_SASL_AUTHZID)
1958 {
1959 int res;
1960 char *sasl_authzid = NULL;
1961
1962 res = ldap_get_option(conn_ld, LDAP_OPT_X_SASL_AUTHZID, &sasl_authzid);
1963 if (res == LDAP_OPT_SUCCESS) {
1964 if (sasl_authzid != NULL) {
1965 pr_trace_msg(trace_channel, 12,
1966 "LDAP SASL default authorization ID = %s (see SASL_AUTHZID in "
1967 "ldap.conf)", sasl_authzid);
1968 sasl->authorization_id = pstrdup(sasl_pool, sasl_authzid);
1969 ldap_memfree(sasl_authzid);
1970
1971 } else {
1972 sasl->authorization_id = pstrdup(sasl_pool, "");
1973 }
1974
1975 } else {
1976 pr_trace_msg(trace_channel, 3,
1977 "error retrieving LDAP_OPT_X_SASL_AUTHZID: %s", ldap_err2string(res));
1978 }
1979 }
1980 #endif /* LDAP_OPT_X_SASL_AUTHZID */
1981
1982 #if defined(LDAP_OPT_X_SASL_REALM)
1983 {
1984 int res;
1985 char *sasl_realm = NULL;
1986
1987 res = ldap_get_option(conn_ld, LDAP_OPT_X_SASL_REALM, &sasl_realm);
1988 if (res == LDAP_OPT_SUCCESS) {
1989 if (sasl_realm != NULL) {
1990 pr_trace_msg(trace_channel, 12,
1991 "LDAP SASL default realm = %s (see SASL_REALM in ldap.conf)",
1992 sasl_realm);
1993 sasl->realm = pstrdup(sasl_pool, sasl_realm);
1994 ldap_memfree(sasl_realm);
1995
1996 } else {
1997 sasl->realm = pstrdup(sasl_pool, "");
1998 }
1999
2000 } else {
2001 pr_trace_msg(trace_channel, 3,
2002 "error retrieving LDAP_OPT_X_SASL_REALM: %s", ldap_err2string(res));
2003 }
2004 }
2005 #endif /* LDAP_OPT_X_SASL_REALM */
2006
2007 return sasl;
2008 }
2009
sasl_info_get_authcid_from_dn(struct sasl_info * sasl,const char * dn_text)2010 static void sasl_info_get_authcid_from_dn(struct sasl_info *sasl,
2011 const char *dn_text) {
2012 register unsigned int i;
2013 LDAPDN dn;
2014 int flags = LDAP_DN_FORMAT_LDAPV3, res;
2015
2016 /* LDAPDN is actually LDAPRDN *, a pointer to a list of LDAPRDN. Which
2017 * makes sense, since a DN is a list of RDNs. And each LDAPRDN is actually
2018 * LDAPAVA *, a pointer to a list of LDAPAVA (Attribute Value Assertions).
2019 */
2020 res = ldap_str2dn(dn_text, &dn, flags);
2021 if (res != LDAP_SUCCESS) {
2022 pr_trace_msg(trace_channel, 3,
2023 "error parsing DN '%s': %s", dn_text, ldap_err2string(res));
2024 return;
2025 }
2026
2027 for (i = 0; dn[i]; i++) {
2028 LDAPRDN rdn;
2029 char *rdn_text = NULL;
2030
2031 rdn = dn[i];
2032 res = ldap_rdn2str(rdn, &rdn_text, flags);
2033 if (res == LDAP_SUCCESS) {
2034 if (strncasecmp(rdn_text, "CN=", 3) == 0) {
2035 sasl->authentication_id = pstrdup(sasl->pool, rdn_text + 3);
2036 }
2037 ldap_memfree(rdn_text);
2038
2039 if (sasl->authentication_id != NULL) {
2040 break;
2041 }
2042
2043 } else {
2044 pr_trace_msg(trace_channel, 3,
2045 "error converting RDN to text: %s", ldap_err2string(res));
2046 }
2047 }
2048
2049 ldap_dnfree(dn);
2050 }
2051
2052 /* server_info functions. */
server_info_create(pool * p)2053 static struct server_info *server_info_create(pool *p) {
2054 struct server_info *info;
2055
2056 info = pcalloc(p, sizeof(struct server_info));
2057 info->ssl_verify = -1;
2058
2059 return info;
2060 }
2061
server_info_get_ssl_defaults(struct server_info * info)2062 static void server_info_get_ssl_defaults(struct server_info *info) {
2063 #if defined(LDAP_OPT_X_TLS)
2064 int res, ssl_verify;
2065 char *ssl_val = NULL;
2066
2067 /* Fill in the SSL defaults, if not explicitly configured. */
2068
2069 # if defined(LDAP_OPT_X_TLS_CACERTFILE)
2070 if (info->ssl_ca_file == NULL) {
2071 ssl_val = NULL;
2072 res = ldap_get_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, &ssl_val);
2073 if (res == LDAP_OPT_SUCCESS) {
2074 if (ssl_val != NULL) {
2075 pr_trace_msg(trace_channel, 17,
2076 "using default 'ssl-ca' value: %s", ssl_val);
2077 info->ssl_ca_file = ldap_strdup(ssl_val);
2078 }
2079 }
2080 }
2081 # endif /* LDAP_OPT_X_TLS_CACERTFILE */
2082
2083 # if defined(LDAP_OPT_X_TLS_CERTFILE)
2084 if (info->ssl_cert_file == NULL) {
2085 ssl_val = NULL;
2086 res = ldap_get_option(NULL, LDAP_OPT_X_TLS_CERTFILE, &ssl_val);
2087 if (res == LDAP_OPT_SUCCESS) {
2088 if (ssl_val != NULL) {
2089 pr_trace_msg(trace_channel, 17,
2090 "using default 'ssl-cert' value: %s", ssl_val);
2091 info->ssl_cert_file = ldap_strdup(ssl_val);
2092 }
2093 }
2094 }
2095 # endif /* LDAP_OPT_X_TLS_CERTFILE */
2096
2097 # if defined(LDAP_OPT_X_TLS_KEYFILE)
2098 if (info->ssl_key_file == NULL) {
2099 ssl_val = NULL;
2100 res = ldap_get_option(NULL, LDAP_OPT_X_TLS_KEYFILE, &ssl_val);
2101 if (res == LDAP_OPT_SUCCESS) {
2102 if (ssl_val != NULL) {
2103 pr_trace_msg(trace_channel, 17,
2104 "using default 'ssl-key' value: %s", ssl_val);
2105 info->ssl_key_file = ldap_strdup(ssl_val);
2106 }
2107 }
2108 }
2109 # endif /* LDAP_OPT_X_TLS_KEYFILE */
2110
2111 # if defined(LDAP_OPT_X_TLS_CIPHER_SUITE)
2112 if (info->ssl_ciphers == NULL) {
2113 ssl_val = NULL;
2114 res = ldap_get_option(NULL, LDAP_OPT_X_TLS_CIPHER_SUITE, &ssl_val);
2115 if (res == LDAP_OPT_SUCCESS) {
2116 if (ssl_val != NULL) {
2117 pr_trace_msg(trace_channel, 17,
2118 "using default 'ssl-ciphers' value: %s", ssl_val);
2119 info->ssl_ciphers = ldap_strdup(ssl_val);
2120 }
2121 }
2122 }
2123 # endif /* LDAP_OPT_X_TLS_CIPHER_SUITE */
2124
2125 # if defined(LDAP_OPT_X_TLS_REQUIRE_CERT)
2126 if (info->ssl_verify == -1) {
2127 res = ldap_get_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &ssl_verify);
2128 if (res == LDAP_OPT_SUCCESS) {
2129 ssl_val = NULL;
2130
2131 switch (ssl_verify) {
2132 # if defined(LDAP_OPT_X_TLS_NEVER)
2133 case LDAP_OPT_X_TLS_NEVER:
2134 ssl_val = "never";
2135 break;
2136 # endif /* LDAP_OPT_X_TLS_NEVER */
2137
2138 # if defined(LDAP_OPT_X_TLS_HARD)
2139 case LDAP_OPT_X_TLS_HARD:
2140 ssl_val = "hard";
2141 break;
2142 # endif /* LDAP_OPT_X_TLS_HARD */
2143
2144 # if defined(LDAP_OPT_X_TLS_DEMAND)
2145 case LDAP_OPT_X_TLS_DEMAND:
2146 ssl_val = "demand";
2147 break;
2148 # endif /* LDAP_OPT_X_TLS_DEMAND */
2149
2150 # if defined(LDAP_OPT_X_TLS_ALLOW)
2151 case LDAP_OPT_X_TLS_ALLOW:
2152 ssl_val = "allow";
2153 break;
2154 # endif /* LDAP_OPT_X_TLS_ALLOW */
2155
2156 # if defined(LDAP_OPT_X_TLS_TRY)
2157 case LDAP_OPT_X_TLS_TRY:
2158 ssl_val = "try";
2159 break;
2160 # endif /* LDAP_OPT_X_TLS_TRY */
2161
2162 default:
2163 ssl_val = NULL;
2164 }
2165
2166 pr_trace_msg(trace_channel, 17,
2167 "using default 'ssl-verify' value: %s", ssl_val ? ssl_val : "UNKNOWN");
2168
2169 info->ssl_verify = ssl_verify;
2170
2171 if (ssl_val != NULL) {
2172 info->ssl_verify_text = ldap_strdup(ssl_val);
2173 }
2174 }
2175 }
2176 # endif /* LDAP_OPT_X_TLS_REQUIRE_CERT */
2177 #endif /* LDAP_OPT_X_TLS */
2178 }
2179
2180 /* Free up any library-allocated memory. */
server_info_free(struct server_info * info)2181 static void server_info_free(struct server_info *info) {
2182 if (info->url_desc != NULL) {
2183 ldap_free_urldesc(info->url_desc);
2184 info->url_desc = NULL;
2185 }
2186
2187 if (info->url_text != NULL) {
2188 ldap_memfree(info->url_text);
2189 info->url_text = NULL;
2190 }
2191
2192 if (info->ssl_ca_file != NULL) {
2193 ldap_memfree((char *) info->ssl_ca_file);
2194 info->ssl_ca_file = NULL;
2195 }
2196
2197 if (info->ssl_cert_file != NULL) {
2198 ldap_memfree((char *) info->ssl_cert_file);
2199 info->ssl_cert_file = NULL;
2200 }
2201
2202 if (info->ssl_key_file != NULL) {
2203 ldap_memfree((char *) info->ssl_key_file);
2204 info->ssl_key_file = NULL;
2205 }
2206
2207 if (info->ssl_ciphers != NULL) {
2208 ldap_memfree((char *) info->ssl_ciphers);
2209 info->ssl_ciphers = NULL;
2210 }
2211
2212 info->ssl_verify = -1;
2213
2214 if (info->ssl_verify_text != NULL) {
2215 ldap_memfree((char *) info->ssl_verify_text);
2216 info->ssl_verify_text = NULL;
2217 }
2218 }
2219
server_infos_free(void)2220 static void server_infos_free(void) {
2221 server_rec *s;
2222
2223 for (s = (server_rec *) server_list->xas_list; s; s = s->next) {
2224 register unsigned int i;
2225 config_rec *c;
2226 array_header *infos;
2227
2228 c = find_config(s->conf, CONF_PARAM, "LDAPServer", FALSE);
2229 if (c == NULL) {
2230 continue;
2231 }
2232
2233 pr_signals_handle();
2234
2235 infos = c->argv[0];
2236 for (i = 0; i < infos->nelts; i++) {
2237 struct server_info *info;
2238
2239 info = ((struct server_info **) infos->elts)[i];
2240 server_info_free(info);
2241 }
2242 }
2243 }
2244
2245 /* Configuration handlers
2246 */
2247
2248 /* usage: LDAPLog path|"none" */
set_ldaplog(cmd_rec * cmd)2249 MODRET set_ldaplog(cmd_rec *cmd) {
2250 CHECK_ARGS(cmd, 1);
2251 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2252
2253 (void) add_config_param_str(cmd->argv[0], 1, cmd->argv[1]);
2254 return PR_HANDLED(cmd);
2255 }
2256
set_ldapprotoversion(cmd_rec * cmd)2257 MODRET set_ldapprotoversion(cmd_rec *cmd) {
2258 int i = 0;
2259 config_rec *c;
2260 char *version;
2261
2262 CHECK_ARGS(cmd, 1);
2263 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2264
2265 version = cmd->argv[1];
2266 while (version[i]) {
2267 if (!PR_ISDIGIT((int) version[i])) {
2268 CONF_ERROR(cmd, "LDAPProtocolVersion: argument must be numeric!");
2269 }
2270
2271 ++i;
2272 }
2273
2274 c = add_config_param(cmd->argv[0], 1, NULL);
2275 c->argv[0] = pcalloc(c->pool, sizeof(int));
2276 *((int *) c->argv[0]) = atoi(version);
2277
2278 return PR_HANDLED(cmd);
2279 }
2280
2281 /* usage: LDAPServer info [ssl-cert:<path>] [ssl-key:<path>] [ssl-ca:<path>]
2282 * [ssl-ciphers:ciphers] [ssl-verify:verify]
2283 */
set_ldapserver(cmd_rec * cmd)2284 MODRET set_ldapserver(cmd_rec *cmd) {
2285 register unsigned int i;
2286 struct server_info *info = NULL;
2287 array_header *infos, *items;
2288 config_rec *c;
2289
2290 if (cmd->argc < 2) {
2291 CONF_ERROR(cmd, "wrong number of parameters");
2292 }
2293 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2294
2295 c = add_config_param(cmd->argv[0], 1, NULL);
2296 infos = make_array(c->pool, cmd->argc - 1, sizeof(struct server_info *));
2297 c->argv[0] = infos;
2298
2299 /* For historical reasons (and leaky abstractions from underlying LDAP
2300 * libraries), the LDAPServer directive supports having multiple hosts/URLs
2301 * being passed as a single string, quoted and separated by whitespace.
2302 * That is not really necessary, but we need to handle such items as well.
2303 *
2304 * Order matters, since the ordering of these hosts/URLs dictates the
2305 * order in which they are tried when attempting to connect.
2306 */
2307
2308 items = make_array(cmd->tmp_pool, cmd->argc - 1, sizeof(char *));
2309 for (i = 1; i < cmd->argc; i++) {
2310 char *item;
2311
2312 item = cmd->argv[i];
2313
2314 /* Split non-URL arguments on whitespace and insert them as separate
2315 * servers.
2316 */
2317 while (*item) {
2318 size_t len;
2319
2320 pr_signals_handle();
2321
2322 len = strcspn(item, " \f\n\r\t\v");
2323 *((char **) push_array(items)) = pstrndup(cmd->tmp_pool, item, len);
2324
2325 item += len;
2326 while (PR_ISSPACE(*item)) {
2327 ++item;
2328 }
2329 }
2330 }
2331
2332 for (i = 0; i < items->nelts; i++) {
2333 char *item;
2334
2335 item = ((char **) items->elts)[i];
2336
2337 /* Is this an SSL option? If so, it needs to be applied to the
2338 * previously defined LDAP URL/host. Otherwise, it's a misconfiguration.
2339 */
2340 if (strncmp(item, "ssl-ca:", 7) == 0) {
2341 char *path;
2342
2343 if (info == NULL) {
2344 CONF_ERROR(cmd, "wrong order of parameters");
2345 }
2346
2347 path = item;
2348
2349 /* Advance past the "ssl-ca:" prefix. */
2350 path += 7;
2351
2352 if (file_exists2(cmd->tmp_pool, path) != TRUE) {
2353 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "SSL CA file '", path, "': ",
2354 strerror(ENOENT), NULL));
2355 }
2356
2357 info->ssl_ca_file = ldap_strdup(path);
2358 continue;
2359
2360 } else if (strncmp(item, "ssl-cert:", 9) == 0) {
2361 char *path;
2362
2363 if (info == NULL) {
2364 CONF_ERROR(cmd, "wrong order of parameters");
2365 }
2366
2367 path = item;
2368
2369 /* Advance past the "ssl-cert:" prefix. */
2370 path += 9;
2371
2372 if (file_exists2(cmd->tmp_pool, path) != TRUE) {
2373 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "SSL certificate file '",
2374 path, "': ", strerror(ENOENT), NULL));
2375 }
2376
2377 info->ssl_cert_file = ldap_strdup(path);
2378 continue;
2379
2380 } else if (strncmp(item, "ssl-key:", 8) == 0) {
2381 char *path;
2382
2383 if (info == NULL) {
2384 CONF_ERROR(cmd, "wrong order of parameters");
2385 }
2386
2387 path = item;
2388
2389 /* Advance past the "ssl-key:" prefix. */
2390 path += 8;
2391
2392 if (file_exists2(cmd->tmp_pool, path) != TRUE) {
2393 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "SSL certificate key file '",
2394 path, "': ", strerror(ENOENT), NULL));
2395 }
2396
2397 info->ssl_key_file = ldap_strdup(path);
2398 continue;
2399
2400 } else if (strncmp(item, "ssl-ciphers:", 12) == 0) {
2401 char *ciphers;
2402
2403 if (info == NULL) {
2404 CONF_ERROR(cmd, "wrong order of parameters");
2405 }
2406
2407 ciphers = item;
2408
2409 /* Advance past the "ssl-ciphers:" prefix. */
2410 ciphers += 12;
2411
2412 info->ssl_ciphers = ldap_strdup(ciphers);
2413 continue;
2414
2415 } else if (strncmp(item, "ssl-verify:", 11) == 0) {
2416 int b, ssl_verify = -1;
2417 char *verify_text;
2418
2419 if (info == NULL) {
2420 CONF_ERROR(cmd, "wrong order of parameters");
2421 }
2422
2423 verify_text = item;
2424
2425 /* Advance past the "ssl-verify:" prefix. */
2426 verify_text += 11;
2427
2428 /* For convenience, we accept the usual on/off values, AND the
2429 * LDAP specific names, for those who think they want the finer
2430 * control.
2431 */
2432
2433 b = pr_str_is_boolean(verify_text);
2434 if (b < 0) {
2435 #if defined(LDAP_OPT_X_TLS_ALLOW)
2436 if (strcasecmp(verify_text, "allow") == 0) {
2437 ssl_verify = LDAP_OPT_X_TLS_ALLOW;
2438 #else
2439 if (FALSE) {
2440 #endif /* LDAP_OPT_X_TLS_ALLOW */
2441
2442 #if defined(LDAP_OPT_X_TLS_DEMAND)
2443 } else if (strcasecmp(verify_text, "demand") == 0) {
2444 ssl_verify = LDAP_OPT_X_TLS_DEMAND;
2445 #endif /* LDAP_OPT_X_TLS_DEMAND */
2446
2447 #if defined(LDAP_OPT_X_TLS_NEVER)
2448 } else if (strcasecmp(verify_text, "never") == 0) {
2449 ssl_verify = LDAP_OPT_X_TLS_NEVER;
2450 #endif /* LDAP_OPT_X_TLS_NEVER */
2451
2452 #if defined(LDAP_OPT_X_TLS_TRY)
2453 } else if (strcasecmp(verify_text, "try") == 0) {
2454 ssl_verify = LDAP_OPT_X_TLS_TRY;
2455 #endif /* LDAP_OPT_X_TLS_TRY */
2456
2457 } else {
2458 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
2459 "unknown/unsupported 'ssl-verify' value: ", verify_text, NULL));
2460 }
2461
2462 } else {
2463 if (b == TRUE) {
2464 #if defined(LDAP_OPT_X_TLS_DEMAND)
2465 ssl_verify = LDAP_OPT_X_TLS_DEMAND;
2466 #endif /* LDAP_OPT_X_TLS_DEMAND */
2467 verify_text = "demand";
2468
2469 } else {
2470 #if defined(LDAP_OPT_X_TLS_NEVER)
2471 ssl_verify = LDAP_OPT_X_TLS_NEVER;
2472 #endif /* LDAP_OPT_X_TLS_NEVER */
2473 verify_text = "never";
2474 }
2475 }
2476
2477 info->ssl_verify = ssl_verify;
2478 info->ssl_verify_text = ldap_strdup(verify_text);
2479 continue;
2480
2481 } else {
2482 info = server_info_create(c->pool);
2483 }
2484
2485 info->info_text = pstrdup(c->pool, item);
2486
2487 if (ldap_is_ldap_url(item)) {
2488 int res;
2489 LDAPURLDesc *url_desc;
2490 char *url_text;
2491
2492 res = ldap_url_parse(item, &url_desc);
2493 if (res != LDAP_URL_SUCCESS) {
2494 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
2495 "invalid LDAP URL '", item, "': ", ldap_err2string(res), NULL));
2496 }
2497
2498 info->url_desc = url_desc;
2499
2500 url_text = ldap_url_desc2str(url_desc);
2501 if (url_text != NULL) {
2502 pr_log_debug(DEBUG0, "%s: parsed URL '%s' as '%s'",
2503 (char *) cmd->argv[0], item, url_text);
2504 info->url_text = url_text;
2505 }
2506
2507 #ifdef HAS_LDAP_INITIALIZE
2508 if (strcasecmp(url_desc->lud_scheme, "ldap") != 0 &&
2509 strcasecmp(url_desc->lud_scheme, "ldaps") != 0) {
2510 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "invalid scheme specified by URL '", item, "': valid schemes are 'ldap' or 'ldaps'", NULL));
2511 }
2512 #else /* HAS_LDAP_INITIALIZE */
2513 if (strcasecmp(url_desc->lud_scheme, "ldap") != 0) {
2514 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unsupported scheme specified by URL '", item, "': valid scheme is only 'ldap'", NULL));
2515 }
2516 #endif /* HAS_LDAP_INITIALIZE */
2517
2518 if (url_desc->lud_dn != NULL &&
2519 strcmp(url_desc->lud_dn, "") != 0) {
2520 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, item, ": a base DN may not be specified by an LDAPServer URL, only by LDAPUsers or LDAPGroups", NULL));
2521 }
2522
2523 if (url_desc->lud_filter != NULL &&
2524 strcmp(url_desc->lud_filter, "") != 0) {
2525 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, item, ": a search filter may not be specified by an LDAPServer URL, only by LDAPUsers or LDAPGroups", NULL));
2526 }
2527
2528 if (url_desc->lud_scope == LDAP_SCOPE_BASE) {
2529 pr_log_debug(DEBUG0, MOD_LDAP_VERSION
2530 ": WARNING: '%s': LDAP URL search scopes default to 'base', "
2531 "not 'subtree', and may not be what you want (see LDAPSearchScope)",
2532 item);
2533 }
2534
2535 /* Need to keep parsed host and port for pre-2000 ldap_init(3). */
2536 if (url_desc->lud_host != NULL) {
2537 info->host = pstrdup(c->pool, url_desc->lud_host);
2538 }
2539
2540 if (url_desc->lud_port != 0) {
2541 info->port = url_desc->lud_port;
2542 }
2543
2544 } else {
2545 char *ptr;
2546
2547 /* The given item is just a hostname/IP address, maybe a port. */
2548 ptr = strchr(item, ':');
2549 if (ptr == NULL) {
2550 info->host = pstrdup(c->pool, item);
2551 info->port = LDAP_PORT;
2552
2553 } else {
2554 int port;
2555
2556 info->host = pstrndup(c->pool, item, ptr - item);
2557
2558 port = atoi(ptr + 1);
2559 if (port == 0) {
2560 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unable to parse '", ptr + 1,
2561 "' as a port number for '", item, "'", NULL));
2562 }
2563
2564 info->port = port;
2565 info->port_text = pstrdup(c->pool, ptr + 1);
2566 }
2567 }
2568
2569 *((struct server_info **) push_array(infos)) = info;
2570 }
2571
2572 return PR_HANDLED(cmd);
2573 }
2574
2575 /* usage: LDAPUseSASL mech1 ... */
2576 MODRET set_ldapusesasl(cmd_rec *cmd) {
2577 #if defined(HAVE_SASL_SASL_H)
2578 register unsigned int i;
2579 config_rec *c;
2580 char *sasl_mechs = "";
2581
2582 if (cmd->argc < 1) {
2583 CONF_ERROR(cmd, "wrong number of parameters");
2584 }
2585
2586 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2587
2588 c = add_config_param(cmd->argv[0], 1, NULL);
2589
2590 for (i = 1; i < cmd->argc; i++) {
2591 register unsigned int j;
2592 char *sasl_mech;
2593
2594 /* Only allow known supported (and tested) mechanisms for now. */
2595 if (strcasecmp(cmd->argv[i], "ANONYMOUS") == 0 ||
2596 strcasecmp(cmd->argv[i], "CRAM-MD5") == 0 ||
2597 strcasecmp(cmd->argv[i], "DIGEST-MD5") == 0 ||
2598 strcasecmp(cmd->argv[i], "PLAIN") == 0 ||
2599 strcasecmp(cmd->argv[i], "LOGIN") == 0 ||
2600 strncasecmp(cmd->argv[i], "SCRAM-SHA-", 10) == 0) {
2601 sasl_mech = cmd->argv[i];
2602
2603 } else {
2604 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unsupported SASL mechanism: ",
2605 cmd->argv[i], NULL));
2606 }
2607
2608 /* Convert the mechanism name to all uppercase, per convention. */
2609 for (j = 0; j < strlen(sasl_mech); j++) {
2610 sasl_mech[j] = toupper(sasl_mech[j]);
2611 }
2612
2613 sasl_mechs = pstrcat(c->pool, sasl_mechs, *sasl_mechs ? " " : "",
2614 sasl_mech, NULL);
2615 }
2616
2617 c->argv[0] = sasl_mechs;
2618 return PR_HANDLED(cmd);
2619 #else
2620 CONF_ERROR(cmd, "Your system libraries do not appear to support SASL (missing <sasl/sasl.h>)");
2621 #endif /* HAVE_SASL_SASL_H */
2622 }
2623
2624 /* usage: LDAPUseTLS on|off */
2625 MODRET set_ldapusetls(cmd_rec *cmd) {
2626 #if defined(LDAP_OPT_X_TLS)
2627 int use_tls;
2628 config_rec *c;
2629
2630 CHECK_ARGS(cmd, 1);
2631 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2632
2633 use_tls = get_boolean(cmd, 1);
2634 if (use_tls == -1) {
2635 CONF_ERROR(cmd, "expected Boolean parameter");
2636 }
2637
2638 c = add_config_param(cmd->argv[0], 1, NULL);
2639 c->argv[0] = pcalloc(c->pool, sizeof(int));
2640 *((int *) c->argv[0]) = use_tls;
2641
2642 return PR_HANDLED(cmd);
2643
2644 #else /* LDAP_OPT_X_TLS */
2645 CONF_ERROR(cmd, "Your LDAP libraries do not appear to support TLS");
2646 #endif /* LDAP_OPT_X_TLS */
2647 }
2648
2649 MODRET set_ldapbinddn(cmd_rec *cmd) {
2650 CHECK_ARGS(cmd, 1);
2651 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2652
2653 add_config_param_str(cmd->argv[0], 2, cmd->argv[1], cmd->argv[2]);
2654 return PR_HANDLED(cmd);
2655 }
2656
2657 MODRET set_ldapsearchscope(cmd_rec *cmd) {
2658 config_rec *c;
2659 const char *scope_name;
2660 int search_scope;
2661
2662 CHECK_ARGS(cmd, 1);
2663 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2664
2665 scope_name = cmd->argv[1];
2666
2667 if (strcasecmp(scope_name, "base") == 0) {
2668 search_scope = LDAP_SCOPE_BASE;
2669
2670 } else if (strcasecmp(scope_name, "one") == 0 ||
2671 strcasecmp(scope_name, "onelevel") == 0) {
2672 search_scope = LDAP_SCOPE_ONELEVEL;
2673
2674 } else if (strcasecmp(scope_name, "sub") == 0 ||
2675 strcasecmp(scope_name, "subtree") == 0) {
2676 search_scope = LDAP_SCOPE_SUBTREE;
2677
2678 } else {
2679 CONF_ERROR(cmd, "search scope must be one of: base, onelevel, subtree");
2680 }
2681
2682 c = add_config_param(cmd->argv[0], 1, NULL);
2683 c->argv[0] = palloc(c->pool, sizeof(int));
2684 *((int *) c->argv[0]) = search_scope;
2685
2686 return PR_HANDLED(cmd);
2687 }
2688
2689 MODRET set_ldapquerytimeout(cmd_rec *cmd) {
2690 config_rec *c;
2691 int timeout;
2692
2693 CHECK_ARGS(cmd, 1);
2694 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2695
2696 if (pr_str_get_duration(cmd->argv[1], &timeout) < 0) {
2697 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "error parsing timeout value '",
2698 cmd->argv[1], "': ", strerror(errno), NULL));
2699 }
2700
2701 c = add_config_param(cmd->argv[0], 1, NULL);
2702 c->argv[0] = pcalloc(c->pool, sizeof(int));
2703 *((int *) c->argv[0]) = timeout;
2704
2705 return PR_HANDLED(cmd);
2706 }
2707
2708 MODRET set_ldapaliasdereference(cmd_rec *cmd) {
2709 int value;
2710 config_rec *c;
2711
2712 CHECK_ARGS(cmd, 1);
2713 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2714
2715 if (strcasecmp(cmd->argv[1], "never") == 0) {
2716 value = LDAP_DEREF_NEVER;
2717
2718 } else if (strcasecmp(cmd->argv[1], "search") == 0) {
2719 value = LDAP_DEREF_SEARCHING;
2720
2721 } else if (strcasecmp(cmd->argv[1], "find") == 0) {
2722 value = LDAP_DEREF_FINDING;
2723
2724 } else if (strcasecmp(cmd->argv[1], "always") == 0) {
2725 value = LDAP_DEREF_ALWAYS;
2726
2727 } else {
2728 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
2729 "expected a valid dereference (never, search, find, always): ",
2730 cmd->argv[1], NULL));
2731 }
2732
2733 c = add_config_param(cmd->argv[0], 1, NULL);
2734 c->argv[0] = pcalloc(c->pool, sizeof(int));
2735 *((int *) c->argv[0]) = value;
2736
2737 return PR_HANDLED(cmd);
2738 }
2739
2740 MODRET set_ldapauthbinds(cmd_rec *cmd) {
2741 int b;
2742 config_rec *c;
2743
2744 CHECK_ARGS(cmd, 1);
2745 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2746
2747 b = get_boolean(cmd, 1);
2748 if (b == -1) {
2749 CONF_ERROR(cmd, "expected Boolean parameter");
2750 }
2751
2752 c = add_config_param(cmd->argv[0], 1, NULL);
2753 c->argv[0] = pcalloc(c->pool, sizeof(int));
2754 *((int *) c->argv[0]) = b;
2755
2756 return PR_HANDLED(cmd);
2757 }
2758
2759 MODRET set_ldapdefaultauthscheme(cmd_rec *cmd) {
2760 CHECK_ARGS(cmd, 1);
2761 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2762
2763 add_config_param_str(cmd->argv[0], 1, cmd->argv[1]);
2764 return PR_HANDLED(cmd);
2765 }
2766
2767 MODRET set_ldapattr(cmd_rec *cmd) {
2768 CHECK_ARGS(cmd, 2);
2769 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2770
2771 if (strcasecmp(cmd->argv[1], "uid") != 0 &&
2772 strcasecmp(cmd->argv[1], "uidNumber") != 0 &&
2773 strcasecmp(cmd->argv[1], "gidNumber") != 0 &&
2774 strcasecmp(cmd->argv[1], "homeDirectory") != 0 &&
2775 strcasecmp(cmd->argv[1], "userPassword") != 0 &&
2776 strcasecmp(cmd->argv[1], "loginShell") != 0 &&
2777 strcasecmp(cmd->argv[1], "cn") != 0 &&
2778 strcasecmp(cmd->argv[1], "memberUid") != 0 &&
2779 strcasecmp(cmd->argv[1], "ftpQuota") != 0 &&
2780 strcasecmp(cmd->argv[1], "ftpQuotaProfileDN") != 0) {
2781 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool,
2782 ": unknown attribute name: ", cmd->argv[1], NULL));
2783 }
2784
2785 add_config_param_str(cmd->argv[0], 2, cmd->argv[1], cmd->argv[2]);
2786 return PR_HANDLED(cmd);
2787 }
2788
2789 /* usage: LDAPUsers base-dn [name-filter-template [uid-filter-template]] */
2790 MODRET set_ldapusers(cmd_rec *cmd) {
2791 config_rec *c;
2792
2793 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2794
2795 if (get_boolean(cmd, 1) != -1) {
2796 CONF_ERROR(cmd, "first parameter must be the base DN, not on/off");
2797 }
2798
2799 c = add_config_param(cmd->argv[0], cmd->argc - 1, NULL, NULL, NULL);
2800 c->argv[0] = pstrdup(c->pool, cmd->argv[1]);
2801 if (cmd->argc > 2) {
2802 c->argv[1] = pstrdup(c->pool, cmd->argv[2]);
2803 }
2804 if (cmd->argc > 3) {
2805 c->argv[2] = pstrdup(c->pool, cmd->argv[3]);
2806 }
2807
2808 return PR_HANDLED(cmd);
2809 }
2810
2811 MODRET set_ldapdefaultuid(cmd_rec *cmd) {
2812 config_rec *c;
2813 uid_t uid;
2814
2815 CHECK_ARGS(cmd, 1);
2816 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2817
2818 c = add_config_param(cmd->argv[0], 1, NULL);
2819 c->argv[0] = pcalloc(c->pool, sizeof(uid_t));
2820
2821 if (pr_str2uid(cmd->argv[1], &uid) < 0) {
2822 CONF_ERROR(cmd, "LDAPDefaultUID: UID argument must be numeric");
2823 }
2824
2825 *((uid_t *) c->argv[0]) = uid;
2826 return PR_HANDLED(cmd);
2827 }
2828
2829 MODRET set_ldapdefaultgid(cmd_rec *cmd) {
2830 config_rec *c;
2831 gid_t gid;
2832
2833 CHECK_ARGS(cmd, 1);
2834 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2835
2836 c = add_config_param(cmd->argv[0], 1, NULL);
2837 c->argv[0] = pcalloc(c->pool, sizeof(gid_t));
2838
2839 if (pr_str2gid(cmd->argv[1], &gid) < 0) {
2840 CONF_ERROR(cmd, "LDAPDefaultGID: GID argument must be numeric");
2841 }
2842
2843 *((gid_t *) c->argv[0]) = gid;
2844 return PR_HANDLED(cmd);
2845 }
2846
2847 MODRET set_ldapforcedefaultuid(cmd_rec *cmd) {
2848 int b;
2849 config_rec *c;
2850
2851 CHECK_CONF(cmd,CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2852
2853 b = get_boolean(cmd, 1);
2854 if (b == -1) {
2855 CONF_ERROR(cmd, "expected Boolean parameter");
2856 }
2857
2858 c = add_config_param(cmd->argv[0], 1, NULL);
2859 c->argv[0] = pcalloc(c->pool, sizeof(int));
2860 *((int *) c->argv[0]) = b;
2861
2862 return PR_HANDLED(cmd);
2863 }
2864
2865 MODRET set_ldapforcedefaultgid(cmd_rec *cmd) {
2866 int b;
2867 config_rec *c;
2868
2869 CHECK_CONF(cmd,CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2870
2871 b = get_boolean(cmd, 1);
2872 if (b == -1) {
2873 CONF_ERROR(cmd, "expected Boolean parameter");
2874 }
2875
2876 c = add_config_param(cmd->argv[0], 1, NULL);
2877 c->argv[0] = pcalloc(c->pool, sizeof(int));
2878 *((int *) c->argv[0]) = b;
2879
2880 return PR_HANDLED(cmd);
2881 }
2882
2883 MODRET set_ldapgenhdir(cmd_rec *cmd) {
2884 int b;
2885 config_rec *c;
2886
2887 CHECK_ARGS(cmd, 1);
2888 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2889
2890 b = get_boolean(cmd, 1);
2891 if (b == -1) {
2892 CONF_ERROR(cmd, "expected Boolean parameter");
2893 }
2894
2895 c = add_config_param(cmd->argv[0], 1, NULL);
2896 c->argv[0] = pcalloc(c->pool, sizeof(int));
2897 *((int *) c->argv[0]) = b;
2898
2899 return PR_HANDLED(cmd);
2900 }
2901
2902 MODRET set_ldapgenhdirprefix(cmd_rec *cmd) {
2903 char *prefix;
2904
2905 CHECK_ARGS(cmd, 1);
2906 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2907
2908 prefix = cmd->argv[1];
2909 if (strlen(prefix) == 0) {
2910 CONF_ERROR(cmd, "must not be an empty string");
2911 }
2912
2913 add_config_param_str(cmd->argv[0], 1, prefix);
2914 return PR_HANDLED(cmd);
2915 }
2916
2917 MODRET set_ldapgenhdirprefixnouname(cmd_rec *cmd) {
2918 int b;
2919 config_rec *c;
2920
2921 CHECK_ARGS(cmd, 1);
2922 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2923
2924 b = get_boolean(cmd, 1);
2925 if (b == -1) {
2926 CONF_ERROR(cmd, "expected Boolean parameter");
2927 }
2928
2929 c = add_config_param(cmd->argv[0], 1, NULL);
2930 c->argv[0] = pcalloc(c->pool, sizeof(int));
2931 *((int *) c->argv[0]) = b;
2932
2933 return PR_HANDLED(cmd);
2934 }
2935
2936 MODRET set_ldapforcegenhdir(cmd_rec *cmd) {
2937 int b;
2938 config_rec *c;
2939
2940 CHECK_ARGS(cmd, 1);
2941 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2942
2943 b = get_boolean(cmd, 1);
2944 if (b == -1) {
2945 CONF_ERROR(cmd, "expected Boolean parameter");
2946 }
2947
2948 c = add_config_param(cmd->argv[0], 1, NULL);
2949 c->argv[0] = pcalloc(c->pool, sizeof(int));
2950 *((int *) c->argv[0]) = b;
2951
2952 return PR_HANDLED(cmd);
2953 }
2954
2955 MODRET set_ldapgrouplookups(cmd_rec *cmd) {
2956 config_rec *c;
2957
2958 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2959
2960 if (get_boolean(cmd, 1) != -1) {
2961 CONF_ERROR(cmd, "first parameter must be the base DN, not on/off.");
2962 }
2963
2964 c = add_config_param(cmd->argv[0], cmd->argc - 1, NULL);
2965 c->argv[0] = pstrdup(c->pool, cmd->argv[1]);
2966 if (cmd->argc > 2) {
2967 c->argv[1] = pstrdup(c->pool, cmd->argv[2]);
2968 }
2969
2970 if (cmd->argc > 3) {
2971 c->argv[2] = pstrdup(c->pool, cmd->argv[3]);
2972 }
2973
2974 if (cmd->argc > 4) {
2975 c->argv[3] = pstrdup(c->pool, cmd->argv[4]);
2976 }
2977
2978 return PR_HANDLED(cmd);
2979 }
2980
2981 MODRET set_ldapdefaultquota(cmd_rec *cmd) {
2982 CHECK_ARGS(cmd, 1);
2983 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
2984
2985 add_config_param_str(cmd->argv[0], 1, cmd->argv[1]);
2986 return PR_HANDLED(cmd);
2987 }
2988
2989 /* Event listeners
2990 */
2991
2992 #if defined(PR_SHARED_MODULE)
2993 static void ldap_mod_unload_ev(const void *event_data, void *user_data) {
2994 if (strcmp("mod_ldap.c", (const char *) event_data) != 0) {
2995 return;
2996 }
2997
2998 pr_event_unregister(&ldap_module, NULL, NULL);
2999 server_infos_free();
3000 }
3001 #endif /* PR_SHARED_MODULE */
3002
3003 static void ldap_postparse_ev(const void *event_data, void *user_data) {
3004 server_rec *s = NULL;
3005
3006 /* Check the configured LDAPServer directives. Specifically, if the URL
3007 * syntax has been used, we look for any LDAPSearchScope directive and
3008 * warn that they are ignored. Similarly, if there are "ldaps" URLs,
3009 * we warn that any LDAPUseTLS directive will be ignored. Otherwise,
3010 * cases where LDAP URLs have not been used, we construct them.
3011 */
3012 for (s = (server_rec *) server_list->xas_list; s; s = s->next) {
3013 register unsigned int i;
3014 config_rec *c;
3015 array_header *infos;
3016 int search_scope = -1, use_tls = -1;
3017
3018 pr_signals_handle();
3019
3020 c = find_config(s->conf, CONF_PARAM, "LDAPSearchScope", FALSE);
3021 if (c != NULL) {
3022 search_scope = *((int *) c->argv[0]);
3023
3024 } else {
3025 /* Per documentation, the default search scope is "subtree". */
3026 search_scope = LDAP_SCOPE_SUBTREE;
3027 }
3028
3029 #if defined(LDAP_OPT_X_TLS)
3030 c = find_config(s->conf, CONF_PARAM, "LDAPUseTLS", FALSE);
3031 if (c != NULL) {
3032 use_tls = *((int *) c->argv[0]);
3033 }
3034 #endif /* LDAP_OPT_X_TLS */
3035
3036 c = find_config(s->conf, CONF_PARAM, "LDAPServer", FALSE);
3037 if (c == NULL) {
3038 continue;
3039 }
3040
3041 infos = c->argv[0];
3042
3043 for (i = 0; i < infos->nelts; i++) {
3044 struct server_info *info;
3045
3046 info = ((struct server_info **) infos->elts)[i];
3047
3048 if (info->url_desc != NULL) {
3049 if (info->url_desc->lud_scope != search_scope) {
3050 /* When LDAP URLs are used, the search scope is part of the URL
3051 * syntax, which takes precedence over LDAPSearchScope.
3052 */
3053 pr_log_debug(DEBUG2, MOD_LDAP_VERSION
3054 ": ignoring configured LDAPSearchScope for LDAP URL '%s'",
3055 info->info_text);
3056 }
3057
3058 /* If the scheme is "ldaps", AND LDAPUseTLS has been explicitly
3059 * configured, warn that it will be ignored.
3060 */
3061 if (use_tls != -1) {
3062 if (strcasecmp(info->url_desc->lud_scheme, "ldaps") == 0) {
3063 pr_log_debug(DEBUG2, MOD_LDAP_VERSION
3064 ": ignoring configured LDAPUseTLS for explicit LDAPS URL '%s'",
3065 info->info_text);
3066 } else {
3067 info->use_starttls = use_tls;
3068 }
3069 }
3070
3071 } else {
3072 int res;
3073 char *url, *url_text;
3074 LDAPURLDesc *url_desc;
3075
3076 /* Construct an LDAP URL, and parse it. */
3077
3078 url = pstrcat(c->pool, "ldap://", info->host, NULL);
3079 if (info->port_text != NULL) {
3080 url = pstrcat(c->pool, url, ":", info->port_text, NULL);
3081 }
3082
3083 switch (search_scope) {
3084 case LDAP_SCOPE_SUBTREE:
3085 url = pstrcat(c->pool, url, "/??sub", NULL);
3086 break;
3087
3088 case LDAP_SCOPE_BASE:
3089 url = pstrcat(c->pool, url, "/??base", NULL);
3090 break;
3091
3092 case LDAP_SCOPE_ONELEVEL:
3093 url = pstrcat(c->pool, url, "/??one", NULL);
3094 break;
3095
3096 default:
3097 break;
3098 }
3099
3100 res = ldap_url_parse(url, &url_desc);
3101 if (res != LDAP_URL_SUCCESS) {
3102 /* This should only happen as a result of a coding bug. */
3103 pr_log_pri(PR_LOG_NOTICE, MOD_LDAP_VERSION
3104 ": invalid LDAP URL '%s': %s", url, ldap_err2string(res));
3105 pr_session_disconnect(&ldap_module, PR_SESS_DISCONNECT_BAD_CONFIG,
3106 NULL);
3107 }
3108
3109 info->url_desc = url_desc;
3110 info->port = url_desc->lud_port;
3111
3112 url_text = ldap_url_desc2str(url_desc);
3113 if (url_text != NULL) {
3114 pr_log_debug(DEBUG0, "%s: parsed URL '%s' as '%s'", c->name, url,
3115 url_text);
3116 info->url_text = url_text;
3117 }
3118
3119 if (use_tls != -1) {
3120 info->use_starttls = use_tls;
3121 }
3122 }
3123
3124 server_info_get_ssl_defaults(info);
3125 }
3126 }
3127 }
3128
3129 static void ldap_sess_reinit_ev(const void *event_data, void *user_data) {
3130 int res;
3131
3132 /* A HOST command changed the main_server pointer; reinitialize ourselves. */
3133
3134 pr_event_unregister(&ldap_module, "core.session-reinit", ldap_sess_reinit_ev);
3135
3136 /* Restore defaults. */
3137 (void) close(ldap_logfd);
3138 ldap_logfd = -1;
3139 ldap_protocol_version = 3;
3140 ldap_servers = NULL;
3141 ldap_dn = NULL;
3142 ldap_dnpass = NULL;
3143 ldap_dnpasslen = 0;
3144 ldap_search_scope = LDAP_SCOPE_SUBTREE;
3145 ldap_sasl_mechs = NULL;
3146 ldap_querytimeout = 0;
3147 ldap_dereference = LDAP_DEREF_NEVER;
3148 ldap_authbinds = TRUE;
3149 ldap_defaultauthscheme = "crypt";
3150 ldap_attr_uid = "uid";
3151 ldap_attr_uidnumber = "uidNumber";
3152 ldap_attr_gidnumber = "gidNumber";
3153 ldap_attr_homedirectory = "homeDirectory";
3154 ldap_attr_userpassword = "userPassword";
3155 ldap_attr_loginshell = "loginShell";
3156 ldap_attr_cn = "cn";
3157 ldap_attr_memberuid = "memberUid";
3158 ldap_attr_ftpquota = "ftpQuota";
3159 ldap_attr_ftpquota_profiledn = "ftpQuotaProfileDN";
3160 ldap_do_users = FALSE;
3161 ldap_user_basedn = NULL;
3162 ldap_user_name_filter = NULL;
3163 ldap_user_uid_filter = NULL;
3164 ldap_do_groups = FALSE;
3165 ldap_group_name_filter = NULL;
3166 ldap_group_gid_filter = NULL;
3167 ldap_group_member_filter = NULL;
3168 ldap_default_quota = NULL;
3169 ldap_defaultuid = (uid_t) -1;
3170 ldap_defaultgid = (gid_t) -1;
3171 ldap_forcedefaultuid = FALSE;
3172 ldap_forcedefaultgid = FALSE;
3173 ldap_forcegenhdir = FALSE;
3174 ldap_genhdir = FALSE;
3175 ldap_genhdir_prefix = NULL;
3176 ldap_genhdir_prefix_nouname = FALSE;
3177
3178 curr_server_info = NULL;
3179 curr_server_index = 0;
3180
3181 destroy_pool(ldap_pool);
3182 ldap_pool = NULL;
3183
3184 res = ldap_sess_init();
3185 if (res < 0) {
3186 pr_session_disconnect(&ldap_module, PR_SESS_DISCONNECT_SESSION_INIT_FAILED,
3187 NULL);
3188 }
3189 }
3190
3191 static void ldap_shutdown_ev(const void *event_data, void *user_data) {
3192 server_infos_free();
3193 }
3194
3195 /* Initialization routines
3196 */
3197
3198 static int ldap_mod_init(void) {
3199 pr_log_debug(DEBUG2, MOD_LDAP_VERSION
3200 ": compiled using LDAP vendor '%s', LDAP API version %lu",
3201 LDAP_VENDOR_NAME, (unsigned long) LDAP_API_VERSION);
3202
3203 #if defined(LDAP_OPT_API_INFO)
3204 {
3205 int res;
3206 LDAPAPIInfo api_info;
3207
3208 api_info.ldapai_info_version = LDAP_API_INFO_VERSION;
3209 res = ldap_get_option(NULL, LDAP_OPT_API_INFO, &api_info);
3210 if (res == LDAP_OPT_SUCCESS) {
3211 pool *tmp_pool;
3212 char *feats = "";
3213
3214 tmp_pool = make_sub_pool(permanent_pool);
3215
3216 if (api_info.ldapai_extensions != NULL) {
3217 register unsigned int i;
3218
3219 for (i = 0; api_info.ldapai_extensions[i]; i++) {
3220 feats = pstrcat(tmp_pool, feats, i != 0 ? ", " : "",
3221 api_info.ldapai_extensions[i], NULL);
3222 ldap_memfree(api_info.ldapai_extensions[i]);
3223 }
3224
3225 ldap_memfree(api_info.ldapai_extensions);
3226 }
3227
3228 pr_log_debug(DEBUG10, MOD_LDAP_VERSION
3229 " linked with LDAP vendor '%s' (LDAP API version %d, "
3230 "vendor version %d), features: %s", api_info.ldapai_vendor_name,
3231 api_info.ldapai_api_version, api_info.ldapai_vendor_version,
3232 feats);
3233 ldap_memfree(api_info.ldapai_vendor_name);
3234 destroy_pool(tmp_pool);
3235
3236 } else {
3237 pr_trace_msg(trace_channel, 3,
3238 "error retrieving LDAP_OPT_API_INFO: %s", ldap_err2string(res));
3239 }
3240 }
3241 #endif /* LDAP_OPT_API_INFO */
3242
3243 #if defined(LDAP_OPT_X_TLS_PACKAGE)
3244 {
3245 int res;
3246 char *tls_package = NULL;
3247
3248 res = ldap_get_option(NULL, LDAP_OPT_X_TLS_PACKAGE, &tls_package);
3249 if (res == LDAP_OPT_SUCCESS) {
3250 pr_log_debug(DEBUG10, MOD_LDAP_VERSION
3251 ": LDAP TLS package = %s", tls_package);
3252
3253 } else {
3254 pr_trace_msg(trace_channel, 3,
3255 "error retrieving LDAP_OPT_X_TLS_PACKAGE: %s", ldap_err2string(res));
3256 }
3257 }
3258 #endif /* LDAP_OPT_X_TLS_PACKAGE */
3259
3260 #if defined(PR_SHARED_MODULE)
3261 pr_event_register(&ldap_module, "core.module-unload", ldap_mod_unload_ev,
3262 NULL);
3263 #endif /* PR_SHARED_MODULE */
3264 pr_event_register(&ldap_module, "core.postparse", ldap_postparse_ev, NULL);
3265 pr_event_register(&ldap_module, "core.shutdown", ldap_shutdown_ev, NULL);
3266
3267 return 0;
3268 }
3269
3270 static int ldap_sess_init(void) {
3271 config_rec *c;
3272 void *ptr;
3273
3274 pr_event_register(&ldap_module, "core.session-reinit", ldap_sess_reinit_ev,
3275 NULL);
3276
3277 ldap_pool = make_sub_pool(session.pool);
3278 pr_pool_tag(ldap_pool, MOD_LDAP_VERSION);
3279
3280 c = find_config(main_server->conf, CONF_PARAM, "LDAPLog", FALSE);
3281 if (c != NULL) {
3282 char *path;
3283
3284 path = c->argv[0];
3285
3286 if (strncasecmp(path, "none", 5) != 0) {
3287 int res, xerrno = 0;
3288
3289 pr_signals_block();
3290 PRIVS_ROOT
3291 res = pr_log_openfile(path, &ldap_logfd, PR_LOG_SYSTEM_MODE);
3292 xerrno = errno;
3293 PRIVS_RELINQUISH
3294 pr_signals_unblock();
3295
3296 if (res < 0) {
3297 if (res == -1) {
3298 pr_log_pri(PR_LOG_NOTICE, MOD_LDAP_VERSION
3299 ": notice: unable to open LDAPLog '%s': %s", path,
3300 strerror(xerrno));
3301
3302 } else if (res == PR_LOG_WRITABLE_DIR) {
3303 pr_log_pri(PR_LOG_WARNING, MOD_LDAP_VERSION
3304 ": notice: unable to open LDAPPLog '%s': parent directory is "
3305 "world-writable", path);
3306
3307 } else if (res == PR_LOG_SYMLINK) {
3308 pr_log_pri(PR_LOG_WARNING, MOD_LDAP_VERSION
3309 ": notice: unable to open LDAPLog '%s': cannot log to a symlink",
3310 path);
3311 }
3312 }
3313 }
3314 }
3315
3316 ptr = get_param_ptr(main_server->conf, "LDAPProtocolVersion", FALSE);
3317 if (ptr != NULL) {
3318 ldap_protocol_version = *((int *) ptr);
3319 }
3320
3321 /* Allow for multiple LDAPServer directives. */
3322 c = find_config(main_server->conf, CONF_PARAM, "LDAPServer", FALSE);
3323 while (c != NULL) {
3324 pr_signals_handle();
3325
3326 if (ldap_servers != NULL) {
3327 array_cat(ldap_servers, c->argv[0]);
3328
3329 } else {
3330 ldap_servers = c->argv[0];
3331 }
3332
3333 c = find_config_next(c, c->next, CONF_PARAM, "LDAPServer", FALSE);
3334 }
3335
3336 if (ldap_servers == NULL) {
3337 pr_log_pri(PR_LOG_NOTICE, MOD_LDAP_VERSION
3338 ": no LDAPServer configured, using LDAP library defaults");
3339 }
3340
3341 c = find_config(main_server->conf, CONF_PARAM, "LDAPBindDN", FALSE);
3342 if (c != NULL) {
3343 ldap_dn = pstrdup(ldap_pool, c->argv[0]);
3344 ldap_dnpass = pstrdup(ldap_pool, c->argv[1]);
3345 ldap_dnpasslen = strlen(ldap_dnpass);
3346 }
3347
3348 c = find_config(main_server->conf, CONF_PARAM, "LDAPSearchScope", FALSE);
3349 if (c != NULL) {
3350 ldap_search_scope = *((int *) c->argv[0]);
3351 }
3352
3353 ptr = get_param_ptr(main_server->conf, "LDAPQueryTimeout", FALSE);
3354 if (ptr != NULL) {
3355 ldap_querytimeout = *((int *) ptr);
3356 }
3357
3358 ptr = get_param_ptr(main_server->conf, "LDAPAliasDereference", FALSE);
3359 if (ptr != NULL) {
3360 ldap_dereference = *((int *) ptr);
3361 }
3362
3363 ptr = get_param_ptr(main_server->conf, "LDAPAuthBinds", FALSE);
3364 if (ptr != NULL) {
3365 ldap_authbinds = *((int *) ptr);
3366 }
3367
3368 ptr = get_param_ptr(main_server->conf, "LDAPDefaultAuthScheme", FALSE);
3369 if (ptr != NULL) {
3370 ldap_defaultauthscheme = (char *) ptr;
3371 }
3372
3373 /* Look up any attr redefinitions (LDAPAttr) before using those
3374 * variables, such as when generating the default search filters.
3375 */
3376 c = find_config(main_server->conf, CONF_PARAM, "LDAPAttr", FALSE);
3377 if (c != NULL) {
3378 do {
3379 if (strcasecmp(c->argv[0], "uid") == 0) {
3380 ldap_attr_uid = pstrdup(ldap_pool, c->argv[1]);
3381
3382 } else if (strcasecmp(c->argv[0], "uidNumber") == 0) {
3383 ldap_attr_uidnumber = pstrdup(ldap_pool, c->argv[1]);
3384
3385 } else if (strcasecmp(c->argv[0], "gidNumber") == 0) {
3386 ldap_attr_gidnumber = pstrdup(ldap_pool, c->argv[1]);
3387
3388 } else if (strcasecmp(c->argv[0], "homeDirectory") == 0) {
3389 ldap_attr_homedirectory = pstrdup(ldap_pool, c->argv[1]);
3390
3391 } else if (strcasecmp(c->argv[0], "userPassword") == 0) {
3392 ldap_attr_userpassword = pstrdup(ldap_pool, c->argv[1]);
3393
3394 } else if (strcasecmp(c->argv[0], "loginShell") == 0) {
3395 ldap_attr_loginshell = pstrdup(ldap_pool, c->argv[1]);
3396
3397 } else if (strcasecmp(c->argv[0], "cn") == 0) {
3398 ldap_attr_cn = pstrdup(ldap_pool, c->argv[1]);
3399
3400 } else if (strcasecmp(c->argv[0], "memberUid") == 0) {
3401 ldap_attr_memberuid = pstrdup(ldap_pool, c->argv[1]);
3402
3403 } else if (strcasecmp(c->argv[0], "ftpQuota") == 0) {
3404 ldap_attr_ftpquota = pstrdup(ldap_pool, c->argv[1]);
3405
3406 } else if (strcasecmp(c->argv[0], "ftpQuotaProfileDN") == 0) {
3407 ldap_attr_ftpquota_profiledn = pstrdup(ldap_pool, c->argv[1]);
3408 }
3409
3410 } while ((c = find_config_next(c, c->next, CONF_PARAM, "LDAPAttr", FALSE)));
3411 }
3412
3413 c = find_config(main_server->conf, CONF_PARAM, "LDAPUsers", FALSE);
3414 if (c != NULL) {
3415 ldap_do_users = TRUE;
3416 ldap_user_basedn = pstrdup(ldap_pool, c->argv[0]);
3417
3418 if (c->argc > 1) {
3419 ldap_user_name_filter = pstrdup(ldap_pool, c->argv[1]);
3420
3421 } else {
3422 ldap_user_name_filter = pstrcat(ldap_pool,
3423 "(&(", ldap_attr_uid, "=%v)(objectclass=posixAccount))", NULL);
3424 }
3425
3426 if (c->argc > 2) {
3427 ldap_user_uid_filter = pstrdup(ldap_pool, c->argv[2]);
3428
3429 } else {
3430 ldap_user_uid_filter = pstrcat(ldap_pool,
3431 "(&(", ldap_attr_uidnumber, "=%v)(objectclass=posixAccount))", NULL);
3432 }
3433 }
3434
3435 ptr = get_param_ptr(main_server->conf, "LDAPDefaultUID", FALSE);
3436 if (ptr != NULL) {
3437 ldap_defaultuid = *((uid_t *) ptr);
3438 }
3439
3440 ptr = get_param_ptr(main_server->conf, "LDAPDefaultGID", FALSE);
3441 if (ptr != NULL) {
3442 ldap_defaultgid = *((gid_t *) ptr);
3443 }
3444
3445 ldap_default_quota = get_param_ptr(main_server->conf, "LDAPDefaultQuota",
3446 FALSE);
3447
3448 ptr = get_param_ptr(main_server->conf, "LDAPForceDefaultUID", FALSE);
3449 if (ptr != NULL) {
3450 ldap_forcedefaultuid = *((int *) ptr);
3451 }
3452
3453 ptr = get_param_ptr(main_server->conf, "LDAPForceDefaultGID", FALSE);
3454 if (ptr != NULL) {
3455 ldap_forcedefaultgid = *((int *) ptr);
3456 }
3457
3458 ptr = get_param_ptr(main_server->conf, "LDAPForceGeneratedHomedir", FALSE);
3459 if (ptr != NULL) {
3460 ldap_forcegenhdir = *((int *) ptr);
3461 }
3462
3463 ptr = get_param_ptr(main_server->conf, "LDAPGenerateHomedir", FALSE);
3464 if (ptr != NULL) {
3465 ldap_genhdir = *((int *) ptr);
3466 }
3467
3468 ldap_genhdir_prefix = get_param_ptr(main_server->conf,
3469 "LDAPGenerateHomedirPrefix", FALSE);
3470
3471 ptr = get_param_ptr(main_server->conf, "LDAPGenerateHomedirPrefixNoUsername",
3472 FALSE);
3473 if (ptr != NULL) {
3474 ldap_genhdir_prefix_nouname = *((int *) ptr);
3475 }
3476
3477 c = find_config(main_server->conf, CONF_PARAM, "LDAPGroups", FALSE);
3478 if (c != NULL) {
3479 ldap_do_groups = TRUE;
3480 ldap_gid_basedn = pstrdup(ldap_pool, c->argv[0]);
3481
3482 if (c->argc > 1) {
3483 ldap_group_name_filter = pstrdup(ldap_pool, c->argv[1]);
3484
3485 } else {
3486 ldap_group_name_filter = pstrcat(ldap_pool,
3487 "(&(", ldap_attr_cn, "=%v)(objectclass=posixGroup))", NULL);
3488 }
3489
3490 if (c->argc > 2) {
3491 ldap_group_gid_filter = pstrdup(ldap_pool, c->argv[2]);
3492
3493 } else {
3494 ldap_group_gid_filter = pstrcat(ldap_pool,
3495 "(&(", ldap_attr_gidnumber, "=%v)(objectclass=posixGroup))", NULL);
3496 }
3497
3498 if (c->argc > 3) {
3499 ldap_group_member_filter = pstrdup(ldap_pool, c->argv[3]);
3500
3501 } else {
3502 ldap_group_member_filter = pstrcat(ldap_pool,
3503 "(&(", ldap_attr_memberuid, "=%v)(objectclass=posixGroup))", NULL);
3504 }
3505 }
3506
3507 c = find_config(main_server->conf, CONF_PARAM, "LDAPUseSASL", FALSE);
3508 if (c != NULL) {
3509 ldap_sasl_mechs = c->argv[0];
3510 }
3511
3512 #if defined(LBER_OPT_LOG_PRINT_FN)
3513 /* If trace logging is enabled for the 'ldap.library' channel, direct
3514 * libldap (via liblber) to log to our trace logging.
3515 */
3516 if (pr_trace_get_level(libtrace_channel) >= 1) {
3517 int res, trace_level;
3518
3519 res = ber_set_option(NULL, LBER_OPT_LOG_PRINT_FN, ldap_tracelog_cb);
3520 if (res != LBER_OPT_SUCCESS) {
3521 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
3522 "error setting trace logging function: %s", strerror(EINVAL));
3523 }
3524
3525 /* Debug levels:
3526 * Trace (1)
3527 * Packets (2)
3528 * Arguments (4)
3529 * Filters (32)
3530 * Access control (128)
3531 *
3532 * See include/ldap_log.h in the OpenLDAP source.
3533 */
3534 trace_level = pr_trace_get_level(libtrace_channel);
3535 res = ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &trace_level);
3536 if (res != LDAP_OPT_SUCCESS) {
3537 (void) pr_log_writefile(ldap_logfd, MOD_LDAP_VERSION,
3538 "error setting LDAP debug level %d: %s", trace_level,
3539 strerror(EINVAL));
3540 }
3541 }
3542 #endif /* LBER_OPT_LOG_PRINT_FN */
3543
3544 if (ldap_do_users == FALSE) {
3545 pr_log_pri(PR_LOG_WARNING, MOD_LDAP_VERSION
3546 ": LDAPUsers not configured, skipping LDAP-based user authentication");
3547 }
3548
3549 if (ldap_do_groups == FALSE) {
3550 pr_log_pri(PR_LOG_NOTICE, MOD_LDAP_VERSION
3551 ": LDAPGroups not configured, skipping LDAP-based group memberships");
3552 }
3553
3554 return 0;
3555 }
3556
3557 /* Module API tables
3558 */
3559
3560 static conftable ldap_conftab[] = {
3561 { "LDAPAliasDereference", set_ldapaliasdereference, NULL },
3562 { "LDAPAttr", set_ldapattr, NULL },
3563 { "LDAPAuthBinds", set_ldapauthbinds, NULL },
3564 { "LDAPBindDN", set_ldapbinddn, NULL },
3565 { "LDAPDefaultAuthScheme", set_ldapdefaultauthscheme, NULL },
3566 { "LDAPDefaultGID", set_ldapdefaultgid, NULL },
3567 { "LDAPDefaultQuota", set_ldapdefaultquota, NULL },
3568 { "LDAPDefaultUID", set_ldapdefaultuid, NULL },
3569 { "LDAPForceDefaultGID", set_ldapforcedefaultgid, NULL },
3570 { "LDAPForceDefaultUID", set_ldapforcedefaultuid, NULL },
3571 { "LDAPForceGeneratedHomedir",set_ldapforcegenhdir, NULL },
3572 { "LDAPGenerateHomedir", set_ldapgenhdir, NULL },
3573 { "LDAPGenerateHomedirPrefix",set_ldapgenhdirprefix, NULL },
3574 { "LDAPGenerateHomedirPrefixNoUsername",
3575 set_ldapgenhdirprefixnouname, NULL },
3576 { "LDAPGroups", set_ldapgrouplookups, NULL },
3577 { "LDAPLog", set_ldaplog, NULL },
3578 { "LDAPProtocolVersion", set_ldapprotoversion, NULL },
3579 { "LDAPQueryTimeout", set_ldapquerytimeout, NULL },
3580 { "LDAPSearchScope", set_ldapsearchscope, NULL },
3581 { "LDAPServer", set_ldapserver, NULL },
3582 { "LDAPUsers", set_ldapusers, NULL },
3583 { "LDAPUseSASL", set_ldapusesasl, NULL },
3584 { "LDAPUseTLS", set_ldapusetls, NULL },
3585
3586 { NULL, NULL, NULL },
3587 };
3588
3589 static cmdtable ldap_cmdtab[] = {
3590 { HOOK, "ldap_quota_lookup", G_NONE, handle_ldap_quota_lookup, FALSE, FALSE},
3591 { HOOK, "ldap_ssh_publickey_lookup", G_NONE, handle_ldap_ssh_pubkey_lookup, FALSE, FALSE},
3592
3593 { 0, NULL}
3594 };
3595
3596 static authtable ldap_authtab[] = {
3597 { 0, "setpwent", ldap_auth_setpwent },
3598 { 0, "endpwent", ldap_auth_endpwent },
3599 { 0, "setgrent", ldap_auth_setpwent },
3600 { 0, "endgrent", ldap_auth_endpwent },
3601 { 0, "getpwnam", ldap_auth_getpwnam },
3602 { 0, "getpwuid", ldap_auth_getpwuid },
3603 { 0, "getgrnam", ldap_auth_getgrnam },
3604 { 0, "getgrgid", ldap_auth_getgrgid },
3605 { 0, "getgroups", ldap_auth_getgroups },
3606 { 0, "auth", ldap_auth_auth },
3607 { 0, "check", ldap_auth_check },
3608 { 0, "uid2name", ldap_auth_uid2name },
3609 { 0, "gid2name", ldap_auth_gid2name },
3610 { 0, "name2uid", ldap_auth_name2uid },
3611 { 0, "name2gid", ldap_auth_name2gid },
3612
3613 { 0, NULL }
3614 };
3615
3616 module ldap_module = {
3617 /* Always NULL */
3618 NULL, NULL,
3619
3620 /* Module API version */
3621 0x20,
3622
3623 /* Module name */
3624 "ldap",
3625
3626 /* Module configuration handler table */
3627 ldap_conftab,
3628
3629 /* Module command handler table */
3630 ldap_cmdtab,
3631
3632 /* Module authentication handler table */
3633 ldap_authtab,
3634
3635 /* Module initialization */
3636 ldap_mod_init,
3637
3638 /* Session initialization */
3639 ldap_sess_init,
3640
3641 /* Module version */
3642 MOD_LDAP_VERSION
3643 };
3644