usrcache.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  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. /* covscan false positive usrobj is linked in the cache */
  149. /* coverity[overwrite_var] */
  150. usrobj = (UserCacheObj *)pool_malloc(usrcache_pool,
  151. sizeof(UserCacheObj));
  152. if (!usrobj) return -1;
  153. memset((void *)usrobj, 0, sizeof(UserCacheObj));
  154. PR_INSERT_AFTER(&usrobj->list, usrobj_list);
  155. }
  156. /* covscan false positive usrobj is linked in the cache */
  157. /* coverity[leaked_storage] */
  158. return (singleDbTable || databaseUserCacheTable) ? 0 : -1;
  159. }
  160. /* If the user hash table exists in the databaseUserCacheTable then return it.
  161. * Otherwise, create a new hash table, insert it in the databaseUserCacheTable
  162. * and then return it.
  163. */
  164. static int usr_cache_table_get (const char *dbname, PRHashTable **usrTable)
  165. {
  166. PRHashTable *table;
  167. if (singleDbTable) {
  168. *usrTable = singleDbTable;
  169. return LAS_EVAL_TRUE;
  170. }
  171. user_hash_crit_enter();
  172. table = (PRHashTable *)PR_HashTableLookup(databaseUserCacheTable,
  173. dbname);
  174. if (!table) {
  175. /* create a new table and insert it in the databaseUserCacheTable */
  176. table = alloc_db2uid_table();
  177. if (table) {
  178. PR_HashTableAdd(databaseUserCacheTable,
  179. pool_strdup(usrcache_pool, dbname),
  180. table);
  181. }
  182. }
  183. *usrTable = table;
  184. user_hash_crit_exit();
  185. return table ? LAS_EVAL_TRUE : LAS_EVAL_FAIL;
  186. }
  187. int acl_usr_cache_insert (const char *uid, const char *dbname,
  188. const char *userdn, const char *passwd,
  189. const char *group,
  190. const SECItem *derCert, const time_t time)
  191. {
  192. PRHashTable *usrTable;
  193. UserCacheObj *usrobj;
  194. UserCacheObj key;
  195. int rv;
  196. if (acl_usr_cache_lifetime <= 0) {
  197. /* Caching is disabled */
  198. return LAS_EVAL_TRUE;
  199. }
  200. rv = usr_cache_table_get (dbname, &usrTable);
  201. if (rv != LAS_EVAL_TRUE) return rv;
  202. user_hash_crit_enter();
  203. key.uid = (char *)uid;
  204. key.derCert = (SECItem *)derCert;
  205. usrobj = (UserCacheObj *)PR_HashTableLookup(usrTable, &key);
  206. if (usrobj) {
  207. time_t elapsed = time - usrobj->time;
  208. int expired = (elapsed >= acl_usr_cache_lifetime);
  209. /* Free & reset the old values in usrobj if -- there is an old value
  210. * and if the new value is given then it is different or the usrobj
  211. * has expired */
  212. /* Set the field if the new value is given and the field is not set */
  213. /* If the usrobj has not expired then we only want to update the field
  214. * whose new value is non-NULL and different */
  215. /* Work on the 'uid' field */
  216. if (usrobj->uid &&
  217. (uid ? strcmp(usrobj->uid, uid) : expired))
  218. {
  219. pool_free(usrcache_pool, usrobj->uid);
  220. usrobj->uid = 0;
  221. }
  222. if (uid && !usrobj->uid) {
  223. usrobj->uid = pool_strdup(usrcache_pool, uid);
  224. }
  225. /* Work on the 'userdn' field */
  226. if (usrobj->userdn &&
  227. (userdn ? strcmp(usrobj->userdn, userdn) : expired))
  228. {
  229. pool_free(usrcache_pool, usrobj->userdn);
  230. usrobj->userdn = 0;
  231. }
  232. if (userdn && !usrobj->userdn) {
  233. usrobj->userdn = pool_strdup(usrcache_pool, userdn);
  234. }
  235. /* Work on the 'passwd' field */
  236. if (usrobj->passwd &&
  237. (passwd ? strcmp(usrobj->passwd, passwd) : expired))
  238. {
  239. pool_free(usrcache_pool, usrobj->passwd);
  240. usrobj->passwd = 0;
  241. }
  242. if (passwd && !usrobj->passwd) {
  243. usrobj->passwd = pool_strdup(usrcache_pool, passwd);
  244. }
  245. /* Work on the 'group' field -- not replace a valid group */
  246. if (!expired && usrobj->group &&
  247. (group ? strcmp(usrobj->group, group) : expired))
  248. {
  249. pool_free(usrcache_pool, usrobj->group);
  250. usrobj->group = 0;
  251. }
  252. if (group && !usrobj->group) {
  253. usrobj->group = pool_strdup(usrcache_pool, group);
  254. }
  255. /* Work on the 'derCert' field */
  256. if (usrobj->derCert &&
  257. (derCert ? (derCert->len != usrobj->derCert->len ||
  258. memcmp(usrobj->derCert->data, derCert->data,
  259. derCert->len))
  260. : expired))
  261. {
  262. SECITEM_FreeItem(usrobj->derCert, PR_TRUE);
  263. usrobj->derCert = 0;
  264. }
  265. if (derCert && !usrobj->derCert) {
  266. usrobj->derCert = SECITEM_DupItem((SECItem *)derCert);
  267. }
  268. /* Reset the time only if the usrobj has expired */
  269. if (expired) {
  270. DBG_PRINT1("Replace ");
  271. usrobj->time = time;
  272. }
  273. else {
  274. DBG_PRINT1("Update ");
  275. }
  276. }
  277. else {
  278. /* Get the last usrobj from the link list, erase it and use it */
  279. /* Maybe the last usrobj is not invalid yet but we don't want to grow
  280. * the list of usrobjs. The last obj is the best candidate for being
  281. * not valid. We don't want to compare the time -- just use it.
  282. */
  283. PRCList *tail = PR_LIST_TAIL(usrobj_list);
  284. usrobj = USEROBJ_PTR(tail);
  285. if (!usrobj) {
  286. rv = LAS_EVAL_FAIL;
  287. goto out;
  288. }
  289. /* If the removed usrobj is in the hashtable, remove it from there */
  290. if (usrobj->hashtable) {
  291. PR_HashTableRemove(usrobj->hashtable, usrobj);
  292. }
  293. /* Free the memory associated with the usrobj */
  294. if (usrobj->userdn) pool_free(usrcache_pool, usrobj->userdn);
  295. if (usrobj->passwd) pool_free(usrcache_pool, usrobj->passwd);
  296. if (usrobj->group) pool_free(usrcache_pool, usrobj->group);
  297. if (usrobj->derCert) SECITEM_FreeItem(usrobj->derCert, PR_TRUE);
  298. if (usrobj->uid) pool_free(usrcache_pool, usrobj->uid);
  299. /* Fill in the usrobj with the current data */
  300. usrobj->uid = pool_strdup(usrcache_pool, uid);
  301. usrobj->userdn = userdn ? pool_strdup(usrcache_pool, userdn) : 0;
  302. usrobj->passwd = passwd ? pool_strdup(usrcache_pool, passwd) : 0;
  303. usrobj->derCert = derCert ? SECITEM_DupItem((SECItem *)derCert) : 0;
  304. usrobj->group = group ? pool_strdup(usrcache_pool, group) : 0;
  305. usrobj->time = time;
  306. /* Add the usrobj to the user hash table */
  307. PR_HashTableAdd(usrTable, usrobj, usrobj);
  308. usrobj->hashtable = usrTable;
  309. DBG_PRINT1("Insert ");
  310. }
  311. /* Move the usrobj to the head of the list */
  312. PR_REMOVE_LINK(&usrobj->list);
  313. PR_INSERT_AFTER(&usrobj->list, usrobj_list);
  314. DBG_PRINT4("acl_usr_cache_insert: derCert = \"%s\" uid = \"%s\" at time = %ld\n",
  315. usrobj->derCert ? (char *)usrobj->derCert->data : "<NONE>",
  316. uid, time);
  317. out:
  318. user_hash_crit_exit();
  319. return rv;
  320. }
  321. static int acl_usr_cache_get_usrobj (const char *uid, const SECItem *derCert,
  322. const char *dbname, const time_t time,
  323. UserCacheObj **usrobj_out)
  324. {
  325. PRHashTable *usrtable;
  326. UserCacheObj *usrobj;
  327. UserCacheObj key;
  328. time_t elapsed;
  329. int rv;
  330. *usrobj_out = 0;
  331. if (acl_usr_cache_lifetime <= 0) {
  332. /* Caching is disabled */
  333. return LAS_EVAL_FALSE;
  334. }
  335. rv = usr_cache_table_get(dbname, &usrtable);
  336. if (!usrtable) return LAS_EVAL_FALSE;
  337. key.uid = (char *)uid;
  338. key.derCert = (SECItem *)derCert;
  339. usrobj = (UserCacheObj *)PR_HashTableLookup(usrtable, &key);
  340. if (!usrobj) return LAS_EVAL_FALSE;
  341. rv = LAS_EVAL_FALSE;
  342. elapsed = time - usrobj->time;
  343. /* If the cache is valid, return the usrobj */
  344. if (elapsed < acl_usr_cache_lifetime) {
  345. rv = LAS_EVAL_TRUE;
  346. *usrobj_out = usrobj;
  347. DBG_PRINT4("usr_cache found: derCert = \"%s\" uid = \"%s\" at time = %ld\n",
  348. usrobj->derCert ? (char *)usrobj->derCert->data : "<NONE>",
  349. usrobj->uid, time);
  350. }
  351. else {
  352. DBG_PRINT4("usr_cache expired: derCert = \"%s\" uid = \"%s\" at time = %ld\n",
  353. usrobj->derCert ? (char *)usrobj->derCert->data : "<NONE>",
  354. usrobj->uid, time);
  355. }
  356. return rv;
  357. }
  358. int acl_usr_cache_passwd_check (const char *uid, const char *dbname,
  359. const char *passwd,
  360. const time_t time, char **dn,
  361. pool_handle_t *pool)
  362. {
  363. UserCacheObj *usrobj;
  364. int rv;
  365. user_hash_crit_enter();
  366. rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
  367. if (rv == LAS_EVAL_TRUE && usrobj->passwd && passwd &&
  368. !strcmp(usrobj->passwd, passwd))
  369. {
  370. /* extract dn from the usrobj */
  371. *dn = usrobj->userdn ? pool_strdup(pool, usrobj->userdn) : 0;
  372. rv = LAS_EVAL_TRUE;
  373. DBG_PRINT1("Success ");
  374. }
  375. else {
  376. rv = LAS_EVAL_FALSE;
  377. DBG_PRINT1("Failed ");
  378. }
  379. DBG_PRINT3("acl_usr_cache_passwd_check: uid = \"%s\" at time = %ld\n",
  380. uid, time);
  381. user_hash_crit_exit();
  382. return rv;
  383. }
  384. int acl_usr_cache_group_check (const char *uid, const char *dbname,
  385. const char *group, const time_t time)
  386. {
  387. UserCacheObj *usrobj;
  388. int rv;
  389. user_hash_crit_enter();
  390. rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
  391. if (rv == LAS_EVAL_TRUE && usrobj->group && group &&
  392. !strcmp(usrobj->group, group))
  393. {
  394. DBG_PRINT1("Success ");
  395. }
  396. else {
  397. rv = LAS_EVAL_FALSE;
  398. DBG_PRINT1("Failed ");
  399. }
  400. DBG_PRINT3("acl_usr_cache_group_check: uid = \"%s\" group = \"%s\"\n",
  401. uid, group ? group : "<NONE>");
  402. user_hash_crit_exit();
  403. return rv;
  404. }
  405. int acl_usr_cache_group_len_check (const char *uid, const char *dbname,
  406. const char *group, const int len,
  407. const time_t time)
  408. {
  409. UserCacheObj *usrobj;
  410. int rv;
  411. user_hash_crit_enter();
  412. rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
  413. if (rv == LAS_EVAL_TRUE && usrobj->group && group &&
  414. !strncmp(usrobj->group, group, len))
  415. {
  416. rv = LAS_EVAL_TRUE;
  417. DBG_PRINT1("Success ");
  418. }
  419. else {
  420. rv = LAS_EVAL_FALSE;
  421. DBG_PRINT1("Failed ");
  422. }
  423. DBG_PRINT3("acl_usr_cache_group_check: uid = \"%s\" group = \"%s\"\n",
  424. uid, group);
  425. user_hash_crit_exit();
  426. return rv;
  427. }
  428. int acl_usr_cache_get_userdn (const char *uid, const char *dbname,
  429. const time_t time, char **userdn,
  430. pool_handle_t *pool)
  431. {
  432. UserCacheObj *usrobj;
  433. int rv;
  434. *userdn = 0;
  435. user_hash_crit_enter();
  436. rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
  437. if (rv == LAS_EVAL_TRUE) {
  438. *userdn = usrobj->userdn ? pool_strdup(pool, usrobj->userdn) : 0;
  439. DBG_PRINT1("Success ");
  440. }
  441. else {
  442. DBG_PRINT1("Failed ");
  443. }
  444. DBG_PRINT3("acl_usr_cache_get_userdn: uid = \"%s\" userdn = \"%s\"\n",
  445. uid, *userdn ? *userdn : "<NONE>");
  446. user_hash_crit_exit();
  447. return *userdn ? LAS_EVAL_TRUE : LAS_EVAL_FALSE;
  448. }
  449. int acl_usr_cache_userdn_check (const char *uid, const char *dbname,
  450. const char *userdn, const time_t time)
  451. {
  452. UserCacheObj *usrobj;
  453. int rv;
  454. user_hash_crit_enter();
  455. rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
  456. if (rv == LAS_EVAL_TRUE && usrobj->userdn && userdn &&
  457. !strcmp(usrobj->userdn, userdn))
  458. {
  459. DBG_PRINT1("Success ");
  460. }
  461. else {
  462. rv = LAS_EVAL_FALSE;
  463. DBG_PRINT1("Failed ");
  464. }
  465. DBG_PRINT3("acl_usr_cache_userdn_check: uid = \"%s\" userdn = \"%s\"\n",
  466. uid, userdn ? userdn : "<NONE>");
  467. user_hash_crit_exit();
  468. return rv;
  469. }
  470. int acl_usr_cache_set_userdn (const char *uid, const char *dbname,
  471. const char *userdn, const time_t time)
  472. {
  473. int rv;
  474. /* acl_usr_cache_insert updates the existing un-expired entry or creates a
  475. * new one */
  476. rv = acl_usr_cache_insert(uid, dbname, userdn, 0, 0, 0, time);
  477. return rv;
  478. }
  479. int acl_usr_cache_get_group (const char *uid, const char *dbname,
  480. const time_t time, char **group,
  481. pool_handle_t *pool)
  482. {
  483. UserCacheObj *usrobj;
  484. int rv;
  485. *group = 0;
  486. user_hash_crit_enter();
  487. rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
  488. if (rv == LAS_EVAL_TRUE) {
  489. *group = usrobj->group ? pool_strdup(pool, usrobj->group) : 0;
  490. DBG_PRINT1("Success ");
  491. }
  492. else {
  493. DBG_PRINT1("Failed ");
  494. }
  495. DBG_PRINT3("acl_usr_cache_get_group: uid = \"%s\" group = \"%s\"\n",
  496. uid, *group ? *group : "<NONE>");
  497. user_hash_crit_exit();
  498. return *group ? LAS_EVAL_TRUE : LAS_EVAL_FALSE;
  499. }
  500. int acl_usr_cache_set_group (const char *uid, const char *dbname,
  501. const char *group, const time_t time)
  502. {
  503. int rv;
  504. /* acl_usr_cache_insert updates the existing un-expired entry or creates a
  505. * new one */
  506. rv = acl_usr_cache_insert(uid, dbname, 0, 0, group, 0, time);
  507. return rv;
  508. }
  509. int acl_cert_cache_insert (void *cert_in, const char *dbname,
  510. const char *uid, const char *dn,
  511. const time_t time)
  512. {
  513. CERTCertificate *cert = (CERTCertificate *)cert_in;
  514. SECItem derCert = cert->derCert;
  515. int rv;
  516. rv = acl_usr_cache_insert(uid, dbname, dn, 0, 0, &derCert, time);
  517. return rv;
  518. }
  519. /* Returns LAS_EVAL_TRUE if the user's cache is valid and returns uid */
  520. int acl_cert_cache_get_uid (void *cert_in, const char *dbname,
  521. const time_t time, char **uid, char **dn,
  522. pool_handle_t *pool)
  523. {
  524. CERTCertificate *cert = (CERTCertificate *)cert_in;
  525. SECItem derCert = cert->derCert;
  526. UserCacheObj *usrobj = 0;
  527. int rv;
  528. rv = acl_usr_cache_get_usrobj(0, &derCert, dbname, time, &usrobj);
  529. if (rv == LAS_EVAL_TRUE && usrobj && usrobj->uid) {
  530. *uid = pool_strdup(pool, usrobj->uid);
  531. *dn = usrobj->userdn ? pool_strdup(pool, usrobj->userdn) : 0;
  532. }
  533. else {
  534. *uid = 0;
  535. *dn = 0;
  536. rv = LAS_EVAL_FALSE;
  537. }
  538. return rv;
  539. }