UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2013 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #ifdef __gnu_linux__ 30 #define _GNU_SOURCE 31 #endif 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <sys/time.h> 37 38 #include <ucx/utils.h> 39 40 #include "ldap_auth.h" 41 42 static void ws_ldap_close(LDAP *ldap) { 43 #ifdef SOLARIS 44 ldap_unbind(ldap); 45 #else 46 ldap_unbind_ext_s(ldap, NULL, NULL); 47 #endif 48 } 49 50 AuthDB* create_ldap_authdb(char *name, LDAPConfig *conf) { 51 LDAPAuthDB *authdb = malloc(sizeof(LDAPAuthDB)); 52 authdb->authdb.name = strdup(name); 53 authdb->authdb.get_user = ldap_get_user; 54 authdb->authdb.use_cache = 1; 55 authdb->config = *conf; 56 57 if (!authdb->config.usersearch) { 58 authdb->config.usersearch = "uid"; 59 } 60 if (!authdb->config.groupsearch) { 61 authdb->config.groupsearch = "uniquemember"; 62 } 63 64 // initialize group cache 65 authdb->groups.first = NULL; 66 authdb->groups.last = NULL; 67 authdb->groups.map = ucx_map_new(32); 68 69 return (AuthDB*) authdb; 70 } 71 72 LDAP* get_ldap_session(LDAPAuthDB *authdb) { 73 LDAPConfig *config = &authdb->config; 74 LDAP *ld = NULL; 75 76 #ifdef SOLARIS 77 ld = ldap_init(config->hostname, config->port); 78 #else 79 char *ldap_uri = NULL; 80 asprintf(&ldap_uri, "ldap://%s:%d", config->hostname, config->port); 81 int init_ret = ldap_initialize(&ld, ldap_uri); 82 free(ldap_uri); 83 if(init_ret) { 84 fprintf(stderr, "ldap_initialize failed\n"); 85 } 86 #endif 87 if(!ld) { 88 return NULL; 89 } 90 91 int ldapv = LDAP_VERSION3; 92 ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldapv); 93 94 // admin bind 95 struct berval cred; 96 cred.bv_val = config->bindpw; 97 cred.bv_len = strlen(config->bindpw); 98 struct berval *server_cred; 99 int r = ldap_sasl_bind_s( 100 ld, 101 config->binddn, 102 LDAP_SASL_SIMPLE, 103 &cred, 104 NULL, 105 NULL, 106 &server_cred); 107 if (r != LDAP_SUCCESS) { 108 ws_ldap_close(ld); 109 fprintf(stderr, "ldap_simple_bind_s failed: %s\n", ldap_err2string(r)); 110 return NULL; 111 } 112 113 return ld; 114 } 115 116 User* ldap_get_user(AuthDB *db, char *username) { 117 LDAPAuthDB *authdb = (LDAPAuthDB*) db; 118 LDAPConfig *config = &authdb->config; 119 120 LDAP *ld = get_ldap_session(authdb); 121 if (ld == NULL) { 122 fprintf(stderr, "ldap_init failed\n"); 123 return NULL; 124 } 125 126 // get the user dn 127 // TODO: use config for filter 128 // TODO: use asprintf 129 char filter[128]; 130 int s = snprintf(filter, 127, "uid=%s", username); 131 filter[s] = 0; 132 133 LDAPMessage *result; 134 struct timeval timeout; 135 timeout.tv_sec = 8; 136 timeout.tv_usec = 0; 137 int r = ldap_search_ext_s( 138 ld, 139 config->basedn, 140 LDAP_SCOPE_SUBTREE, 141 filter, 142 NULL, 143 0, 144 NULL, // server controls 145 NULL, // client controls 146 &timeout, 147 1, // size limit 148 &result); 149 if (r != LDAP_SUCCESS) { 150 ws_ldap_close(ld); 151 152 fprintf(stderr, "ldap_search_ext_s failed\n"); 153 return NULL; 154 } 155 156 LDAPMessage *msg = ldap_first_entry(ld, result); 157 if (msg) { 158 LDAPUser *user = malloc(sizeof(LDAPUser)); 159 if (user != NULL) { 160 user->authdb = authdb; 161 user->user.verify_password = ldap_user_verify_password; 162 user->user.check_group = ldap_user_check_group; 163 user->user.free = ldap_user_free; 164 user->user.name = username; // must not be freed 165 166 // TODO: get uid/gid from ldap 167 user->user.uid = -1; 168 user->user.gid = -1; 169 170 user->ldap = ld; 171 user->userdn = ldap_get_dn(ld, msg); 172 173 ldap_msgfree(result); 174 175 return (User*)user; 176 } 177 } 178 179 ws_ldap_close(ld); 180 return NULL; 181 } 182 183 LDAPGroup* ldap_get_group(LDAPAuthDB *authdb, char *group) { 184 printf("ldap_get_group: %s\n", group); 185 186 LDAPConfig *config = &authdb->config; 187 188 LDAP *ld = get_ldap_session(authdb); 189 if (ld == NULL) { 190 fprintf(stderr, "ldap_init failed\n"); 191 return NULL; 192 } 193 194 // get the user dn 195 // TODO: use config for filter 196 // TODO: use asprintf 197 char filter[128]; 198 int s = snprintf(filter, 127, "cn=%s", group); 199 filter[s] = 0; 200 201 LDAPMessage *result; 202 struct timeval timeout; 203 timeout.tv_sec = 8; 204 timeout.tv_usec = 0; 205 int r = ldap_search_ext_s( 206 ld, 207 config->basedn, 208 LDAP_SCOPE_SUBTREE, 209 filter, 210 NULL, 211 0, 212 NULL, // server controls 213 NULL, // client controls 214 &timeout, 215 1, // size limit 216 &result); 217 if (r != LDAP_SUCCESS) { 218 ws_ldap_close(ld); 219 220 fprintf(stderr, "ldap_search_ext_s failed\n"); 221 return NULL; 222 } 223 224 LDAPGroup *wsgroup = NULL; 225 LDAPMessage *msg = ldap_first_entry(ld, result); 226 if (msg) { 227 // create group object 228 wsgroup = malloc(sizeof(LDAPGroup)); 229 wsgroup->name = strdup(group); 230 wsgroup->members = NULL; 231 wsgroup->nmembers = 0; 232 wsgroup->update = 0; 233 wsgroup->next = NULL; 234 235 // get attributes 236 BerElement *ber = NULL; 237 char *attribute = attribute=ldap_first_attribute(ld, msg, &ber); 238 while(attribute != NULL) { 239 printf("attribute: %s\n", attribute); 240 if(!strcasecmp(attribute, "memberuid")) { 241 // get all memberuid values and add the users to the group obj 242 243 struct berval **values = ldap_get_values_len(ld, msg, attribute); 244 if(values) { 245 int count = ldap_count_values_len(values); 246 wsgroup->members = calloc(count, sizeof(LDAPMember)); 247 wsgroup->nmembers = count; 248 for(int i=0;i<count;i++) { 249 sstr_t member = sstrn( 250 values[i]->bv_val, 251 values[i]->bv_len); 252 wsgroup->members[i].name = sstrdup(member).ptr; 253 // TODO: uid? 254 printf("added member: %.*s\n", (int)member.length, member.ptr); 255 } 256 } 257 } 258 259 attribute = ldap_next_attribute(ld, msg, ber); 260 } 261 262 if(ber) { 263 //ldap_ber_free(ber, 0); 264 } 265 if(attribute) { 266 ldap_memfree(attribute); 267 } 268 } 269 270 ws_ldap_close(ld); 271 return wsgroup; 272 } 273 274 int ldap_user_verify_password(User *u, char *password) { 275 LDAPUser *user = (LDAPUser*)u; 276 277 //int r = ldap_simple_bind_s(user->ldap, user->userdn, password); 278 struct berval cred; 279 cred.bv_val = password; 280 cred.bv_len = strlen(password); 281 struct berval *server_cred; 282 int r = ldap_sasl_bind_s( 283 user->ldap, 284 user->userdn, 285 LDAP_SASL_SIMPLE, 286 &cred, 287 NULL, 288 NULL, 289 &server_cred); 290 if(r == LDAP_SUCCESS) { 291 printf("ldap password ok\n"); 292 return 1; 293 } else { 294 printf("ldap password not ok\n"); 295 return 0; 296 } 297 } 298 299 int ldap_user_check_group(User *u, char *group_str) { 300 LDAPUser *user = (LDAPUser*)u; 301 302 int ret = 0; 303 304 LDAPGroup *group = ldap_get_group(user->authdb, group_str); 305 for(int i=0;i<group->nmembers;i++) { 306 char *member = group->members[i].name; 307 if(!strcmp(member, u->name)) { 308 printf("is member\n"); 309 ret = 1; 310 } 311 } 312 313 // TODO: free or cache group 314 315 return ret; 316 } 317 318 void ldap_user_free(User *u) { 319 LDAPUser *user = (LDAPUser*)u; 320 ldap_memfree(user->userdn); 321 // TODO: use connection pool 322 ws_ldap_close(user->ldap); 323 free(user); 324 } 325