X-Git-Url: https://jfr.im/git/irc/evilnet/x3.git/blobdiff_plain/8a729617ec6b967a46aee3226fdc5c4d1d5d4a71..0b401fb654b69fd9649954a9bdd5ff041971e62d:/src/x3ldap.c diff --git a/src/x3ldap.c b/src/x3ldap.c index 23551fc..931ea52 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, @@ -17,6 +17,13 @@ * along with srvx; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + * + * INSTRUCTIONS: + * * Setup an ldap server. Add inetOrgAnon to the schema (it is in tools/ldap) + * * Make sure ldap is enabled at compile time (debian needs libldap2-dev package) + * * Enable ldap in x3.conf and set everything + * * Initial import: you can use the secret authserv search action add2ldap + * to get your users into ldap. /msg authserv search add2ldap account * * * TODO: * * get queries working in static existance, so i understand how it works @@ -29,10 +36,13 @@ #include "config.h" #ifdef WITH_LDAP +#define LDAP_DEPRECATED 1 + #include #include #include +#include "base64.h" #include "conf.h" #include "global.h" #include "log.h" @@ -42,19 +52,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 +92,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) { @@ -96,16 +109,20 @@ unsigned int ldap_do_bind( const char *dn, const char *pass) } 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 */ } - return(ldap_do_bind(nickserv_conf.ldap_admin_dn, nickserv_conf.ldap_admin_pass)); + 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) +unsigned int ldap_check_auth( const char *account, const char *pass) { char buff[MAXLEN]; @@ -114,11 +131,12 @@ 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); } -int ldap_search_user(char *account, LDAPMessage **entry) +int ldap_search_user(const char *account, LDAPMessage **entry) { char filter[MAXLEN+1]; @@ -133,8 +151,8 @@ int ldap_search_user(char *account, LDAPMessage **entry) Now we do a search; */ timeout.tv_usec = 0; - timeout.tv_sec = 5; - if(LDAP_SUCCESS != ( rc = ldap_do_admin_bind())) { + 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; } @@ -144,7 +162,7 @@ int ldap_search_user(char *account, LDAPMessage **entry) } 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_ERROR, "LDAP search got %d entries when looking for %s", ldap_count_entries(ld, res), account); + 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)); @@ -159,20 +177,23 @@ int ldap_search_user(char *account, LDAPMessage **entry) * 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 ldap_get_user_info(const char *account, char **email) { int rc; - char **value; + struct berval **value; LDAPMessage *entry, *res; - *email = NULL; + 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); + value = ldap_get_values_len(ld, entry, nickserv_conf.ldap_field_email); if(!value) { return(LDAP_OTHER); } - *email = strdup(value[0]); - log_module(MAIN_LOG, LOG_DEBUG, "%s: %s\n", nickserv_conf.ldap_field_email, value[0]); + if(email) + *email = strdup(value[0]->bv_val); + log_module(MAIN_LOG, LOG_DEBUG, "%s: %s\n", nickserv_conf.ldap_field_email, value[0]->bv_val); + ldap_value_free_len(value); /* value = ldap_get_values(ld, entry, "description"); log_module(MAIN_LOG, LOG_DEBUG, "Description: %s\n", value[0]); @@ -201,7 +222,7 @@ int ldap_get_user_info(char *account, char **email) /********* 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; @@ -210,7 +231,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++); @@ -238,64 +259,6 @@ unsigned char *pack(char *str, unsigned int *len) return(buf); } - -/* from php5 sources */ -static char base64_table[] = - { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0' - }; -static char base64_pad = '='; - -char *base64_encode(const unsigned char *str, int length, int *ret_length) -{ - const unsigned char *current = str; - char *p; - char *result; - - if ((length + 2) < 0 || ((length + 2) / 3) >= (1 << (sizeof(int) * 8 - 2))) { - if (ret_length != NULL) { - *ret_length = 0; - } - return NULL; - } - - result = (char *)calloc(((length + 2) / 3) * 4, sizeof(char)); - p = result; - - while (length > 2) { /* keep going until we have less than 24 bits */ - *p++ = base64_table[current[0] >> 2]; - *p++ = base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)]; - *p++ = base64_table[((current[1] & 0x0f) << 2) + (current[2] >> 6)]; - *p++ = base64_table[current[2] & 0x3f]; - - current += 3; - length -= 3; /* we just handle 3 octets of data */ - } - - /* now deal with the tail end of things */ - if (length != 0) { - *p++ = base64_table[current[0] >> 2]; - if (length > 1) { - *p++ = base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)]; - *p++ = base64_table[(current[1] & 0x0f) << 2]; - *p++ = base64_pad; - } else { - *p++ = base64_table[(current[0] & 0x03) << 4]; - *p++ = base64_pad; - *p++ = base64_pad; - } - } - if (ret_length != NULL) { - *ret_length = (int)(p - result); - } - *p = '\0'; - return result; -} - - char **make_object_vals() { unsigned int y; @@ -304,26 +267,25 @@ char **make_object_vals() if(object_vals) free(object_vals); - object_vals = malloc(sizeof( *object_vals ) * nickserv_conf.ldap_object_classes->used); + object_vals = malloc(sizeof( *object_vals ) * (nickserv_conf.ldap_object_classes->used+1)); for(y = 0; y < nickserv_conf.ldap_object_classes->used; y++) { object_vals[y] = nickserv_conf.ldap_object_classes->list[y]; } object_vals[y] = NULL; return object_vals; + /* NOTE: The return value of this is only good until the next call to it. */ } -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); + base64_encode_alloc((char *)packed, len, &base64pass); passbuf = malloc(strlen(base64pass) + 1 + 5); strcpy(passbuf, "{MD5}"); strcat(passbuf, base64pass); @@ -338,15 +300,26 @@ LDAPMod **make_mods_add(const char *account, const char *password, const char *e static char *account_vals[] = { NULL, NULL }; static char *password_vals[] = { NULL, NULL }; static char *email_vals[] = { NULL, NULL }; - int num_mods = 3; + int num_mods = 2; int i; + int mod = 0; /* TODO: take this from nickserv_conf.ldap_add_objects */ LDAPMod **mods; static char **object_vals; + + account_vals[0] = NULL; + account_vals[1] = NULL; + password_vals[0] = NULL; + password_vals[1] = NULL; + email_vals[0] = NULL; + email_vals[1] = NULL; object_vals = make_object_vals(); account_vals[0] = (char *) account; - password_vals[0] = (char *) password; + if (password != NULL) { + password_vals[0] = (char *) password; + num_mods++; + } email_vals[0] = (char *) email; if(!(nickserv_conf.ldap_field_account && *nickserv_conf.ldap_field_account)) @@ -362,54 +335,59 @@ LDAPMod **make_mods_add(const char *account, const char *password, const char *e memset(mods[i], 0, sizeof(LDAPMod)); } - mods[0]->mod_op = LDAP_MOD_ADD; - mods[0]->mod_type = strdup("objectclass"); - mods[0]->mod_values = object_vals; + mods[mod]->mod_op = LDAP_MOD_ADD; + mods[mod]->mod_type = strdup("objectclass"); + mods[mod]->mod_values = object_vals; + mod++; - mods[1]->mod_op = LDAP_MOD_ADD; - mods[1]->mod_type = strdup(nickserv_conf.ldap_field_account); - mods[1]->mod_values = account_vals; + mods[mod]->mod_op = LDAP_MOD_ADD; + mods[mod]->mod_type = strdup(nickserv_conf.ldap_field_account); + mods[mod]->mod_values = account_vals; + mod++; - mods[2]->mod_op = LDAP_MOD_ADD; - mods[2]->mod_type = strdup(nickserv_conf.ldap_field_password); - mods[2]->mod_values = password_vals; + if (password != NULL) { + mods[mod]->mod_op = LDAP_MOD_ADD; + mods[mod]->mod_type = strdup(nickserv_conf.ldap_field_password); + mods[mod]->mod_values = password_vals; + mod++; + } if(nickserv_conf.ldap_field_email && *nickserv_conf.ldap_field_email && email && *email) { - mods[3]->mod_op = LDAP_MOD_ADD; - mods[3]->mod_type = strdup(nickserv_conf.ldap_field_email); - mods[3]->mod_values = email_vals; - mods[4] = NULL; + mods[mod]->mod_op = LDAP_MOD_ADD; + mods[mod]->mod_type = strdup(nickserv_conf.ldap_field_email); + mods[mod]->mod_values = email_vals; + mod++; } - else - mods[3] = NULL; + mods[mod] = NULL; *num_mods_ret = num_mods; return mods; } -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; int rc, i; int num_mods; - char *passbuf; + 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; } - - passbuf = make_password(password); + + if (crypted != NULL) + 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, (crypted != NULL ? passbuf : crypted), 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++) { @@ -417,13 +395,21 @@ int ldap_do_add(const char *account, const char *password, const char *email) free(mods[i]); } free(mods); - free(passbuf); + if (crypted != NULL) + free(passbuf); return rc; } 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)); @@ -434,7 +420,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; } @@ -448,7 +434,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; @@ -503,6 +489,56 @@ LDAPMod **make_mods_modify(const char *password, const char *email, int *num_mod return mods; } +/* Save OpServ level to LDAP + * + * level - OpServ level + * + * A level of <0 will be treated as 0 + */ +int ldap_do_oslevel(const char *account, int level, int oldlevel) +{ + LDAPMod **mods; + static char *oslevel_vals[] = { NULL, NULL }; + char dn[MAXLEN], temp[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; + } + + if (level < 0) { + level = 0; + } + + snprintf(temp, MAXLEN-1, "%d", (level ? level : oldlevel)); + oslevel_vals[0] = (char *) temp; + + if(!(nickserv_conf.ldap_field_oslevel && *nickserv_conf.ldap_field_oslevel)) + return 0; + + snprintf(dn, MAXLEN-1, nickserv_conf.ldap_dn_fmt, account); + + mods = ( LDAPMod ** ) malloc(( 1 ) * sizeof( LDAPMod * )); + mods[0] = (LDAPMod *) malloc(sizeof(LDAPMod)); + memset(mods[0], 0, sizeof(LDAPMod)); + + mods[0]->mod_op = (level ? LDAP_MOD_REPLACE : LDAP_MOD_DELETE); + mods[0]->mod_type = strdup(nickserv_conf.ldap_field_oslevel); + mods[0]->mod_values = oslevel_vals; + mods[1] = NULL; + + rc = ldap_modify_s(ld, dn, mods); + if(rc != LDAP_SUCCESS) { + log_module(MAIN_LOG, LOG_ERROR, "Error modifying ldap OpServ level: %s -- %s", account, ldap_err2string(rc)); + //return rc; + } + free(mods[0]->mod_type); + free(mods[0]); + free(mods); + + return rc; +} /* Save email or password to server * @@ -519,7 +555,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; } @@ -531,13 +567,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); @@ -585,7 +621,7 @@ int ldap_add2group(char *account, const char *group) int num_mods; int rc, i; - 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; } @@ -595,7 +631,7 @@ int ldap_add2group(char *account, const char *group) return LDAP_OTHER; } rc = ldap_modify_s(ld, group, mods); - if(rc != LDAP_SUCCESS) { + 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; } @@ -613,7 +649,7 @@ int ldap_delfromgroup(char *account, const char *group) int num_mods; int rc, i; - 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; } @@ -623,7 +659,7 @@ int ldap_delfromgroup(char *account, const char *group) return LDAP_OTHER; } rc = ldap_modify_s(ld, group, mods); - if(rc != LDAP_SUCCESS) { + 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; } @@ -638,7 +674,23 @@ int ldap_delfromgroup(char *account, const char *group) void ldap_close() { - ldap_unbind(ld); + admin_bind = false; + ldap_unbind_ext(ld, NULL, NULL); +} + +/* queries the ldap server for account.. + * returns LDAP_SUCCESS if a match is found + * returns LDAP_OTHER if no match is found + * on error returns the proper ldap error + */ +int ldap_user_exists(const char *account) +{ + int rc; + LDAPMessage *res; + + rc = ldap_search_user(account, &res); + + return rc; } #endif