155 cxstring uidAttributes = serverconfig_object_directive_value(node, cx_str("UidAttributes")); |
155 cxstring uidAttributes = serverconfig_object_directive_value(node, cx_str("UidAttributes")); |
156 cxstring groupSearchFilter = serverconfig_object_directive_value(node, cx_str("GroupSearchFilter")); |
156 cxstring groupSearchFilter = serverconfig_object_directive_value(node, cx_str("GroupSearchFilter")); |
157 cxstring memberAttributes = serverconfig_object_directive_value(node, cx_str("MemberAttributes")); |
157 cxstring memberAttributes = serverconfig_object_directive_value(node, cx_str("MemberAttributes")); |
158 cxstring memberType = serverconfig_object_directive_value(node, cx_str("MemberType")); |
158 cxstring memberType = serverconfig_object_directive_value(node, cx_str("MemberType")); |
159 cxstring enableGroups = serverconfig_object_directive_value(node, cx_str("EnableGroups")); |
159 cxstring enableGroups = serverconfig_object_directive_value(node, cx_str("EnableGroups")); |
160 cxstring userNameIsDn = serverconfig_object_directive_value(node, cx_str("UserNameIsDn")); |
160 cxstring userNameIsDn = serverconfig_object_directive_value(node, cx_str("UserNameIsDn")); |
161 |
161 |
162 if(!resource.ptr) { |
162 if(!resource.ptr) { |
163 // TODO: create resource pool |
163 // TODO: create resource pool |
164 } else { |
164 } else { |
165 authdb->config.resource = resource.ptr; |
165 authdb->config.resource = cx_strdup_a(cfg->a, resource).ptr; |
|
166 if(!authdb->config.resource) return NULL; |
166 } |
167 } |
167 |
168 |
168 if(!basedn.ptr) { |
169 if(!basedn.ptr) { |
169 log_ereport(LOG_FAILURE, "ldap authdb %s: basedn is required", name); |
170 log_ereport(LOG_FAILURE, "ldap authdb %s: basedn is required", name); |
170 return NULL; |
171 return NULL; |
171 } |
172 } |
172 authdb->config.basedn = basedn.ptr; |
173 authdb->config.basedn = cx_strdup_a(cfg->a, basedn).ptr; |
|
174 if(!authdb->config.basedn) return NULL; |
173 |
175 |
174 // optional config |
176 // optional config |
175 if(binddn.ptr) { |
177 if(binddn.ptr) { |
176 if(!bindpw.ptr) { |
178 if(!bindpw.ptr) { |
177 log_ereport(LOG_FAILURE, "ldap authdb %s: binddn specified, but no bindpw", name); |
179 log_ereport(LOG_FAILURE, "ldap authdb %s: binddn specified, but no bindpw", name); |
178 return NULL; |
180 return NULL; |
179 } |
181 } |
180 |
182 |
181 authdb->config.binddn = binddn.ptr; |
183 authdb->config.binddn = cx_strdup_a(cfg->a, binddn).ptr; |
182 authdb->config.bindpw = bindpw.ptr; |
184 authdb->config.bindpw = cx_strdup_a(cfg->a, bindpw).ptr; |
183 } |
185 |
|
186 if(!authdb->config.binddn || !authdb->config.bindpw) { |
|
187 return NULL; |
|
188 } |
|
189 } |
|
190 |
184 |
191 |
185 if(userSearchFilter.ptr) { |
192 if(userSearchFilter.ptr) { |
186 authdb->config.userSearchFilter = userSearchFilter.ptr; |
193 authdb->config.userSearchFilter = cx_strdup_a(cfg->a, userSearchFilter).ptr; |
187 } |
194 } |
188 if(uidAttributes.ptr) { |
195 if(uidAttributes.ptr) { |
189 authdb->config.numUidAttributes = cx_strsplit_a( |
196 cxmutstr uidAttributesCopy = cx_strdup_a(cfg->a, uidAttributes); |
190 cfg->a, |
197 if(uidAttributesCopy.ptr) { |
191 uidAttributes, |
198 authdb->config.numUidAttributes = cx_strsplit_a( |
192 cx_str(","), |
199 cfg->a, |
193 1024, |
200 cx_strcast(uidAttributesCopy), |
194 &authdb->config.uidAttributes); |
201 cx_str(","), |
|
202 1024, |
|
203 &authdb->config.uidAttributes); |
|
204 } |
195 } |
205 } |
196 if(groupSearchFilter.ptr) { |
206 if(groupSearchFilter.ptr) { |
197 authdb->config.groupSearchFilter = groupSearchFilter.ptr; |
207 authdb->config.groupSearchFilter = groupSearchFilter.ptr; |
198 } |
208 } |
199 if(memberAttributes.ptr) { |
209 if(memberAttributes.ptr) { |
200 authdb->config.numMemberAttributes = cx_strsplit_a( |
210 cxmutstr memberAttributesCopy = cx_strdup_a(cfg->a, memberAttributes); |
201 cfg->a, |
211 if(memberAttributesCopy.ptr) { |
202 memberAttributes, |
212 authdb->config.numMemberAttributes = cx_strsplit_a( |
203 cx_str(","), |
213 cfg->a, |
204 1024, |
214 cx_strcast(memberAttributesCopy), |
205 &authdb->config.memberAttributes); |
215 cx_str(","), |
|
216 1024, |
|
217 &authdb->config.memberAttributes); |
|
218 } |
206 } |
219 } |
207 if(memberType.ptr) { |
220 if(memberType.ptr) { |
208 if(!cx_strcmp(memberType, cx_str("dn"))) { |
221 if(!cx_strcmp(memberType, cx_str("dn"))) { |
209 authdb->config.groupMemberType = WS_LDAP_GROUP_MEMBER_DN; |
222 authdb->config.groupMemberType = WS_LDAP_GROUP_MEMBER_DN; |
210 } else if(cx_strcmp(memberType, cx_str("uid"))) { |
223 } else if(!cx_strcmp(memberType, cx_str("uid"))) { |
211 authdb->config.groupMemberType = WS_LDAP_GROUP_MEMBER_UID; |
224 authdb->config.groupMemberType = WS_LDAP_GROUP_MEMBER_UID; |
212 } else { |
225 } else { |
213 log_ereport(LOG_FAILURE, "ldap authdb %s: unknown MemberType %s", name, memberType.ptr); |
226 log_ereport(LOG_FAILURE, "ldap authdb %s: unknown MemberType %s", name, memberType.ptr); |
214 return NULL; |
227 return NULL; |
215 } |
228 } |
255 } |
268 } |
256 |
269 |
257 return ldap; |
270 return ldap; |
258 } |
271 } |
259 |
272 |
|
273 static LDAPUser* ldap_msg_to_user( |
|
274 Session *sn, |
|
275 Request *rq, |
|
276 LDAPAuthDB *authdb, |
|
277 LDAP *ldap, |
|
278 LDAPMessage *msg) |
|
279 { |
|
280 CxAllocator *a = pool_allocator(sn->pool); |
|
281 |
|
282 LDAPUser *user = pool_malloc(sn->pool, sizeof(LDAPUser)); |
|
283 if(!user) { |
|
284 return NULL; |
|
285 } |
|
286 |
|
287 // get dn |
|
288 char *ldap_dn = ldap_get_dn(ldap, msg); |
|
289 if(!ldap_dn) { |
|
290 return NULL; |
|
291 } |
|
292 char *dn = pool_strdup(sn->pool, ldap_dn); |
|
293 ldap_memfree(ldap_dn); |
|
294 if(!dn) { |
|
295 return NULL; |
|
296 } |
|
297 |
|
298 // get uid |
|
299 char *uid = NULL; |
|
300 |
|
301 // values of configured UidAttributes |
|
302 size_t numUidAttributes = authdb->config.numUidAttributes; |
|
303 cxmutstr *uid_values = pool_calloc(sn->pool, authdb->config.numUidAttributes, sizeof(cxmutstr)); |
|
304 if(!uid_values) { |
|
305 return NULL; |
|
306 } |
|
307 |
|
308 |
|
309 BerElement *ber = NULL; |
|
310 char *attribute = ldap_first_attribute(ldap, msg, &ber); |
|
311 while(attribute) { |
|
312 cxstring attr = cx_str(attribute); |
|
313 for(int i=0;i<numUidAttributes;i++) { |
|
314 // check if the attribute is one of the uid attributes |
|
315 if(!uid_values[i].ptr && !cx_strcmp(attr, authdb->config.uidAttributes[i])) { |
|
316 // copy value to uid_values |
|
317 struct berval **values = ldap_get_values_len(ldap, msg, attribute); |
|
318 if(values) { |
|
319 int count = ldap_count_values_len(values); |
|
320 if(count > 0) { |
|
321 cxstring attr_val = cx_strn(values[0]->bv_val, values[0]->bv_len); |
|
322 uid_values[i] = cx_strdup_a(a, attr_val); |
|
323 } else { |
|
324 log_ereport(LOG_FAILURE, "ldap user: dn: %s attribute %s: no values", dn, attribute); |
|
325 } |
|
326 ldap_value_free_len(values); |
|
327 } |
|
328 } |
|
329 } |
|
330 if(uid_values[0].ptr) { |
|
331 // if we found a value for the first attribute, we can use that |
|
332 break; |
|
333 } |
|
334 |
|
335 ldap_memfree(attribute); |
|
336 attribute = ldap_next_attribute(ldap, msg, ber); |
|
337 } |
|
338 |
|
339 |
|
340 // use first value as uid |
|
341 for(int i=0;i<numUidAttributes;i++) { |
|
342 if(uid_values[i].ptr) { |
|
343 if(!uid) { |
|
344 uid = uid_values[i].ptr; |
|
345 } else { |
|
346 cxFree(a, uid_values[i].ptr); |
|
347 } |
|
348 } |
|
349 } |
|
350 pool_free(sn->pool, uid_values); |
|
351 |
|
352 // get user name |
|
353 char *username; |
|
354 if(authdb->config.userNameIsDN) { |
|
355 username = dn; |
|
356 } else { |
|
357 username = uid; |
|
358 } |
|
359 |
|
360 if(!username) { |
|
361 return NULL; |
|
362 } |
|
363 |
|
364 user->authdb = authdb; |
|
365 user->user.verify_password = ldap_user_verify_password; |
|
366 user->user.check_group = ldap_user_check_group; |
|
367 user->user.free = ldap_user_free; |
|
368 user->user.name = username; |
|
369 user->sn = sn; |
|
370 user->rq = rq; |
|
371 |
|
372 // TODO: get uid/gid from ldap |
|
373 user->user.uid = -1; |
|
374 user->user.gid = -1; |
|
375 |
|
376 user->ldap = ldap; |
|
377 user->userdn = dn; |
|
378 user->uid_attr = uid; |
|
379 |
|
380 return user; |
|
381 } |
|
382 |
260 User* ldap_get_user(AuthDB *db, Session *sn, Request *rq, const char *username) { |
383 User* ldap_get_user(AuthDB *db, Session *sn, Request *rq, const char *username) { |
261 LDAPAuthDB *authdb = (LDAPAuthDB*) db; |
384 LDAPAuthDB *authdb = (LDAPAuthDB*) db; |
262 LDAPConfig *config = &authdb->config; |
385 LDAPConfig *config = &authdb->config; |
|
386 CxAllocator *a = pool_allocator(sn->pool); |
263 |
387 |
264 LDAP *ld = get_ldap_session(sn, rq, authdb); |
388 LDAP *ld = get_ldap_session(sn, rq, authdb); |
265 if (ld == NULL) { |
389 if (ld == NULL) { |
266 fprintf(stderr, "ldap_init failed\n"); |
|
267 return NULL; |
390 return NULL; |
268 } |
391 } |
269 |
392 |
270 // get the user dn |
393 // get the user dn |
271 // TODO: use config for filter |
394 cxstring userSearch = cx_str(config->userSearchFilter); |
272 // TODO: use asprintf |
395 cxmutstr filter = cx_strreplace_a(a, userSearch, cx_str("%s"), cx_str(username)); |
273 char filter[128]; |
396 if(!filter.ptr) { |
274 snprintf(filter, 128, "(uid=%s)", username); |
397 return NULL; |
275 |
398 } |
|
399 |
|
400 log_ereport(LOG_DEBUG, "ldap_get_user: filter: %s", filter.ptr); |
|
401 |
276 LDAPMessage *result; |
402 LDAPMessage *result; |
277 struct timeval timeout; |
403 struct timeval timeout; |
278 timeout.tv_sec = 8; |
404 timeout.tv_sec = 8; // TODO: add config parameter for timeout |
279 timeout.tv_usec = 0; |
405 timeout.tv_usec = 0; |
280 int r = ldap_search_ext_s( |
406 int r = ldap_search_ext_s( |
281 ld, |
407 ld, |
282 config->basedn, |
408 config->basedn, |
283 LDAP_SCOPE_SUBTREE, |
409 LDAP_SCOPE_SUBTREE, |
284 filter, |
410 filter.ptr, |
285 NULL, |
411 NULL, |
286 0, |
412 0, |
287 NULL, // server controls |
413 NULL, // server controls |
288 NULL, // client controls |
414 NULL, // client controls |
289 &timeout, |
415 &timeout, |
290 1, // size limit |
416 2, // size limit |
291 &result); |
417 &result); |
292 if (r != LDAP_SUCCESS) { |
418 cxFree(a, filter.ptr); |
293 //ws_ldap_close(ld); |
419 if(r != LDAP_SUCCESS) { |
294 |
420 if(result) { |
|
421 ldap_msgfree(result); |
|
422 } |
295 log_ereport(LOG_FAILURE, "ldap_get_user: search failed: %s", ldap_err2string(r)); |
423 log_ereport(LOG_FAILURE, "ldap_get_user: search failed: %s", ldap_err2string(r)); |
296 return NULL; |
424 return NULL; |
297 } |
425 } |
|
426 if(!result) { |
|
427 // not sure if this can happen |
|
428 log_ereport(LOG_FAILURE, "ldap_get_user: search failed: no result"); |
|
429 return NULL; |
|
430 } |
298 |
431 |
299 LDAPMessage *msg = ldap_first_entry(ld, result); |
432 LDAPMessage *msg = ldap_first_entry(ld, result); |
300 if (msg) { |
433 LDAPUser *user = NULL; |
301 LDAPUser *user = pool_malloc(sn->pool, sizeof(LDAPUser)); |
434 if(msg) { |
302 if (user != NULL) { |
435 if(ldap_count_entries(ld, msg) > 1) { |
303 user->authdb = authdb; |
436 log_ereport(LOG_FAILURE, "ldap_get_user: more than one search result"); |
304 user->user.verify_password = ldap_user_verify_password; |
437 } else { |
305 user->user.check_group = ldap_user_check_group; |
438 user = ldap_msg_to_user(sn, rq, authdb, ld, msg); |
306 user->user.free = ldap_user_free; |
439 } |
307 user->user.name = pool_strdup(sn->pool, username); |
440 } |
308 user->sn = sn; |
441 ldap_msgfree(result); |
309 user->rq = rq; |
442 |
310 |
443 return (User*)user; |
311 // TODO: get uid/gid from ldap |
|
312 user->user.uid = -1; |
|
313 user->user.gid = -1; |
|
314 |
|
315 user->ldap = ld; |
|
316 user->userdn = ldap_get_dn(ld, msg); |
|
317 |
|
318 ldap_msgfree(result); |
|
319 |
|
320 return (User*)user; |
|
321 } |
|
322 } |
|
323 |
|
324 //ws_ldap_close(ld); |
|
325 return NULL; |
|
326 } |
444 } |
327 |
445 |
328 LDAPGroup* ldap_get_group(Session *sn, Request *rq, LDAPAuthDB *authdb, const char *group) { |
446 LDAPGroup* ldap_get_group(Session *sn, Request *rq, LDAPAuthDB *authdb, const char *group) { |
329 printf("ldap_get_group: %s\n", group); |
447 printf("ldap_get_group: %s\n", group); |
330 |
448 |