]> jfr.im git - irc/evilnet/x3.git/blame - src/x3ldap.c
Small tweak to the password checks with sslfp LOC.
[irc/evilnet/x3.git] / src / x3ldap.c
CommitLineData
50895889 1/* x3ldap.c - LDAP functionality for x3, by Rubin
2 * Copyright 2002-2007 x3 Development Team
3 *
4 * This file is part of x3.
5 *
6 * x3 is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
348683aa 8 * the Free Software Foundation; either version 3 of the License, or
50895889 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 srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
e166c31b 19 *
e166c31b 20 *
21 * TODO:
22 * * get queries working in static existance, so i understand how it works
23 * * get ldap enabled in ./configure
24 * * x3.conf settings to enable/configure its use
25 * * generic functions to enable ldap
26 * * nickserv.c work to use said functions.
27 */
28
39edf54a 29#include "config.h"
db9a9a8a 30#ifdef WITH_LDAP
31
e166c31b 32#include <stdio.h>
33#include <stdlib.h>
34#include <ldap.h>
73d4cc91 35
e166c31b 36#include "conf.h"
e166c31b 37#include "global.h"
50895889 38#include "log.h"
e166c31b 39#include "x3ldap.h"
40
e166c31b 41extern struct nickserv_config nickserv_conf;
42
43
e166c31b 44LDAP *ld = NULL;
b96027ad 45int admin_bind = false;
e166c31b 46
47int ldap_do_init()
48{
39edf54a 49 if(!nickserv_conf.ldap_enable)
50 return false;
e166c31b 51 /* TODO: check here for all required config options and exit() out if not present */
bec5dd26 52 //ld = ldap_init(nickserv_conf.ldap_host, nickserv_conf.ldap_port);
53
54 //if(ld == NULL) {
55 if(ldap_initialize(&ld, nickserv_conf.ldap_uri)) {
50895889 56 log_module(MAIN_LOG, LOG_ERROR, "LDAP initilization failed!\n");
e166c31b 57 exit(1);
58 }
59 ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &nickserv_conf.ldap_version);
bec5dd26 60 log_module(MAIN_LOG, LOG_INFO, "Success! ldap_init() was successfull in connecting to %s\n", nickserv_conf.ldap_uri);
e166c31b 61 return true;
62}
63
ea02341b 64
e166c31b 65/* Try to auth someone. If theres problems, try reconnecting
66 * once every 10 seconds for 1 minute.
67 * TODO: move this stuff to config file
68 */
ea02341b 69unsigned int ldap_do_bind( const char *dn, const char *pass)
e166c31b 70{
e166c31b 71 int q;
72
e166c31b 73 int n = 0;
74 while(1) {
ea02341b 75 q = ldap_simple_bind_s(ld, dn, pass);
e166c31b 76 if(q == LDAP_SUCCESS) {
4b8ccfeb 77 log_module(MAIN_LOG, LOG_DEBUG, "bind() successfull! You are bound as %s", dn);
ea02341b 78 /* unbind now */
a5a8a781 79 return q;
e166c31b 80 }
81 else if(q == LDAP_INVALID_CREDENTIALS) {
a5a8a781 82 return q;
e166c31b 83 }
84 else {
5aef35cf 85 log_module(MAIN_LOG, LOG_ERROR, "Bind failed: %s/****** (%s)", dn, ldap_err2string(q));
86 /* ldap_perror(ld, "ldap"); */
ea02341b 87 ldap_do_init();
e166c31b 88 }
39edf54a 89 if(n++ > 1) {
90 /* TODO: return to the user that this is a connection error and not a problem
91 * with their password
92 */
93 log_module(MAIN_LOG, LOG_ERROR, "Failing to reconnect to ldap server. Auth failing.");
a5a8a781 94 return q;
e166c31b 95 }
96 }
ea02341b 97 log_module(MAIN_LOG, LOG_ERROR, "ldap_do_bind falling off the end. this shouldnt happen");
a5a8a781 98 return q;
ea02341b 99}
24e9e6c3 100int ldap_do_admin_bind()
101{
b96027ad 102 int rc;
24e9e6c3 103 if(!(nickserv_conf.ldap_admin_dn && *nickserv_conf.ldap_admin_dn &&
104 nickserv_conf.ldap_admin_pass && *nickserv_conf.ldap_admin_pass)) {
105 log_module(MAIN_LOG, LOG_ERROR, "Tried to admin bind, but no admin credentials configured in config file. ldap_admin_dn/ldap_admin_pass");
106 return LDAP_OTHER; /* not configured to do this */
107 }
b96027ad 108 rc = ldap_do_bind(nickserv_conf.ldap_admin_dn, nickserv_conf.ldap_admin_pass);
109 if(rc == LDAP_SUCCESS)
110 admin_bind = true;
111 return rc;
24e9e6c3 112}
113
ea02341b 114
115unsigned int ldap_check_auth( char *account, char *pass)
116{
117 char buff[MAXLEN];
118
119 if(!nickserv_conf.ldap_enable)
a5a8a781 120 return LDAP_OTHER;
ea02341b 121
122 memset(buff, 0, MAXLEN);
123 snprintf(buff, sizeof(buff)-1, nickserv_conf.ldap_dn_fmt /*"uid=%s,ou=Users,dc=afternet,dc=org"*/, account);
b96027ad 124 admin_bind = false;
ea02341b 125 return ldap_do_bind(buff, pass);
e166c31b 126
127}
128
24e9e6c3 129int ldap_search_user(char *account, LDAPMessage **entry)
e166c31b 130{
131
24e9e6c3 132 char filter[MAXLEN+1];
133 int rc;
134 LDAPMessage *res;
e166c31b 135
136 struct timeval timeout;
24e9e6c3 137
138 memset(filter, 0, MAXLEN+1);
139 snprintf(filter, MAXLEN, "%s=%s", nickserv_conf.ldap_field_account, account);
e166c31b 140 /*
141 Now we do a search;
142 */
143 timeout.tv_usec = 0;
ddcb3eb3 144 timeout.tv_sec = nickserv_conf.ldap_timeout;
b96027ad 145 if(!admin_bind && LDAP_SUCCESS != ( rc = ldap_do_admin_bind())) {
24e9e6c3 146 log_module(MAIN_LOG, LOG_ERROR, "failed to bind as admin");
147 return rc;
148 }
149 if( (rc = ldap_search_st(ld, nickserv_conf.ldap_base, LDAP_SCOPE_ONELEVEL, filter, NULL, 0, &timeout, &res)) != LDAP_SUCCESS) {
150 log_module(MAIN_LOG, LOG_ERROR, "search failed: %s %s: %s", nickserv_conf.ldap_base, filter, ldap_err2string(rc));
151 return(rc);
e166c31b 152 }
24e9e6c3 153 log_module(MAIN_LOG, LOG_DEBUG, "Search successfull! %s %s\n", nickserv_conf.ldap_base, filter);
154 if(ldap_count_entries(ld, res) != 1) {
b96027ad 155 log_module(MAIN_LOG, LOG_DEBUG, "LDAP search got %d entries when looking for %s", ldap_count_entries(ld, res), account);
24e9e6c3 156 return(LDAP_OTHER); /* Search was a success, but user not found.. */
e166c31b 157 }
24e9e6c3 158 log_module(MAIN_LOG, LOG_DEBUG, "LDAP search got %d entries", ldap_count_entries(ld, res));
159 *entry = ldap_first_entry(ld, res);
160 return(rc);
161}
162
163/* queries the ldap server for account..
164 * if a single account match is found,
165 * email is allocated and set to the email address
166 * and returns LDAP_SUCCESS. returns LDAP_OTHER if
167 * 0 or 2+ entries are matched, or the proper ldap error
168 * code for other errors.
169 */
170int ldap_get_user_info(char *account, char **email)
171{
172 int rc;
173 char **value;
174 LDAPMessage *entry, *res;
b96027ad 175 if(email)
176 *email = NULL;
24e9e6c3 177 if( (rc = ldap_search_user(account, &res)) == LDAP_SUCCESS) {
178 entry = ldap_first_entry(ld, res);
179 value = ldap_get_values(ld, entry, nickserv_conf.ldap_field_email);
180 if(!value) {
181 return(LDAP_OTHER);
182 }
b96027ad 183 if(email)
184 *email = strdup(value[0]);
24e9e6c3 185 log_module(MAIN_LOG, LOG_DEBUG, "%s: %s\n", nickserv_conf.ldap_field_email, value[0]);
186 /*
187 value = ldap_get_values(ld, entry, "description");
188 log_module(MAIN_LOG, LOG_DEBUG, "Description: %s\n", value[0]);
189 value = ldap_get_values(ld, entry, "userPassword");
190 log_module(MAIN_LOG, LOG_DEBUG, "pass: %s\n", value ? value[0] : "error");
191 */
192 }
193 return(rc);
194}
195
e166c31b 196 /*
197 ldap_result();
198 ldap_first_entry();
199 ldap_first_attribute();
200 for(;;) {
201 ldap_get_values();
202 ldap_next_attribute();
203 }
204
205 ldap_parse_result();
206
207 ldap_unbind_ext();
e166c31b 208 */
209 /* get errors with ldap_err2string(); */
e166c31b 210
e166c31b 211
4b8ccfeb 212/********* base64 stuff ***********/
213
8dc17ddf 214unsigned char *pack(const char *str, unsigned int *len)
4b8ccfeb 215{
216 int nibbleshift = 4;
217 int first = 1;
218 char *v;
219 static unsigned char buf[MAXLEN+1];
220 int outputpos = -1;
221
222 memset(buf, 0, MAXLEN+1);
8dc17ddf 223 v = (char *)str;
4b8ccfeb 224 while(*v) {
225 char n = *(v++);
226
227 if((n >= '0') && (n <= '9')) {
228 n -= '0';
229 } else if ((n >= 'A') && (n <= 'F')) {
230 n -= ('A' - 10);
231 } else if ((n >= 'a') && (n <= 'f')) {
232 n -= ('a' - 10);
233 } else {
234 printf("pack type H: illegal hex digit %c", n);
235 n = 0;
236 }
237
238 if (first--) {
239 buf[++outputpos] = 0;
240 } else {
241 first = 1;
242 }
243
244 buf[outputpos] |= (n << nibbleshift);
245 nibbleshift = (nibbleshift + 4) & 7;
246 }
247 *len = outputpos+1;
248 return(buf);
249}
250
251
252/* from php5 sources */
253static char base64_table[] =
254 { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
255 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
256 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
257 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
258 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0'
259 };
260static char base64_pad = '=';
261
262char *base64_encode(const unsigned char *str, int length, int *ret_length)
263{
264 const unsigned char *current = str;
265 char *p;
266 char *result;
267
268 if ((length + 2) < 0 || ((length + 2) / 3) >= (1 << (sizeof(int) * 8 - 2))) {
269 if (ret_length != NULL) {
270 *ret_length = 0;
271 }
272 return NULL;
273 }
274
41a3556d 275 result = (char *)calloc((((length + 2) / 3) * 4)+1, sizeof(char));
4b8ccfeb 276 p = result;
277
278 while (length > 2) { /* keep going until we have less than 24 bits */
279 *p++ = base64_table[current[0] >> 2];
280 *p++ = base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)];
281 *p++ = base64_table[((current[1] & 0x0f) << 2) + (current[2] >> 6)];
282 *p++ = base64_table[current[2] & 0x3f];
283
284 current += 3;
285 length -= 3; /* we just handle 3 octets of data */
286 }
287
288 /* now deal with the tail end of things */
289 if (length != 0) {
290 *p++ = base64_table[current[0] >> 2];
291 if (length > 1) {
292 *p++ = base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)];
293 *p++ = base64_table[(current[1] & 0x0f) << 2];
294 *p++ = base64_pad;
295 } else {
296 *p++ = base64_table[(current[0] & 0x03) << 4];
297 *p++ = base64_pad;
298 *p++ = base64_pad;
299 }
300 }
301 if (ret_length != NULL) {
302 *ret_length = (int)(p - result);
303 }
304 *p = '\0';
305 return result;
306}
307
308
73d4cc91 309char **make_object_vals()
310{
311 unsigned int y;
312 static char **object_vals = NULL;
313
314 if(object_vals)
315 free(object_vals);
316
317 object_vals = malloc(sizeof( *object_vals ) * nickserv_conf.ldap_object_classes->used);
318
319 for(y = 0; y < nickserv_conf.ldap_object_classes->used; y++) {
320 object_vals[y] = nickserv_conf.ldap_object_classes->list[y];
321 }
322 object_vals[y] = NULL;
323 return object_vals;
324}
325
8dc17ddf 326char *make_password(const char *crypted)
4b8ccfeb 327{
328 char *base64pass;
4b8ccfeb 329 unsigned char *packed;
330 unsigned int len;
331 char *passbuf;
4b8ccfeb 332
333 packed = pack(crypted, &len);
334 base64pass = base64_encode(packed, len, NULL);
335 passbuf = malloc(strlen(base64pass) + 1 + 5);
336 strcpy(passbuf, "{MD5}");
337 strcat(passbuf, base64pass);
338 //log_module(MAIN_LOG, LOG_DEBUG, "Encoded password is: '%s'", passbuf);
339 free(base64pass);
340 return passbuf;
341
342}
343
73d4cc91 344LDAPMod **make_mods_add(const char *account, const char *password, const char *email, int *num_mods_ret)
ea02341b 345{
346 static char *account_vals[] = { NULL, NULL };
347 static char *password_vals[] = { NULL, NULL };
348 static char *email_vals[] = { NULL, NULL };
75fcdcad 349 int num_mods = 2;
ea02341b 350 int i;
75fcdcad 351 int mod = 0;
ea02341b 352 /* TODO: take this from nickserv_conf.ldap_add_objects */
ea02341b 353 LDAPMod **mods;
73d4cc91 354 static char **object_vals;
355 object_vals = make_object_vals();
ea02341b 356
357 account_vals[0] = (char *) account;
75fcdcad 358 if (password != NULL) {
359 password_vals[0] = (char *) password;
360 num_mods++;
361 }
ea02341b 362 email_vals[0] = (char *) email;
363
364 if(!(nickserv_conf.ldap_field_account && *nickserv_conf.ldap_field_account))
365 return 0; /* account required */
366 if(!(nickserv_conf.ldap_field_password && *nickserv_conf.ldap_field_password))
367 return 0; /* password required */
368 if(email && *email && nickserv_conf.ldap_field_email && *nickserv_conf.ldap_field_email)
369 num_mods++;
370
371 mods = ( LDAPMod ** ) malloc(( num_mods + 1 ) * sizeof( LDAPMod * ));
372 for( i = 0; i < num_mods; i++) {
373 mods[i] = (LDAPMod *) malloc(sizeof(LDAPMod));
374 memset(mods[i], 0, sizeof(LDAPMod));
375 }
376
75fcdcad 377 mods[mod]->mod_op = LDAP_MOD_ADD;
378 mods[mod]->mod_type = strdup("objectclass");
379 mods[mod]->mod_values = object_vals;
380 mod++;
381
382 mods[mod]->mod_op = LDAP_MOD_ADD;
383 mods[mod]->mod_type = strdup(nickserv_conf.ldap_field_account);
384 mods[mod]->mod_values = account_vals;
385 mod++;
386
387 if (password != NULL) {
388 mods[mod]->mod_op = LDAP_MOD_ADD;
389 mods[mod]->mod_type = strdup(nickserv_conf.ldap_field_password);
390 mods[mod]->mod_values = password_vals;
391 mod++;
392 }
ea02341b 393
394 if(nickserv_conf.ldap_field_email && *nickserv_conf.ldap_field_email && email && *email) {
75fcdcad 395 mods[mod]->mod_op = LDAP_MOD_ADD;
396 mods[mod]->mod_type = strdup(nickserv_conf.ldap_field_email);
397 mods[mod]->mod_values = email_vals;
398 mod++;
ea02341b 399 }
75fcdcad 400 mods[mod] = NULL;
ea02341b 401 *num_mods_ret = num_mods;
402 return mods;
403}
404
8dc17ddf 405int ldap_do_add(const char *account, const char *crypted, const char *email)
ea02341b 406{
407 char newdn[MAXLEN];
408 LDAPMod **mods;
409 int rc, i;
410 int num_mods;
4b8ccfeb 411 char *passbuf;
ea02341b 412
b96027ad 413 if(!admin_bind && LDAP_SUCCESS != ( rc = ldap_do_admin_bind())) {
ea02341b 414 log_module(MAIN_LOG, LOG_ERROR, "failed to bind as admin");
a5a8a781 415 return rc;
ea02341b 416 }
75fcdcad 417
418 if (crypted != NULL)
419 passbuf = make_password(crypted);
ea02341b 420 snprintf(newdn, MAXLEN-1, nickserv_conf.ldap_dn_fmt, account);
75fcdcad 421 mods = make_mods_add(account, (crypted != NULL ? passbuf : crypted), email, &num_mods);
ea02341b 422 if(!mods) {
423 log_module(MAIN_LOG, LOG_ERROR, "Error building mods for ldap_add");
a5a8a781 424 return LDAP_OTHER;
ea02341b 425 }
426 rc = ldap_add_ext_s(ld, newdn, mods, NULL, NULL);
eb9bf540 427 if(rc != LDAP_SUCCESS && rc!= LDAP_ALREADY_EXISTS) {
ea02341b 428 log_module(MAIN_LOG, LOG_ERROR, "Error adding ldap account: %s -- %s", account, ldap_err2string(rc));
b96027ad 429 // return rc;
ea02341b 430 }
431 //ldap_unbind_s(ld);
432 for(i = 0; i < num_mods; i++) {
433 free(mods[i]->mod_type);
434 free(mods[i]);
435 }
436 free(mods);
75fcdcad 437 if (crypted != NULL)
438 free(passbuf);
a5a8a781 439 return rc;
ea02341b 440}
441
73d4cc91 442int ldap_delete_account(char *account)
443{
444 char dn[MAXLEN];
a40080a2 445 int rc;
446
b96027ad 447 if(!admin_bind && LDAP_SUCCESS != ( rc = ldap_do_admin_bind())) {
a40080a2 448 log_module(MAIN_LOG, LOG_ERROR, "failed to bind as admin");
449 return rc;
450 }
451
73d4cc91 452 memset(dn, 0, MAXLEN);
453 snprintf(dn, MAXLEN-1, nickserv_conf.ldap_dn_fmt, account);
454 return(ldap_delete_s(ld, dn));
455}
456
457int ldap_rename_account(char *oldaccount, char *newaccount)
458{
459 char dn[MAXLEN], newdn[MAXLEN];
460 int rc;
461
b96027ad 462 if(!admin_bind && LDAP_SUCCESS != ( rc = ldap_do_admin_bind())) {
73d4cc91 463 log_module(MAIN_LOG, LOG_ERROR, "failed to bind as admin");
464 return rc;
465 }
466
467 memset(dn, 0, MAXLEN);
468 memset(newdn, 0, MAXLEN);
469 snprintf(dn, MAXLEN-1, nickserv_conf.ldap_dn_fmt, oldaccount);
470 strcat(newdn, nickserv_conf.ldap_field_account);
471 strcat(newdn, "=");
472 strcat(newdn, newaccount);
473 rc = ldap_modrdn2_s(ld, dn, newdn, true);
474 if(rc != LDAP_SUCCESS) {
475 log_module(MAIN_LOG, LOG_ERROR, "Error modifying ldap account: %s -- %s", oldaccount, ldap_err2string(rc));
b96027ad 476 //return rc;
73d4cc91 477 }
478 return rc;
479
480}
481
482LDAPMod **make_mods_modify(const char *password, const char *email, int *num_mods_ret)
483{
484 static char *password_vals[] = { NULL, NULL };
485 static char *email_vals[] = { NULL, NULL };
8a729617 486 int num_mods = 0;
73d4cc91 487 int i;
488 /* TODO: take this from nickserv_conf.ldap_add_objects */
489 LDAPMod **mods;
490
491 password_vals[0] = (char *) password;
492 email_vals[0] = (char *) email;
493
494 if(!(nickserv_conf.ldap_field_password && *nickserv_conf.ldap_field_password))
495 return 0; /* password required */
8a729617 496 /*
73d4cc91 497 if(email && *email && nickserv_conf.ldap_field_email && *nickserv_conf.ldap_field_email)
498 num_mods++;
8a729617 499 */
500 if(password)
501 num_mods++;
502 if(email)
503 num_mods++;
73d4cc91 504
505 mods = ( LDAPMod ** ) malloc(( num_mods + 1 ) * sizeof( LDAPMod * ));
506 for( i = 0; i < num_mods; i++) {
507 mods[i] = (LDAPMod *) malloc(sizeof(LDAPMod));
508 memset(mods[i], 0, sizeof(LDAPMod));
509 }
510
511 i = 0;
512 if(nickserv_conf.ldap_field_password && *nickserv_conf.ldap_field_password &&
513 password) {
514 mods[i]->mod_op = LDAP_MOD_REPLACE;
515 mods[i]->mod_type = strdup(nickserv_conf.ldap_field_password);
516 mods[i]->mod_values = password_vals;
517 i++;
518 }
519
520 if(nickserv_conf.ldap_field_email && *nickserv_conf.ldap_field_email && email) {
521 mods[i]->mod_op = LDAP_MOD_REPLACE;
522 mods[i]->mod_type = strdup(nickserv_conf.ldap_field_email);
523 mods[i]->mod_values = email_vals;
524 i++;
525 }
526 mods[i] = NULL;
527 *num_mods_ret = num_mods;
528 return mods;
529}
530
35ea100f 531/* Save OpServ level to LDAP
532 *
533 * level - OpServ level
534 *
535 * A level of <0 will be treated as 0
536 */
f3aff201 537int ldap_do_oslevel(const char *account, int level, int oldlevel)
35ea100f 538{
539 LDAPMod **mods;
540 static char *oslevel_vals[] = { NULL, NULL };
541 char dn[MAXLEN], temp[MAXLEN];
542 int rc;
543
544 if(!admin_bind && LDAP_SUCCESS != ( rc = ldap_do_admin_bind())) {
545 log_module(MAIN_LOG, LOG_ERROR, "failed to bind as admin");
546 return rc;
547 }
548
549 if (level < 0) {
550 level = 0;
551 }
552
f3aff201 553 snprintf(temp, MAXLEN-1, "%d", (level ? level : oldlevel));
35ea100f 554 oslevel_vals[0] = (char *) temp;
555
556 if(!(nickserv_conf.ldap_field_oslevel && *nickserv_conf.ldap_field_oslevel))
557 return 0;
558
559 snprintf(dn, MAXLEN-1, nickserv_conf.ldap_dn_fmt, account);
560
561 mods = ( LDAPMod ** ) malloc(( 1 ) * sizeof( LDAPMod * ));
562 mods[0] = (LDAPMod *) malloc(sizeof(LDAPMod));
563 memset(mods[0], 0, sizeof(LDAPMod));
564
f3aff201 565 mods[0]->mod_op = (level ? LDAP_MOD_REPLACE : LDAP_MOD_DELETE);
35ea100f 566 mods[0]->mod_type = strdup(nickserv_conf.ldap_field_oslevel);
567 mods[0]->mod_values = oslevel_vals;
568 mods[1] = NULL;
569
570 rc = ldap_modify_s(ld, dn, mods);
571 if(rc != LDAP_SUCCESS) {
572 log_module(MAIN_LOG, LOG_ERROR, "Error modifying ldap OpServ level: %s -- %s", account, ldap_err2string(rc));
573 //return rc;
574 }
575 free(mods[0]->mod_type);
576 free(mods[0]);
577 free(mods);
578
579 return rc;
580}
73d4cc91 581
582/* Save email or password to server
583 *
584 * password - UNENCRYPTED password. This function encrypts if libs are available
585 * email - email address
586 *
587 * NULL to make no change
588 */
589int ldap_do_modify(const char *account, const char *password, const char *email)
590{
591 char dn[MAXLEN];
592 LDAPMod **mods;
593 int rc, i;
594 int num_mods;
595 char *passbuf = NULL;
596
b96027ad 597 if(!admin_bind && LDAP_SUCCESS != ( rc = ldap_do_admin_bind())) {
73d4cc91 598 log_module(MAIN_LOG, LOG_ERROR, "failed to bind as admin");
599 return rc;
600 }
601
602 if(password) {
4b8ccfeb 603 passbuf = make_password(password);
73d4cc91 604 }
605
606 snprintf(dn, MAXLEN-1, nickserv_conf.ldap_dn_fmt, account);
607 mods = make_mods_modify(passbuf, email, &num_mods);
608 if(!mods) {
b96027ad 609 log_module(MAIN_LOG, LOG_ERROR, "Error building mods for ldap_do_modify");
73d4cc91 610 return LDAP_OTHER;
611 }
612 rc = ldap_modify_s(ld, dn, mods);
613 if(rc != LDAP_SUCCESS) {
b96027ad 614 log_module(MAIN_LOG, LOG_ERROR, "Error modifying ldap account: %s -- %s", account, ldap_err2string(rc));
615 // return rc;
73d4cc91 616 }
617 for(i = 0; i < num_mods; i++) {
618 free(mods[i]->mod_type);
619 free(mods[i]);
620 }
621 free(mods);
622 if(passbuf)
623 free(passbuf);
624 return rc;
625}
626
8a729617 627LDAPMod **make_mods_group(const char *account, int operation, int *num_mods_ret)
628{
629 static char *uid_vals[] = { NULL, NULL };
630 int num_mods = 1;
631 int i;
632 /* TODO: take this from nickserv_conf.ldap_add_objects */
633 LDAPMod **mods;
634
635 uid_vals[0] = (char *) account;
636
637 if(!(nickserv_conf.ldap_field_group_member && *nickserv_conf.ldap_field_group_member))
638 return 0; /* password required */
639
640 mods = ( LDAPMod ** ) malloc(( num_mods + 1 ) * sizeof( LDAPMod * ));
641 for( i = 0; i < num_mods; i++) {
642 mods[i] = (LDAPMod *) malloc(sizeof(LDAPMod));
643 memset(mods[i], 0, sizeof(LDAPMod));
644 }
645
646 i = 0;
647 mods[i]->mod_op = operation;
648 mods[i]->mod_type = strdup(nickserv_conf.ldap_field_group_member);
649 mods[i]->mod_values = uid_vals;
650 i++;
651 mods[i] = NULL;
652 *num_mods_ret = num_mods;
653 return mods;
654}
655
656
657int ldap_add2group(char *account, const char *group)
658{
659 LDAPMod **mods;
660 int num_mods;
661 int rc, i;
662
b96027ad 663 if(!admin_bind && LDAP_SUCCESS != ( rc = ldap_do_admin_bind())) {
8a729617 664 log_module(MAIN_LOG, LOG_ERROR, "failed to bind as admin");
665 return rc;
666 }
667 mods = make_mods_group(account, LDAP_MOD_ADD, &num_mods);
668 if(!mods) {
669 log_module(MAIN_LOG, LOG_ERROR, "Error building mods for add2group");
670 return LDAP_OTHER;
671 }
672 rc = ldap_modify_s(ld, group, mods);
87677bd8 673 if(rc != LDAP_SUCCESS && rc != LDAP_TYPE_OR_VALUE_EXISTS) {
8a729617 674 log_module(MAIN_LOG, LOG_ERROR, "Error adding %s to group %s: %s", account, group, ldap_err2string(rc));
675 return rc;
676 }
677 for(i = 0; i < num_mods; i++) {
678 free(mods[i]->mod_type);
679 free(mods[i]);
680 }
681 free(mods);
682 return rc;
683}
684
685int ldap_delfromgroup(char *account, const char *group)
686{
687 LDAPMod **mods;
688 int num_mods;
689 int rc, i;
690
b96027ad 691 if(!admin_bind && LDAP_SUCCESS != ( rc = ldap_do_admin_bind())) {
8a729617 692 log_module(MAIN_LOG, LOG_ERROR, "failed to bind as admin");
693 return rc;
694 }
695 mods = make_mods_group(account, LDAP_MOD_DELETE, &num_mods);
696 if(!mods) {
697 log_module(MAIN_LOG, LOG_ERROR, "Error building mods for delfromgroup");
698 return LDAP_OTHER;
699 }
700 rc = ldap_modify_s(ld, group, mods);
eb9bf540 701 if(rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_ATTRIBUTE) {
8a729617 702 log_module(MAIN_LOG, LOG_ERROR, "Error removing %s from group %s: %s", account, group, ldap_err2string(rc));
703 return rc;
704 }
705 for(i = 0; i < num_mods; i++) {
706 free(mods[i]->mod_type);
707 free(mods[i]);
708 }
709 free(mods);
710 return rc;
711}
712
713
e166c31b 714void ldap_close()
715{
b96027ad 716 admin_bind = false;
e166c31b 717 ldap_unbind(ld);
718}
719
720#endif