usrcache.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. *
  6. * License: GPL (version 3 or any later version).
  7. * See LICENSE for details.
  8. * END COPYRIGHT BLOCK **/
  9. #ifdef HAVE_CONFIG_H
  10. # include <config.h>
  11. #endif
  12. /* #define DBG_PRINT */
  13. #include <netsite.h>
  14. extern "C" {
  15. #include <secitem.h>
  16. }
  17. #include <base/crit.h>
  18. #include <ldaputil/errors.h>
  19. #include <libaccess/usrcache.h>
  20. #include <libaccess/las.h>
  21. #include <libaccess/authdb.h>
  22. #include "permhash.h"
  23. /* uid is unique within a database. The user cache tables are stored per
  24. * database. The following table maps a database name to the corresponding
  25. * user cache table. The user cache table is another hash table which stores
  26. * the UserCacheObj instances.
  27. */
  28. static PRHashTable *databaseUserCacheTable = 0;
  29. static time_t acl_usr_cache_lifetime = (time_t)120;
  30. static PRCList *usrobj_list = 0;
  31. static const int num_usrobj = 200;
  32. static CRITICAL usr_hash_crit = NULL; /* Controls user cache hash tables & */
  33. /* usrobj link list */
  34. static pool_handle_t *usrcache_pool = NULL;
  35. static PRHashTable *singleDbTable = 0;
  36. #define USEROBJ_PTR(l) \
  37. ((UserCacheObj*) ((char*) (l) - offsetof(UserCacheObj, list)))
  38. static void user_hash_crit_enter (void)
  39. {
  40. /* Caching may be disabled (usr_hash_crit will be NULL) */
  41. if (usr_hash_crit) crit_enter(usr_hash_crit);
  42. }
  43. static void user_hash_crit_exit (void)
  44. {
  45. /* Caching may be disabled (usr_hash_crit will be NULL) */
  46. if (usr_hash_crit) crit_exit(usr_hash_crit);
  47. }
  48. static void user_hash_crit_init (void)
  49. {
  50. usr_hash_crit = crit_init();
  51. }
  52. static PRHashNumber
  53. usr_cache_hash_cert(const void *key)
  54. {
  55. PRHashNumber h;
  56. const unsigned char *s;
  57. unsigned int i = 0;
  58. SECItem *derCert = (SECItem *)key;
  59. unsigned int len = derCert->len;
  60. h = 0;
  61. for (s = (const unsigned char *)derCert->data; i < len; s++, i++)
  62. h = (h >> 28) ^ (h << 4) ^ *s;
  63. return h;
  64. }
  65. static PRHashNumber
  66. usr_cache_hash_fn (const void *key)
  67. {
  68. UserCacheObj *usrObj = (UserCacheObj *)key;
  69. if (usrObj->derCert)
  70. return usr_cache_hash_cert(usrObj->derCert);
  71. else
  72. return PR_HashCaseString(usrObj->uid);
  73. }
  74. static int
  75. usr_cache_compare_certs(const void *v1, const void *v2)
  76. {
  77. const SECItem *c1 = (const SECItem *)v1;
  78. const SECItem *c2 = (const SECItem *)v2;
  79. return (c1->len == c2 ->len && !memcmp(c1->data, c2->data, c1->len));
  80. }
  81. static int
  82. usr_cache_compare_fn(const void *v1, const void *v2)
  83. {
  84. UserCacheObj *usrObj1 = (UserCacheObj *)v1;
  85. UserCacheObj *usrObj2 = (UserCacheObj *)v2;
  86. if (usrObj1->derCert && usrObj2->derCert)
  87. return usr_cache_compare_certs(usrObj1->derCert, usrObj2->derCert);
  88. else if (!usrObj1->derCert && !usrObj2->derCert)
  89. return PR_CompareCaseStrings(usrObj1->uid, usrObj1->uid);
  90. else
  91. return 0;
  92. }
  93. static PRHashTable *alloc_db2uid_table ()
  94. {
  95. return PR_NewHashTable(0,
  96. usr_cache_hash_fn,
  97. usr_cache_compare_fn,
  98. PR_CompareValues,
  99. &ACLPermAllocOps,
  100. usrcache_pool);
  101. }
  102. int acl_usr_cache_set_timeout (const int nsec)
  103. {
  104. acl_usr_cache_lifetime = (time_t)nsec;
  105. return 0;
  106. }
  107. int acl_usr_cache_enabled ()
  108. {
  109. return (acl_usr_cache_lifetime > 0);
  110. }
  111. int acl_usr_cache_init ()
  112. {
  113. UserCacheObj *usrobj;
  114. int i;
  115. if (acl_usr_cache_lifetime <= 0) {
  116. /* Caching is disabled */
  117. DBG_PRINT1("usrcache is disabled");
  118. return 0;
  119. }
  120. usrcache_pool = pool_create();
  121. user_hash_crit_init();
  122. if (acl_num_databases() == 0) {
  123. /* Something wrong -- No databases registered yet! */
  124. return -1;
  125. }
  126. else if (acl_num_databases() == 1) {
  127. /* Optimize for single database */
  128. DBG_PRINT1("Optimizing usrcache for single db");
  129. singleDbTable = alloc_db2uid_table();
  130. }
  131. else {
  132. singleDbTable = 0;
  133. databaseUserCacheTable = PR_NewHashTable(0,
  134. PR_HashCaseString,
  135. PR_CompareCaseStrings,
  136. PR_CompareValues,
  137. &ACLPermAllocOps,
  138. usrcache_pool);
  139. }
  140. /* Allocate first UserCacheObj and initialize the circular link list */
  141. usrobj = (UserCacheObj *)pool_malloc(usrcache_pool, sizeof(UserCacheObj));
  142. if (!usrobj) return -1;
  143. memset((void *)usrobj, 0, sizeof(UserCacheObj));
  144. usrobj_list = &usrobj->list;
  145. PR_INIT_CLIST(usrobj_list);
  146. /* Allocate rest of the UserCacheObj and put them in the link list */
  147. for(i = 0; i < num_usrobj; i++){
  148. usrobj = (UserCacheObj *)pool_malloc(usrcache_pool,
  149. sizeof(UserCacheObj));
  150. if (!usrobj) return -1;
  151. memset((void *)usrobj, 0, sizeof(UserCacheObj));
  152. PR_INSERT_AFTER(&usrobj->list, usrobj_list);
  153. }
  154. return (singleDbTable || databaseUserCacheTable) ? 0 : -1;
  155. }
  156. /* If the user hash table exists in the databaseUserCacheTable then return it.
  157. * Otherwise, create a new hash table, insert it in the databaseUserCacheTable
  158. * and then return it.
  159. */
  160. static int usr_cache_table_get (const char *dbname, PRHashTable **usrTable)
  161. {
  162. PRHashTable *table;
  163. if (singleDbTable) {
  164. *usrTable = singleDbTable;
  165. return LAS_EVAL_TRUE;
  166. }
  167. user_hash_crit_enter();
  168. table = (PRHashTable *)PR_HashTableLookup(databaseUserCacheTable,
  169. dbname);
  170. if (!table) {
  171. /* create a new table and insert it in the databaseUserCacheTable */
  172. table = alloc_db2uid_table();
  173. if (table) {
  174. PR_HashTableAdd(databaseUserCacheTable,
  175. pool_strdup(usrcache_pool, dbname),
  176. table);
  177. }
  178. }
  179. *usrTable = table;
  180. user_hash_crit_exit();
  181. return table ? LAS_EVAL_TRUE : LAS_EVAL_FAIL;
  182. }
  183. int acl_usr_cache_insert (const char *uid, const char *dbname,
  184. const char *userdn, const char *passwd,
  185. const char *group,
  186. const SECItem *derCert, const time_t time)
  187. {
  188. PRHashTable *usrTable;
  189. UserCacheObj *usrobj;
  190. UserCacheObj key;
  191. int rv;
  192. if (acl_usr_cache_lifetime <= 0) {
  193. /* Caching is disabled */
  194. return LAS_EVAL_TRUE;
  195. }
  196. rv = usr_cache_table_get (dbname, &usrTable);
  197. if (rv != LAS_EVAL_TRUE) return rv;
  198. user_hash_crit_enter();
  199. key.uid = (char *)uid;
  200. key.derCert = (SECItem *)derCert;
  201. usrobj = (UserCacheObj *)PR_HashTableLookup(usrTable, &key);
  202. if (usrobj) {
  203. time_t elapsed = time - usrobj->time;
  204. int expired = (elapsed >= acl_usr_cache_lifetime);
  205. /* Free & reset the old values in usrobj if -- there is an old value
  206. * and if the new value is given then it is different or the usrobj
  207. * has expired */
  208. /* Set the field if the new value is given and the field is not set */
  209. /* If the usrobj has not expired then we only want to update the field
  210. * whose new value is non-NULL and different */
  211. /* Work on the 'uid' field */
  212. if (usrobj->uid &&
  213. (uid ? strcmp(usrobj->uid, uid) : expired))
  214. {
  215. pool_free(usrcache_pool, usrobj->uid);
  216. usrobj->uid = 0;
  217. }
  218. if (uid && !usrobj->uid) {
  219. usrobj->uid = pool_strdup(usrcache_pool, uid);
  220. }
  221. /* Work on the 'userdn' field */
  222. if (usrobj->userdn &&
  223. (userdn ? strcmp(usrobj->userdn, userdn) : expired))
  224. {
  225. pool_free(usrcache_pool, usrobj->userdn);
  226. usrobj->userdn = 0;
  227. }
  228. if (userdn && !usrobj->userdn) {
  229. usrobj->userdn = pool_strdup(usrcache_pool, userdn);
  230. }
  231. /* Work on the 'passwd' field */
  232. if (usrobj->passwd &&
  233. (passwd ? strcmp(usrobj->passwd, passwd) : expired))
  234. {
  235. pool_free(usrcache_pool, usrobj->passwd);
  236. usrobj->passwd = 0;
  237. }
  238. if (passwd && !usrobj->passwd) {
  239. usrobj->passwd = pool_strdup(usrcache_pool, passwd);
  240. }
  241. /* Work on the 'group' field -- not replace a valid group */
  242. if (!expired && usrobj->group &&
  243. (group ? strcmp(usrobj->group, group) : expired))
  244. {
  245. pool_free(usrcache_pool, usrobj->group);
  246. usrobj->group = 0;
  247. }
  248. if (group && !usrobj->group) {
  249. usrobj->group = pool_strdup(usrcache_pool, group);
  250. }
  251. /* Work on the 'derCert' field */
  252. if (usrobj->derCert &&
  253. (derCert ? (derCert->len != usrobj->derCert->len ||
  254. memcmp(usrobj->derCert->data, derCert->data,
  255. derCert->len))
  256. : expired))
  257. {
  258. SECITEM_FreeItem(usrobj->derCert, PR_TRUE);
  259. usrobj->derCert = 0;
  260. }
  261. if (derCert && !usrobj->derCert) {
  262. usrobj->derCert = SECITEM_DupItem((SECItem *)derCert);
  263. }
  264. /* Reset the time only if the usrobj has expired */
  265. if (expired) {
  266. DBG_PRINT1("Replace ");
  267. usrobj->time = time;
  268. }
  269. else {
  270. DBG_PRINT1("Update ");
  271. }
  272. }
  273. else {
  274. /* Get the last usrobj from the link list, erase it and use it */
  275. /* Maybe the last usrobj is not invalid yet but we don't want to grow
  276. * the list of usrobjs. The last obj is the best candidate for being
  277. * not valid. We don't want to compare the time -- just use it.
  278. */
  279. PRCList *tail = PR_LIST_TAIL(usrobj_list);
  280. usrobj = USEROBJ_PTR(tail);
  281. if (!usrobj) {
  282. rv = LAS_EVAL_FAIL;
  283. goto out;
  284. }
  285. /* If the removed usrobj is in the hashtable, remove it from there */
  286. if (usrobj->hashtable) {
  287. PR_HashTableRemove(usrobj->hashtable, usrobj);
  288. }
  289. /* Free the memory associated with the usrobj */
  290. if (usrobj->userdn) pool_free(usrcache_pool, usrobj->userdn);
  291. if (usrobj->passwd) pool_free(usrcache_pool, usrobj->passwd);
  292. if (usrobj->group) pool_free(usrcache_pool, usrobj->group);
  293. if (usrobj->derCert) SECITEM_FreeItem(usrobj->derCert, PR_TRUE);
  294. if (usrobj->uid) pool_free(usrcache_pool, usrobj->uid);
  295. /* Fill in the usrobj with the current data */
  296. usrobj->uid = pool_strdup(usrcache_pool, uid);
  297. usrobj->userdn = userdn ? pool_strdup(usrcache_pool, userdn) : 0;
  298. usrobj->passwd = passwd ? pool_strdup(usrcache_pool, passwd) : 0;
  299. usrobj->derCert = derCert ? SECITEM_DupItem((SECItem *)derCert) : 0;
  300. usrobj->group = group ? pool_strdup(usrcache_pool, group) : 0;
  301. usrobj->time = time;
  302. /* Add the usrobj to the user hash table */
  303. PR_HashTableAdd(usrTable, usrobj, usrobj);
  304. usrobj->hashtable = usrTable;
  305. DBG_PRINT1("Insert ");
  306. }
  307. /* Move the usrobj to the head of the list */
  308. PR_REMOVE_LINK(&usrobj->list);
  309. PR_INSERT_AFTER(&usrobj->list, usrobj_list);
  310. DBG_PRINT4("acl_usr_cache_insert: derCert = \"%s\" uid = \"%s\" at time = %ld\n",
  311. usrobj->derCert ? (char *)usrobj->derCert->data : "<NONE>",
  312. uid, time);
  313. out:
  314. user_hash_crit_exit();
  315. return rv;
  316. }
  317. static int acl_usr_cache_get_usrobj (const char *uid, const SECItem *derCert,
  318. const char *dbname, const time_t time,
  319. UserCacheObj **usrobj_out)
  320. {
  321. PRHashTable *usrtable;
  322. UserCacheObj *usrobj;
  323. UserCacheObj key;
  324. time_t elapsed;
  325. int rv;
  326. *usrobj_out = 0;
  327. if (acl_usr_cache_lifetime <= 0) {
  328. /* Caching is disabled */
  329. return LAS_EVAL_FALSE;
  330. }
  331. rv = usr_cache_table_get(dbname, &usrtable);
  332. if (!usrtable) return LAS_EVAL_FALSE;
  333. key.uid = (char *)uid;
  334. key.derCert = (SECItem *)derCert;
  335. usrobj = (UserCacheObj *)PR_HashTableLookup(usrtable, &key);
  336. if (!usrobj) return LAS_EVAL_FALSE;
  337. rv = LAS_EVAL_FALSE;
  338. elapsed = time - usrobj->time;
  339. /* If the cache is valid, return the usrobj */
  340. if (elapsed < acl_usr_cache_lifetime) {
  341. rv = LAS_EVAL_TRUE;
  342. *usrobj_out = usrobj;
  343. DBG_PRINT4("usr_cache found: derCert = \"%s\" uid = \"%s\" at time = %ld\n",
  344. usrobj->derCert ? (char *)usrobj->derCert->data : "<NONE>",
  345. usrobj->uid, time);
  346. }
  347. else {
  348. DBG_PRINT4("usr_cache expired: derCert = \"%s\" uid = \"%s\" at time = %ld\n",
  349. usrobj->derCert ? (char *)usrobj->derCert->data : "<NONE>",
  350. usrobj->uid, time);
  351. }
  352. return rv;
  353. }
  354. int acl_usr_cache_passwd_check (const char *uid, const char *dbname,
  355. const char *passwd,
  356. const time_t time, char **dn,
  357. pool_handle_t *pool)
  358. {
  359. UserCacheObj *usrobj;
  360. int rv;
  361. user_hash_crit_enter();
  362. rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
  363. if (rv == LAS_EVAL_TRUE && usrobj->passwd && passwd &&
  364. !strcmp(usrobj->passwd, passwd))
  365. {
  366. /* extract dn from the usrobj */
  367. *dn = usrobj->userdn ? pool_strdup(pool, usrobj->userdn) : 0;
  368. rv = LAS_EVAL_TRUE;
  369. DBG_PRINT1("Success ");
  370. }
  371. else {
  372. rv = LAS_EVAL_FALSE;
  373. DBG_PRINT1("Failed ");
  374. }
  375. DBG_PRINT3("acl_usr_cache_passwd_check: uid = \"%s\" at time = %ld\n",
  376. uid, time);
  377. user_hash_crit_exit();
  378. return rv;
  379. }
  380. int acl_usr_cache_group_check (const char *uid, const char *dbname,
  381. const char *group, const time_t time)
  382. {
  383. UserCacheObj *usrobj;
  384. int rv;
  385. user_hash_crit_enter();
  386. rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
  387. if (rv == LAS_EVAL_TRUE && usrobj->group && group &&
  388. !strcmp(usrobj->group, group))
  389. {
  390. DBG_PRINT1("Success ");
  391. }
  392. else {
  393. rv = LAS_EVAL_FALSE;
  394. DBG_PRINT1("Failed ");
  395. }
  396. DBG_PRINT3("acl_usr_cache_group_check: uid = \"%s\" group = \"%s\"\n",
  397. uid, group ? group : "<NONE>");
  398. user_hash_crit_exit();
  399. return rv;
  400. }
  401. int acl_usr_cache_group_len_check (const char *uid, const char *dbname,
  402. const char *group, const int len,
  403. const time_t time)
  404. {
  405. UserCacheObj *usrobj;
  406. int rv;
  407. user_hash_crit_enter();
  408. rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
  409. if (rv == LAS_EVAL_TRUE && usrobj->group && group &&
  410. !strncmp(usrobj->group, group, len))
  411. {
  412. rv = LAS_EVAL_TRUE;
  413. DBG_PRINT1("Success ");
  414. }
  415. else {
  416. rv = LAS_EVAL_FALSE;
  417. DBG_PRINT1("Failed ");
  418. }
  419. DBG_PRINT3("acl_usr_cache_group_check: uid = \"%s\" group = \"%s\"\n",
  420. uid, group);
  421. user_hash_crit_exit();
  422. return rv;
  423. }
  424. int acl_usr_cache_get_userdn (const char *uid, const char *dbname,
  425. const time_t time, char **userdn,
  426. pool_handle_t *pool)
  427. {
  428. UserCacheObj *usrobj;
  429. int rv;
  430. *userdn = 0;
  431. user_hash_crit_enter();
  432. rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
  433. if (rv == LAS_EVAL_TRUE) {
  434. *userdn = usrobj->userdn ? pool_strdup(pool, usrobj->userdn) : 0;
  435. DBG_PRINT1("Success ");
  436. }
  437. else {
  438. DBG_PRINT1("Failed ");
  439. }
  440. DBG_PRINT3("acl_usr_cache_get_userdn: uid = \"%s\" userdn = \"%s\"\n",
  441. uid, *userdn ? *userdn : "<NONE>");
  442. user_hash_crit_exit();
  443. return *userdn ? LAS_EVAL_TRUE : LAS_EVAL_FALSE;
  444. }
  445. int acl_usr_cache_userdn_check (const char *uid, const char *dbname,
  446. const char *userdn, const time_t time)
  447. {
  448. UserCacheObj *usrobj;
  449. int rv;
  450. user_hash_crit_enter();
  451. rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
  452. if (rv == LAS_EVAL_TRUE && usrobj->userdn && userdn &&
  453. !strcmp(usrobj->userdn, userdn))
  454. {
  455. DBG_PRINT1("Success ");
  456. }
  457. else {
  458. rv = LAS_EVAL_FALSE;
  459. DBG_PRINT1("Failed ");
  460. }
  461. DBG_PRINT3("acl_usr_cache_userdn_check: uid = \"%s\" userdn = \"%s\"\n",
  462. uid, userdn ? userdn : "<NONE>");
  463. user_hash_crit_exit();
  464. return rv;
  465. }
  466. int acl_usr_cache_set_userdn (const char *uid, const char *dbname,
  467. const char *userdn, const time_t time)
  468. {
  469. int rv;
  470. /* acl_usr_cache_insert updates the existing un-expired entry or creates a
  471. * new one */
  472. rv = acl_usr_cache_insert(uid, dbname, userdn, 0, 0, 0, time);
  473. return rv;
  474. }
  475. int acl_usr_cache_get_group (const char *uid, const char *dbname,
  476. const time_t time, char **group,
  477. pool_handle_t *pool)
  478. {
  479. UserCacheObj *usrobj;
  480. int rv;
  481. *group = 0;
  482. user_hash_crit_enter();
  483. rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
  484. if (rv == LAS_EVAL_TRUE) {
  485. *group = usrobj->group ? pool_strdup(pool, usrobj->group) : 0;
  486. DBG_PRINT1("Success ");
  487. }
  488. else {
  489. DBG_PRINT1("Failed ");
  490. }
  491. DBG_PRINT3("acl_usr_cache_get_group: uid = \"%s\" group = \"%s\"\n",
  492. uid, *group ? *group : "<NONE>");
  493. user_hash_crit_exit();
  494. return *group ? LAS_EVAL_TRUE : LAS_EVAL_FALSE;
  495. }
  496. int acl_usr_cache_set_group (const char *uid, const char *dbname,
  497. const char *group, const time_t time)
  498. {
  499. int rv;
  500. /* acl_usr_cache_insert updates the existing un-expired entry or creates a
  501. * new one */
  502. rv = acl_usr_cache_insert(uid, dbname, 0, 0, group, 0, time);
  503. return rv;
  504. }
  505. int acl_cert_cache_insert (void *cert_in, const char *dbname,
  506. const char *uid, const char *dn,
  507. const time_t time)
  508. {
  509. CERTCertificate *cert = (CERTCertificate *)cert_in;
  510. SECItem derCert = cert->derCert;
  511. int rv;
  512. rv = acl_usr_cache_insert(uid, dbname, dn, 0, 0, &derCert, time);
  513. return rv;
  514. }
  515. /* Returns LAS_EVAL_TRUE if the user's cache is valid and returns uid */
  516. int acl_cert_cache_get_uid (void *cert_in, const char *dbname,
  517. const time_t time, char **uid, char **dn,
  518. pool_handle_t *pool)
  519. {
  520. CERTCertificate *cert = (CERTCertificate *)cert_in;
  521. SECItem derCert = cert->derCert;
  522. UserCacheObj *usrobj = 0;
  523. int rv;
  524. rv = acl_usr_cache_get_usrobj(0, &derCert, dbname, time, &usrobj);
  525. if (rv == LAS_EVAL_TRUE && usrobj && usrobj->uid) {
  526. *uid = pool_strdup(pool, usrobj->uid);
  527. *dn = usrobj->userdn ? pool_strdup(pool, usrobj->userdn) : 0;
  528. }
  529. else {
  530. *uid = 0;
  531. *dn = 0;
  532. rv = LAS_EVAL_FALSE;
  533. }
  534. return rv;
  535. }