X-Git-Url: https://jfr.im/git/irc/evilnet/x3.git/blobdiff_plain/4b8ccfeb5cff79382167d1d7d6c765870ed1a5cd..ff3b058ac51e9caf5cf1fd310b8a401a97a85582:/src/x3ldap.c diff --git a/src/x3ldap.c b/src/x3ldap.c index 18a93bb..1ed4b1e 100644 --- a/src/x3ldap.c +++ b/src/x3ldap.c @@ -5,7 +5,7 @@ * * x3 is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -42,19 +42,22 @@ extern struct nickserv_config nickserv_conf; LDAP *ld = NULL; +int admin_bind = false; int ldap_do_init() { if(!nickserv_conf.ldap_enable) return false; /* TODO: check here for all required config options and exit() out if not present */ - ld = ldap_init(nickserv_conf.ldap_host, nickserv_conf.ldap_port); - if(ld == NULL) { + //ld = ldap_init(nickserv_conf.ldap_host, nickserv_conf.ldap_port); + + //if(ld == NULL) { + if(ldap_initialize(&ld, nickserv_conf.ldap_uri)) { log_module(MAIN_LOG, LOG_ERROR, "LDAP initilization failed!\n"); exit(1); } ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &nickserv_conf.ldap_version); - log_module(MAIN_LOG, LOG_INFO, "Success! ldap_init() was successfull in connecting to %s port %d\n", nickserv_conf.ldap_host, nickserv_conf.ldap_port ); + log_module(MAIN_LOG, LOG_INFO, "Success! ldap_init() was successfull in connecting to %s\n", nickserv_conf.ldap_uri); return true; } @@ -79,8 +82,8 @@ unsigned int ldap_do_bind( const char *dn, const char *pass) return q; } else { - log_module(MAIN_LOG, LOG_ERROR, "Bind failed: %s/****** (%d)", dn, q); - ldap_perror(ld, "ldap"); + log_module(MAIN_LOG, LOG_ERROR, "Bind failed: %s/****** (%s)", dn, ldap_err2string(q)); + /* ldap_perror(ld, "ldap"); */ ldap_do_init(); } if(n++ > 1) { @@ -94,6 +97,20 @@ unsigned int ldap_do_bind( const char *dn, const char *pass) log_module(MAIN_LOG, LOG_ERROR, "ldap_do_bind falling off the end. this shouldnt happen"); return q; } +int ldap_do_admin_bind() +{ + int rc; + if(!(nickserv_conf.ldap_admin_dn && *nickserv_conf.ldap_admin_dn && + nickserv_conf.ldap_admin_pass && *nickserv_conf.ldap_admin_pass)) { + log_module(MAIN_LOG, LOG_ERROR, "Tried to admin bind, but no admin credentials configured in config file. ldap_admin_dn/ldap_admin_pass"); + return LDAP_OTHER; /* not configured to do this */ + } + rc = ldap_do_bind(nickserv_conf.ldap_admin_dn, nickserv_conf.ldap_admin_pass); + if(rc == LDAP_SUCCESS) + admin_bind = true; + return rc; +} + unsigned int ldap_check_auth( char *account, char *pass) { @@ -104,39 +121,78 @@ unsigned int ldap_check_auth( char *account, char *pass) memset(buff, 0, MAXLEN); snprintf(buff, sizeof(buff)-1, nickserv_conf.ldap_dn_fmt /*"uid=%s,ou=Users,dc=afternet,dc=org"*/, account); + admin_bind = false; return ldap_do_bind(buff, pass); } -#ifdef notdef /* not used yet - will be used to pull email etc out of ldap */ -LDAPMessage ldap_search_user(char uid) +int ldap_search_user(char *account, LDAPMessage **entry) { - char filter[] = "cn=admin"; + char filter[MAXLEN+1]; + int rc; + LDAPMessage *res; struct timeval timeout; + + memset(filter, 0, MAXLEN+1); + snprintf(filter, MAXLEN, "%s=%s", nickserv_conf.ldap_field_account, account); /* Now we do a search; */ timeout.tv_usec = 0; - timeout.tv_sec = 5; - if( ldap_search_st(ld, base, LDAP_SCOPE_ONELEVEL, filter, NULL, 0, &timeout, &res) != LDAP_SUCCESS) { - log_module(MAIN_LOG, LOG_ERROR, "search failed: %s %s\n", base, filter); - exit(1); + timeout.tv_sec = nickserv_conf.ldap_timeout; + if(!admin_bind && LDAP_SUCCESS != ( rc = ldap_do_admin_bind())) { + log_module(MAIN_LOG, LOG_ERROR, "failed to bind as admin"); + return rc; + } + if( (rc = ldap_search_st(ld, nickserv_conf.ldap_base, LDAP_SCOPE_ONELEVEL, filter, NULL, 0, &timeout, &res)) != LDAP_SUCCESS) { + log_module(MAIN_LOG, LOG_ERROR, "search failed: %s %s: %s", nickserv_conf.ldap_base, filter, ldap_err2string(rc)); + return(rc); } - log_module(MAIN_LOG, LOG_DEBUG, "Search successfull! %s %s\n", base, filter); - log_module(MAIN_LOG, LOG_DEBUG, "Got %d entries\n", ldap_count_entries(ld, res)); - { - LDAPMessage *entry; - char **value; - entry = ldap_first_entry(ld, res); - value = ldap_get_values(ld, entry, "cn"); - log_module(MAIN_LOG, LOG_DEBUG, "cn: %s\n", value[0]); - value = ldap_get_values(ld, entry, "description"); - log_module(MAIN_LOG, LOG_DEBUG, "Description: %s\n", value[0]); - value = ldap_get_values(ld, entry, "userPassword"); - log_module(MAIN_LOG, LOG_DEBUG, "pass: %s\n", value ? value[0] : "error"); + log_module(MAIN_LOG, LOG_DEBUG, "Search successfull! %s %s\n", nickserv_conf.ldap_base, filter); + if(ldap_count_entries(ld, res) != 1) { + log_module(MAIN_LOG, LOG_DEBUG, "LDAP search got %d entries when looking for %s", ldap_count_entries(ld, res), account); + return(LDAP_OTHER); /* Search was a success, but user not found.. */ } + log_module(MAIN_LOG, LOG_DEBUG, "LDAP search got %d entries", ldap_count_entries(ld, res)); + *entry = ldap_first_entry(ld, res); + return(rc); +} + +/* queries the ldap server for account.. + * if a single account match is found, + * email is allocated and set to the email address + * and returns LDAP_SUCCESS. returns LDAP_OTHER if + * 0 or 2+ entries are matched, or the proper ldap error + * code for other errors. + */ +int ldap_get_user_info(char *account, char **email) +{ + int rc; + char **value; + LDAPMessage *entry, *res; + if(email) + *email = NULL; + if( (rc = ldap_search_user(account, &res)) == LDAP_SUCCESS) { + entry = ldap_first_entry(ld, res); + value = ldap_get_values(ld, entry, nickserv_conf.ldap_field_email); + if(!value) { + return(LDAP_OTHER); + } + if(email) + *email = strdup(value[0]); + log_module(MAIN_LOG, LOG_DEBUG, "%s: %s\n", nickserv_conf.ldap_field_email, value[0]); + /* + value = ldap_get_values(ld, entry, "description"); + log_module(MAIN_LOG, LOG_DEBUG, "Description: %s\n", value[0]); + value = ldap_get_values(ld, entry, "userPassword"); + log_module(MAIN_LOG, LOG_DEBUG, "pass: %s\n", value ? value[0] : "error"); + */ + } + return(rc); +} + /* ldap_result(); ldap_first_entry(); @@ -149,16 +205,13 @@ LDAPMessage ldap_search_user(char uid) ldap_parse_result(); ldap_unbind_ext(); - */ /* get errors with ldap_err2string(); */ -} -#endif /********* base64 stuff ***********/ -unsigned char *pack(char *str, unsigned int *len) +unsigned char *pack(const char *str, unsigned int *len) { int nibbleshift = 4; int first = 1; @@ -167,7 +220,7 @@ unsigned char *pack(char *str, unsigned int *len) int outputpos = -1; memset(buf, 0, MAXLEN+1); - v = str; + v = (char *)str; while(*v) { char n = *(v++); @@ -219,7 +272,7 @@ char *base64_encode(const unsigned char *str, int length, int *ret_length) return NULL; } - result = (char *)calloc(((length + 2) / 3) * 4, sizeof(char)); + result = (char *)calloc((((length + 2) / 3) * 4)+1, sizeof(char)); p = result; while (length > 2) { /* keep going until we have less than 24 bits */ @@ -270,14 +323,12 @@ char **make_object_vals() return object_vals; } -char *make_password(const char *password) +char *make_password(const char *crypted) { char *base64pass; - char crypted[MD5_CRYPT_LENGTH+1]; unsigned char *packed; unsigned int len; char *passbuf; - cryptpass(password, crypted); packed = pack(crypted, &len); base64pass = base64_encode(packed, len, NULL); @@ -343,17 +394,7 @@ LDAPMod **make_mods_add(const char *account, const char *password, const char *e return mods; } -int ldap_do_admin_bind() -{ - if(!(nickserv_conf.ldap_admin_dn && *nickserv_conf.ldap_admin_dn && - nickserv_conf.ldap_admin_pass && *nickserv_conf.ldap_admin_pass)) { - log_module(MAIN_LOG, LOG_ERROR, "Tried to admin bind, but no admin credentials configured in config file. ldap_admin_dn/ldap_admin_pass"); - return LDAP_OTHER; /* not configured to do this */ - } - return(ldap_do_bind(nickserv_conf.ldap_admin_dn, nickserv_conf.ldap_admin_pass)); -} - -int ldap_do_add(const char *account, const char *password, const char *email) +int ldap_do_add(const char *account, const char *crypted, const char *email) { char newdn[MAXLEN]; LDAPMod **mods; @@ -361,22 +402,22 @@ int ldap_do_add(const char *account, const char *password, const char *email) int num_mods; char *passbuf; - if(LDAP_SUCCESS != ( rc = ldap_do_admin_bind())) { + if(!admin_bind && LDAP_SUCCESS != ( rc = ldap_do_admin_bind())) { log_module(MAIN_LOG, LOG_ERROR, "failed to bind as admin"); return rc; } - passbuf = make_password(password); + passbuf = make_password(crypted); snprintf(newdn, MAXLEN-1, nickserv_conf.ldap_dn_fmt, account); - mods = make_mods_add(account, password, email, &num_mods); + mods = make_mods_add(account, passbuf, email, &num_mods); if(!mods) { log_module(MAIN_LOG, LOG_ERROR, "Error building mods for ldap_add"); return LDAP_OTHER; } rc = ldap_add_ext_s(ld, newdn, mods, NULL, NULL); - if(rc != LDAP_SUCCESS) { + if(rc != LDAP_SUCCESS && rc!= LDAP_ALREADY_EXISTS) { log_module(MAIN_LOG, LOG_ERROR, "Error adding ldap account: %s -- %s", account, ldap_err2string(rc)); - return rc; + // return rc; } //ldap_unbind_s(ld); for(i = 0; i < num_mods; i++) { @@ -391,6 +432,13 @@ int ldap_do_add(const char *account, const char *password, const char *email) int ldap_delete_account(char *account) { char dn[MAXLEN]; + int rc; + + if(!admin_bind && LDAP_SUCCESS != ( rc = ldap_do_admin_bind())) { + log_module(MAIN_LOG, LOG_ERROR, "failed to bind as admin"); + return rc; + } + memset(dn, 0, MAXLEN); snprintf(dn, MAXLEN-1, nickserv_conf.ldap_dn_fmt, account); return(ldap_delete_s(ld, dn)); @@ -401,7 +449,7 @@ int ldap_rename_account(char *oldaccount, char *newaccount) char dn[MAXLEN], newdn[MAXLEN]; int rc; - if(LDAP_SUCCESS != ( rc = ldap_do_admin_bind())) { + if(!admin_bind && LDAP_SUCCESS != ( rc = ldap_do_admin_bind())) { log_module(MAIN_LOG, LOG_ERROR, "failed to bind as admin"); return rc; } @@ -415,7 +463,7 @@ int ldap_rename_account(char *oldaccount, char *newaccount) rc = ldap_modrdn2_s(ld, dn, newdn, true); if(rc != LDAP_SUCCESS) { log_module(MAIN_LOG, LOG_ERROR, "Error modifying ldap account: %s -- %s", oldaccount, ldap_err2string(rc)); - return rc; + //return rc; } return rc; @@ -425,7 +473,7 @@ LDAPMod **make_mods_modify(const char *password, const char *email, int *num_mod { static char *password_vals[] = { NULL, NULL }; static char *email_vals[] = { NULL, NULL }; - int num_mods = 1; + int num_mods = 0; int i; /* TODO: take this from nickserv_conf.ldap_add_objects */ LDAPMod **mods; @@ -435,8 +483,14 @@ LDAPMod **make_mods_modify(const char *password, const char *email, int *num_mod if(!(nickserv_conf.ldap_field_password && *nickserv_conf.ldap_field_password)) return 0; /* password required */ + /* if(email && *email && nickserv_conf.ldap_field_email && *nickserv_conf.ldap_field_email) num_mods++; + */ + if(password) + num_mods++; + if(email) + num_mods++; mods = ( LDAPMod ** ) malloc(( num_mods + 1 ) * sizeof( LDAPMod * )); for( i = 0; i < num_mods; i++) { @@ -480,7 +534,7 @@ int ldap_do_modify(const char *account, const char *password, const char *email) int num_mods; char *passbuf = NULL; - if(LDAP_SUCCESS != ( rc = ldap_do_admin_bind())) { + if(!admin_bind && LDAP_SUCCESS != ( rc = ldap_do_admin_bind())) { log_module(MAIN_LOG, LOG_ERROR, "failed to bind as admin"); return rc; } @@ -492,13 +546,13 @@ int ldap_do_modify(const char *account, const char *password, const char *email) snprintf(dn, MAXLEN-1, nickserv_conf.ldap_dn_fmt, account); mods = make_mods_modify(passbuf, email, &num_mods); if(!mods) { - log_module(MAIN_LOG, LOG_ERROR, "Error building mods for ldap_add"); + log_module(MAIN_LOG, LOG_ERROR, "Error building mods for ldap_do_modify"); return LDAP_OTHER; } rc = ldap_modify_s(ld, dn, mods); if(rc != LDAP_SUCCESS) { - log_module(MAIN_LOG, LOG_ERROR, "Error adding ldap account: %s -- %s", account, ldap_err2string(rc)); - return rc; + log_module(MAIN_LOG, LOG_ERROR, "Error modifying ldap account: %s -- %s", account, ldap_err2string(rc)); + // return rc; } for(i = 0; i < num_mods; i++) { free(mods[i]->mod_type); @@ -510,8 +564,96 @@ int ldap_do_modify(const char *account, const char *password, const char *email) return rc; } +LDAPMod **make_mods_group(const char *account, int operation, int *num_mods_ret) +{ + static char *uid_vals[] = { NULL, NULL }; + int num_mods = 1; + int i; + /* TODO: take this from nickserv_conf.ldap_add_objects */ + LDAPMod **mods; + + uid_vals[0] = (char *) account; + + if(!(nickserv_conf.ldap_field_group_member && *nickserv_conf.ldap_field_group_member)) + return 0; /* password required */ + + mods = ( LDAPMod ** ) malloc(( num_mods + 1 ) * sizeof( LDAPMod * )); + for( i = 0; i < num_mods; i++) { + mods[i] = (LDAPMod *) malloc(sizeof(LDAPMod)); + memset(mods[i], 0, sizeof(LDAPMod)); + } + + i = 0; + mods[i]->mod_op = operation; + mods[i]->mod_type = strdup(nickserv_conf.ldap_field_group_member); + mods[i]->mod_values = uid_vals; + i++; + mods[i] = NULL; + *num_mods_ret = num_mods; + return mods; +} + + +int ldap_add2group(char *account, const char *group) +{ + LDAPMod **mods; + int num_mods; + int rc, i; + + if(!admin_bind && LDAP_SUCCESS != ( rc = ldap_do_admin_bind())) { + log_module(MAIN_LOG, LOG_ERROR, "failed to bind as admin"); + return rc; + } + mods = make_mods_group(account, LDAP_MOD_ADD, &num_mods); + if(!mods) { + log_module(MAIN_LOG, LOG_ERROR, "Error building mods for add2group"); + return LDAP_OTHER; + } + rc = ldap_modify_s(ld, group, mods); + if(rc != LDAP_SUCCESS && rc != LDAP_TYPE_OR_VALUE_EXISTS) { + log_module(MAIN_LOG, LOG_ERROR, "Error adding %s to group %s: %s", account, group, ldap_err2string(rc)); + return rc; + } + for(i = 0; i < num_mods; i++) { + free(mods[i]->mod_type); + free(mods[i]); + } + free(mods); + return rc; +} + +int ldap_delfromgroup(char *account, const char *group) +{ + LDAPMod **mods; + int num_mods; + int rc, i; + + if(!admin_bind && LDAP_SUCCESS != ( rc = ldap_do_admin_bind())) { + log_module(MAIN_LOG, LOG_ERROR, "failed to bind as admin"); + return rc; + } + mods = make_mods_group(account, LDAP_MOD_DELETE, &num_mods); + if(!mods) { + log_module(MAIN_LOG, LOG_ERROR, "Error building mods for delfromgroup"); + return LDAP_OTHER; + } + rc = ldap_modify_s(ld, group, mods); + if(rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_ATTRIBUTE) { + log_module(MAIN_LOG, LOG_ERROR, "Error removing %s from group %s: %s", account, group, ldap_err2string(rc)); + return rc; + } + for(i = 0; i < num_mods; i++) { + free(mods[i]->mod_type); + free(mods[i]); + } + free(mods); + return rc; +} + + void ldap_close() { + admin_bind = false; ldap_unbind(ld); }