acleffectiverights.c 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2005 Red Hat, Inc.
  3. * All rights reserved.
  4. *
  5. * License: GPL (version 3 or any later version).
  6. * See LICENSE for details.
  7. * END COPYRIGHT BLOCK **/
  8. #ifdef HAVE_CONFIG_H
  9. # include <config.h>
  10. #endif
  11. #include <ldap.h>
  12. #include "acl.h"
  13. /* safer than doing strcat unprotected */
  14. /* news2 is optional, provided as a convenience */
  15. /* capacity is the capacity of the gerstr, size is the current length */
  16. static void
  17. _append_gerstr(
  18. char **gerstr,
  19. size_t *capacity,
  20. size_t *size,
  21. const char *news,
  22. const char *news2
  23. )
  24. {
  25. size_t len;
  26. size_t increment = 128;
  27. size_t fornull;
  28. if (!news) {
  29. return;
  30. }
  31. /* find out how much space we need */
  32. len = strlen(news);
  33. fornull = 1;
  34. if (news2) {
  35. len += strlen(news2);
  36. fornull++;
  37. }
  38. /* increase space if needed */
  39. while ((*size + len + fornull) > *capacity) {
  40. if ((len + fornull) > increment) {
  41. *capacity += len + fornull; /* just go ahead and grow the string enough */
  42. } else {
  43. *capacity += increment; /* rather than having lots of small increments */
  44. }
  45. }
  46. if (!*gerstr) {
  47. *gerstr = slapi_ch_malloc(*capacity);
  48. **gerstr = 0;
  49. } else {
  50. *gerstr = slapi_ch_realloc(*gerstr, *capacity);
  51. }
  52. strcat(*gerstr, news);
  53. if (news2) {
  54. strcat(*gerstr, news2);
  55. }
  56. *size += len;
  57. return;
  58. }
  59. static int
  60. _ger_g_permission_granted (
  61. Slapi_PBlock *pb,
  62. Slapi_Entry *e,
  63. const char *subjectdn,
  64. char **errbuf
  65. )
  66. {
  67. char *proxydn = NULL;
  68. Slapi_DN *requestor_sdn, *entry_sdn;
  69. char *errtext = NULL;
  70. int isroot;
  71. int rc;
  72. /*
  73. * Theorically, we should check if the entry has "g"
  74. * permission granted to the requestor. If granted,
  75. * allows the effective rights on that entry and its
  76. * attributes within the entry to be returned for
  77. * ANY subject.
  78. *
  79. * "G" permission granting has not been implemented yet,
  80. * the current release assumes that "g" permission be
  81. * granted to root and owner of any entry.
  82. */
  83. /*
  84. * The requestor may be either the bind dn or a proxy dn
  85. */
  86. if ((proxyauth_get_dn( pb, &proxydn, &errtext ) == LDAP_SUCCESS) && ( proxydn != NULL ))
  87. {
  88. requestor_sdn = slapi_sdn_new_dn_passin ( proxydn );
  89. }
  90. else
  91. {
  92. slapi_ch_free_string(&proxydn); /* this could still have been set - free it */
  93. requestor_sdn = &(pb->pb_op->o_sdn);
  94. }
  95. if ( slapi_sdn_get_dn (requestor_sdn) == NULL )
  96. {
  97. slapi_log_error(SLAPI_LOG_ACL, plugin_name,
  98. "_ger_g_permission_granted - Anonymous has no g permission\n" );
  99. rc = LDAP_INSUFFICIENT_ACCESS;
  100. goto bailout;
  101. }
  102. isroot = slapi_dn_isroot ( slapi_sdn_get_dn (requestor_sdn) );
  103. if ( isroot )
  104. {
  105. /* Root has "g" permission on any entry */
  106. rc = LDAP_SUCCESS;
  107. goto bailout;
  108. }
  109. entry_sdn = slapi_entry_get_sdn ( e );
  110. if ( entry_sdn == NULL || slapi_sdn_get_dn (entry_sdn) == NULL )
  111. {
  112. rc = LDAP_SUCCESS;
  113. goto bailout;
  114. }
  115. if ( slapi_sdn_compare ( requestor_sdn, entry_sdn ) == 0 )
  116. {
  117. /* Owner has "g" permission on his own entry */
  118. rc = LDAP_SUCCESS;
  119. goto bailout;
  120. }
  121. /* if the requestor and the subject user are identical, let's grant it */
  122. if ( strcasecmp ( slapi_sdn_get_ndn(requestor_sdn), subjectdn ) == 0)
  123. {
  124. /* Requestor should see his own permission rights on any entry */
  125. rc = LDAP_SUCCESS;
  126. goto bailout;
  127. }
  128. aclutil_str_append ( errbuf, "get-effective-rights: requestor has no g permission on the entry" );
  129. slapi_log_error(SLAPI_LOG_ACL, plugin_name,
  130. "_ger_g_permission_granted - %s\n", *errbuf);
  131. rc = LDAP_INSUFFICIENT_ACCESS;
  132. bailout:
  133. if ( proxydn )
  134. {
  135. /* The ownership of proxydn has passed to requestor_sdn */
  136. slapi_sdn_free ( &requestor_sdn );
  137. }
  138. return rc;
  139. }
  140. static int
  141. _ger_parse_control (
  142. Slapi_PBlock *pb,
  143. char **subjectndn,
  144. int *iscritical,
  145. char **errbuf
  146. )
  147. {
  148. LDAPControl **requestcontrols;
  149. struct berval *subjectber;
  150. BerElement *ber;
  151. size_t subjectndnlen = 0;
  152. char *orig = NULL;
  153. char *normed = NULL;
  154. if (NULL == subjectndn)
  155. {
  156. return LDAP_OPERATIONS_ERROR;
  157. }
  158. *subjectndn = NULL;
  159. /*
  160. * Get the control
  161. */
  162. slapi_pblock_get ( pb, SLAPI_REQCONTROLS, (void *) &requestcontrols );
  163. slapi_control_present ( requestcontrols,
  164. LDAP_CONTROL_GET_EFFECTIVE_RIGHTS,
  165. &subjectber,
  166. iscritical );
  167. if ( subjectber == NULL || subjectber->bv_val == NULL ||
  168. subjectber->bv_len == 0 )
  169. {
  170. aclutil_str_append ( errbuf, "get-effective-rights: missing subject" );
  171. slapi_log_error(SLAPI_LOG_ERR, plugin_name, "_ger_parse_control - %s\n", *errbuf );
  172. if (iscritical)
  173. return LDAP_UNAVAILABLE_CRITICAL_EXTENSION; /* RFC 4511 4.1.11 */
  174. else
  175. return LDAP_INVALID_SYNTAX;
  176. }
  177. if ( strncasecmp ( "dn:", subjectber->bv_val, 3 ) == 0 )
  178. {
  179. /*
  180. * This is a non-standard support to allow the subject being a plain
  181. * or base64 encoding string. Hence users using -J option in
  182. * ldapsearch don't have to do BER encoding for the subject.
  183. */
  184. orig = slapi_ch_malloc ( subjectber->bv_len + 1 );
  185. strncpy ( orig, subjectber->bv_val, subjectber->bv_len );
  186. *(orig + subjectber->bv_len) = '\0';
  187. }
  188. else
  189. {
  190. ber = ber_init (subjectber);
  191. if ( ber == NULL )
  192. {
  193. aclutil_str_append ( errbuf, "get-effective-rights: ber_init failed for the subject" );
  194. slapi_log_error(SLAPI_LOG_ERR, plugin_name, "_ger_parse_control - %s\n", *errbuf );
  195. if (iscritical)
  196. return LDAP_UNAVAILABLE_CRITICAL_EXTENSION; /* RFC 4511 4.1.11 */
  197. else
  198. return LDAP_OPERATIONS_ERROR;
  199. }
  200. /* "a" means to allocate storage as needed for octet string */
  201. if ( ber_scanf (ber, "a", &orig) == LBER_ERROR )
  202. {
  203. aclutil_str_append ( errbuf, "get-effective-rights: invalid ber tag in the subject" );
  204. slapi_log_error(SLAPI_LOG_ERR, plugin_name, "_ger_parse_control - %s\n", *errbuf );
  205. ber_free ( ber, 1 );
  206. if (iscritical)
  207. return LDAP_UNAVAILABLE_CRITICAL_EXTENSION; /* RFC 4511 4.1.11 */
  208. else
  209. return LDAP_INVALID_SYNTAX;
  210. }
  211. ber_free ( ber, 1 );
  212. }
  213. /*
  214. * The current implementation limits the subject to authorization ID
  215. * (see section 9 of RFC 2829) only. It also only supports the "dnAuthzId"
  216. * flavor, which looks like "dn:<DN>" where null <DN> is for anonymous.
  217. */
  218. subjectndnlen = orig ? strlen(orig) : 0;
  219. if ( NULL == orig || subjectndnlen < 3 || strncasecmp ( "dn:", orig, 3 ) != 0 )
  220. {
  221. aclutil_str_append ( errbuf, "get-effective-rights: subject is not dnAuthzId" );
  222. slapi_log_error(SLAPI_LOG_ERR, plugin_name, "_ger_parse_control - %s\n", *errbuf );
  223. slapi_ch_free_string(&orig);
  224. if (iscritical)
  225. return LDAP_UNAVAILABLE_CRITICAL_EXTENSION; /* RFC 4511 4.1.11 */
  226. else
  227. return LDAP_INVALID_SYNTAX;
  228. }
  229. /* memmove is safe for overlapping copy */
  230. normed = slapi_create_dn_string("%s", orig + 3);
  231. if (NULL == normed) {
  232. aclutil_str_append (errbuf, "get-effective-rights: failed to normalize dn: ");
  233. aclutil_str_append (errbuf, orig);
  234. slapi_log_error(SLAPI_LOG_ERR, plugin_name, "_ger_parse_control - %s\n", *errbuf);
  235. slapi_ch_free_string(&orig);
  236. if (iscritical)
  237. return LDAP_UNAVAILABLE_CRITICAL_EXTENSION; /* RFC 4511 4.1.11 */
  238. else
  239. return LDAP_INVALID_SYNTAX;
  240. }
  241. slapi_ch_free_string(&orig);
  242. *subjectndn = normed;
  243. slapi_dn_ignore_case(*subjectndn);
  244. return LDAP_SUCCESS;
  245. }
  246. static void
  247. _ger_release_gerpb (
  248. Slapi_PBlock **gerpb,
  249. void **aclcb, /* original aclcb */
  250. Slapi_PBlock *pb /* original pb */
  251. )
  252. {
  253. if ( *gerpb )
  254. {
  255. slapi_pblock_destroy ( *gerpb );
  256. *gerpb = NULL;
  257. }
  258. /* Put the original aclcb back to pb */
  259. if ( *aclcb )
  260. {
  261. Connection *conn = NULL;
  262. slapi_pblock_get ( pb, SLAPI_CONNECTION, &conn );
  263. if (conn)
  264. {
  265. struct aclcb *geraclcb;
  266. geraclcb = (struct aclcb *) acl_get_ext ( ACL_EXT_CONNECTION, conn );
  267. acl_conn_ext_destructor ( geraclcb, NULL, NULL );
  268. acl_set_ext ( ACL_EXT_CONNECTION, conn, *aclcb );
  269. *aclcb = NULL;
  270. }
  271. }
  272. }
  273. static int
  274. _ger_new_gerpb (
  275. Slapi_PBlock *pb,
  276. Slapi_Entry *e,
  277. const char *subjectndn,
  278. Slapi_PBlock **gerpb,
  279. void **aclcb, /* original aclcb */
  280. char **errbuf
  281. )
  282. {
  283. Connection *conn;
  284. struct acl_cblock *geraclcb;
  285. Acl_PBlock *geraclpb;
  286. Operation *gerop;
  287. int rc = LDAP_SUCCESS;
  288. *aclcb = NULL;
  289. *gerpb = slapi_pblock_new ();
  290. if ( *gerpb == NULL )
  291. {
  292. rc = LDAP_NO_MEMORY;
  293. goto bailout;
  294. }
  295. {
  296. /* aclpb initialization needs the backend */
  297. Slapi_Backend *be;
  298. slapi_pblock_get ( pb, SLAPI_BACKEND, &be );
  299. slapi_pblock_set ( *gerpb, SLAPI_BACKEND, be );
  300. }
  301. {
  302. int isroot = slapi_dn_isroot ( subjectndn );
  303. slapi_pblock_set ( *gerpb, SLAPI_REQUESTOR_ISROOT, &isroot );
  304. }
  305. /* Save requestor's aclcb and set subjectdn's one */
  306. {
  307. slapi_pblock_get ( pb, SLAPI_CONNECTION, &conn );
  308. slapi_pblock_set ( *gerpb, SLAPI_CONNECTION, conn );
  309. /* Can't share the conn->aclcb because of different context */
  310. geraclcb = (struct acl_cblock *) acl_conn_ext_constructor ( NULL, NULL);
  311. if ( geraclcb == NULL )
  312. {
  313. rc = LDAP_NO_MEMORY;
  314. goto bailout;
  315. }
  316. slapi_sdn_set_ndn_byval ( geraclcb->aclcb_sdn, subjectndn );
  317. *aclcb = acl_get_ext ( ACL_EXT_CONNECTION, conn );
  318. acl_set_ext ( ACL_EXT_CONNECTION, conn, (void *) geraclcb );
  319. }
  320. {
  321. gerop = operation_new ( OP_FLAG_INTERNAL );
  322. if ( gerop == NULL )
  323. {
  324. rc = LDAP_NO_MEMORY;
  325. goto bailout;
  326. }
  327. /*
  328. * conn is a no-use parameter in the functions
  329. * chained down from factory_create_extension
  330. */
  331. gerop->o_extension = factory_create_extension ( get_operation_object_type(), (void *)gerop, (void *)conn );
  332. slapi_pblock_set ( *gerpb, SLAPI_OPERATION, gerop );
  333. slapi_sdn_set_ndn_byval ( &gerop->o_sdn, subjectndn );
  334. geraclpb = acl_get_ext ( ACL_EXT_OPERATION, (void *)gerop);
  335. acl_init_aclpb ( *gerpb, geraclpb, subjectndn, 0 );
  336. geraclpb->aclpb_res_type |= ACLPB_EFFECTIVE_RIGHTS;
  337. }
  338. bailout:
  339. if ( rc != LDAP_SUCCESS )
  340. {
  341. _ger_release_gerpb ( gerpb, aclcb, pb );
  342. }
  343. return rc;
  344. }
  345. /*
  346. * Callers should have already allocated *gerstr to hold at least
  347. * "entryLevelRights: adnvxxx\n".
  348. */
  349. unsigned long
  350. _ger_get_entry_rights (
  351. Slapi_PBlock *gerpb,
  352. Slapi_Entry *e,
  353. const char *subjectndn,
  354. char **gerstr,
  355. size_t *gerstrsize,
  356. size_t *gerstrcap,
  357. char **errbuf
  358. )
  359. {
  360. unsigned long entryrights = 0;
  361. Slapi_RDN *rdn = NULL;
  362. char *rdntype = NULL;
  363. char *rdnvalue = NULL;
  364. _append_gerstr(gerstr, gerstrsize, gerstrcap, "entryLevelRights: ", NULL);
  365. slapi_log_error(SLAPI_LOG_ACL, plugin_name,
  366. "_ger_get_entry_rights - SLAPI_ACL_READ\n" );
  367. if (acl_access_allowed(gerpb, e, "*", NULL, SLAPI_ACL_READ) == LDAP_SUCCESS)
  368. {
  369. /* v - view e */
  370. entryrights |= SLAPI_ACL_READ;
  371. _append_gerstr(gerstr, gerstrsize, gerstrcap, "v", NULL);
  372. }
  373. slapi_log_error(SLAPI_LOG_ACL, plugin_name,
  374. "_ger_get_entry_rights - SLAPI_ACL_ADD\n" );
  375. if (acl_access_allowed(gerpb, e, NULL, NULL, SLAPI_ACL_ADD) == LDAP_SUCCESS)
  376. {
  377. /* a - add child entry below e */
  378. entryrights |= SLAPI_ACL_ADD;
  379. _append_gerstr(gerstr, gerstrsize, gerstrcap, "a", NULL);
  380. }
  381. slapi_log_error(SLAPI_LOG_ACL, plugin_name,
  382. "_ger_get_entry_rights - SLAPI_ACL_DELETE\n" );
  383. if (acl_access_allowed(gerpb, e, NULL, NULL, SLAPI_ACL_DELETE) == LDAP_SUCCESS)
  384. {
  385. /* d - delete e */
  386. entryrights |= SLAPI_ACL_DELETE;
  387. _append_gerstr(gerstr, gerstrsize, gerstrcap, "d", NULL);
  388. }
  389. if (config_get_moddn_aci()) {
  390. /* The server enforces the new MODDN aci right.
  391. * So the status 'n' is set if this right is granted.
  392. * Opposed to the legacy mode where this flag is set if
  393. * WRITE was granted on rdn attrbibute
  394. */
  395. if (acl_access_allowed(gerpb, e, NULL, NULL, SLAPI_ACL_MODDN) == LDAP_SUCCESS) {
  396. slapi_log_error(SLAPI_LOG_ACL, plugin_name,
  397. "_ger_get_entry_rights - SLAPI_ACL_MODDN %s\n", slapi_entry_get_ndn(e));
  398. /* n - rename e */
  399. entryrights |= SLAPI_ACL_MODDN;
  400. _append_gerstr(gerstr, gerstrsize, gerstrcap, "n", NULL);
  401. }
  402. } else {
  403. /*
  404. * Some limitation/simplification applied here:
  405. * - The modrdn right requires the rights to delete the old rdn and
  406. * the new one. However we have no knowledge of what the new rdn
  407. * is going to be.
  408. * - In multi-valued RDN case, we check the right on
  409. * the first rdn type only for now.
  410. */
  411. rdn = slapi_rdn_new_dn(slapi_entry_get_ndn(e));
  412. slapi_rdn_get_first(rdn, &rdntype, &rdnvalue);
  413. if (NULL != rdntype) {
  414. slapi_log_error(SLAPI_LOG_ACL, plugin_name,
  415. "_ger_get_entry_rights - SLAPI_ACL_WRITE_DEL & _ADD %s\n", rdntype);
  416. if (acl_access_allowed(gerpb, e, rdntype, NULL,
  417. ACLPB_SLAPI_ACL_WRITE_DEL) == LDAP_SUCCESS &&
  418. acl_access_allowed(gerpb, e, rdntype, NULL,
  419. ACLPB_SLAPI_ACL_WRITE_ADD) == LDAP_SUCCESS) {
  420. /* n - rename e */
  421. entryrights |= SLAPI_ACL_WRITE;
  422. _append_gerstr(gerstr, gerstrsize, gerstrcap, "n", NULL);
  423. }
  424. }
  425. slapi_rdn_free(&rdn);
  426. }
  427. if ( entryrights == 0 )
  428. {
  429. _append_gerstr(gerstr, gerstrsize, gerstrcap, "none", NULL);
  430. }
  431. _append_gerstr(gerstr, gerstrsize, gerstrcap, "\n", NULL);
  432. return entryrights;
  433. }
  434. /*
  435. * *gerstr should point to a heap buffer since it may need
  436. * to expand dynamically.
  437. */
  438. unsigned long
  439. _ger_get_attr_rights (
  440. Slapi_PBlock *gerpb,
  441. Slapi_Entry *e,
  442. const char *subjectndn,
  443. char *type,
  444. char **gerstr,
  445. size_t *gerstrsize,
  446. size_t *gerstrcap,
  447. int isfirstattr,
  448. char **errbuf
  449. )
  450. {
  451. unsigned long attrrights = 0;
  452. if (!isfirstattr)
  453. {
  454. _append_gerstr(gerstr, gerstrsize, gerstrcap, ", ", NULL);
  455. }
  456. _append_gerstr(gerstr, gerstrsize, gerstrcap, type, ":");
  457. slapi_log_error(SLAPI_LOG_ACL, plugin_name,
  458. "_ger_get_attr_rights - SLAPI_ACL_READ %s\n", type );
  459. if (acl_access_allowed(gerpb, e, type, NULL, SLAPI_ACL_READ) == LDAP_SUCCESS)
  460. {
  461. /* r - read the values of type */
  462. attrrights |= SLAPI_ACL_READ;
  463. _append_gerstr(gerstr, gerstrsize, gerstrcap, "r", NULL);
  464. }
  465. slapi_log_error(SLAPI_LOG_ACL, plugin_name,
  466. "_ger_get_attr_rights - SLAPI_ACL_SEARCH %s\n", type );
  467. if (acl_access_allowed(gerpb, e, type, NULL, SLAPI_ACL_SEARCH) == LDAP_SUCCESS)
  468. {
  469. /* s - search the values of type */
  470. attrrights |= SLAPI_ACL_SEARCH;
  471. _append_gerstr(gerstr, gerstrsize, gerstrcap, "s", NULL);
  472. }
  473. slapi_log_error(SLAPI_LOG_ACL, plugin_name,
  474. "_ger_get_attr_rights - SLAPI_ACL_COMPARE %s\n", type );
  475. if (acl_access_allowed(gerpb, e, type, NULL, SLAPI_ACL_COMPARE) == LDAP_SUCCESS)
  476. {
  477. /* c - compare the values of type */
  478. attrrights |= SLAPI_ACL_COMPARE;
  479. _append_gerstr(gerstr, gerstrsize, gerstrcap, "c", NULL);
  480. }
  481. slapi_log_error(SLAPI_LOG_ACL, plugin_name,
  482. "_ger_get_attr_rights - SLAPI_ACL_WRITE_ADD %s\n", type );
  483. if (acl_access_allowed(gerpb, e, type, NULL, ACLPB_SLAPI_ACL_WRITE_ADD) == LDAP_SUCCESS)
  484. {
  485. /* w - add the values of type */
  486. attrrights |= ACLPB_SLAPI_ACL_WRITE_ADD;
  487. _append_gerstr(gerstr, gerstrsize, gerstrcap, "w", NULL);
  488. }
  489. slapi_log_error(SLAPI_LOG_ACL, plugin_name,
  490. "_ger_get_attr_rights - SLAPI_ACL_WRITE_DEL %s\n", type );
  491. if (acl_access_allowed(gerpb, e, type, NULL, ACLPB_SLAPI_ACL_WRITE_DEL) == LDAP_SUCCESS)
  492. {
  493. /* o - delete the values of type */
  494. attrrights |= ACLPB_SLAPI_ACL_WRITE_DEL;
  495. _append_gerstr(gerstr, gerstrsize, gerstrcap, "o", NULL);
  496. }
  497. /* If subjectdn has no general write right, check for self write */
  498. if ( 0 == (attrrights & (ACLPB_SLAPI_ACL_WRITE_DEL | ACLPB_SLAPI_ACL_WRITE_ADD)) )
  499. {
  500. struct berval val;
  501. val.bv_val = (char *)subjectndn;
  502. val.bv_len = strlen (subjectndn);
  503. if (acl_access_allowed(gerpb, e, type, &val, ACLPB_SLAPI_ACL_WRITE_ADD) == LDAP_SUCCESS)
  504. {
  505. /* W - add self to the attribute */
  506. attrrights |= ACLPB_SLAPI_ACL_WRITE_ADD;
  507. _append_gerstr(gerstr, gerstrsize, gerstrcap, "W", NULL);
  508. }
  509. if (acl_access_allowed(gerpb, e, type, &val, ACLPB_SLAPI_ACL_WRITE_DEL) == LDAP_SUCCESS)
  510. {
  511. /* O - delete self from the attribute */
  512. attrrights |= ACLPB_SLAPI_ACL_WRITE_DEL;
  513. _append_gerstr(gerstr, gerstrsize, gerstrcap, "O", NULL);
  514. }
  515. }
  516. if ( attrrights == 0 )
  517. {
  518. _append_gerstr(gerstr, gerstrsize, gerstrcap, "none", NULL);
  519. }
  520. return attrrights;
  521. }
  522. #define GER_GET_ATTR_RIGHTS(attrs) \
  523. for (thisattr = (attrs); thisattr && *thisattr; thisattr++) \
  524. { \
  525. _ger_get_attr_rights (gerpb, e, subjectndn, *thisattr, \
  526. gerstr, gerstrsize, gerstrcap, isfirstattr, errbuf); \
  527. isfirstattr = 0; \
  528. } \
  529. #define GER_GET_ATTR_RIGHTA_EXT(c, inattrs, exattrs); \
  530. for ( i = 0; attrs[i]; i++ ) \
  531. { \
  532. if ((c) != *attrs[i] && charray_inlist((inattrs), attrs[i]) && \
  533. !charray_inlist((exattrs), attrs[i])) \
  534. { \
  535. _ger_get_attr_rights ( gerpb, e, subjectndn, attrs[i], \
  536. gerstr, gerstrsize, gerstrcap, isfirstattr, errbuf ); \
  537. isfirstattr = 0; \
  538. } \
  539. }
  540. void
  541. _ger_get_attrs_rights (
  542. Slapi_PBlock *gerpb,
  543. Slapi_Entry *e,
  544. const char *subjectndn,
  545. char **attrs,
  546. char **gerstr,
  547. size_t *gerstrsize,
  548. size_t *gerstrcap,
  549. char **errbuf
  550. )
  551. {
  552. int isfirstattr = 1;
  553. /* gerstr was initially allocated with enough space for one more line */
  554. _append_gerstr(gerstr, gerstrsize, gerstrcap, "attributeLevelRights: ", NULL);
  555. /*
  556. * If it's stated attribute list is given,
  557. * the first attr in the list should not be empty.
  558. * Otherwise, it's considered the list is not given.
  559. */
  560. if (attrs && *attrs && (strlen(*attrs) > 0))
  561. {
  562. int i = 0;
  563. char **allattrs = NULL;
  564. char **opattrs = NULL;
  565. char **noexpattrs = NULL; /* attrs not to expose */
  566. char **myattrs = NULL;
  567. char **thisattr = NULL;
  568. int hasstar = charray_inlist(attrs, "*");
  569. int hasplus = charray_inlist(attrs, "+");
  570. Slapi_Attr *objclasses = NULL;
  571. Slapi_ValueSet *objclassvals = NULL;
  572. int isextensibleobj = 0;
  573. /* get all attrs available for the entry */
  574. slapi_entry_attr_find(e, "objectclass", &objclasses);
  575. if (NULL != objclasses) {
  576. Slapi_Value *v;
  577. slapi_attr_get_valueset(objclasses, &objclassvals);
  578. i = slapi_valueset_first_value(objclassvals, &v);
  579. if (-1 != i)
  580. {
  581. const char *ocname = NULL;
  582. allattrs = slapi_schema_list_objectclass_attributes(
  583. (const char *)v->bv.bv_val,
  584. SLAPI_OC_FLAG_REQUIRED|SLAPI_OC_FLAG_ALLOWED);
  585. /* check if this entry is an extensble object or not */
  586. ocname = slapi_value_get_string(v);
  587. if ( strcasecmp( ocname, "extensibleobject" ) == 0 )
  588. {
  589. isextensibleobj = 1;
  590. }
  591. /* add "aci" to the allattrs to adjust to do_search */
  592. charray_add(&allattrs, slapi_attr_syntax_normalize("aci"));
  593. while (-1 != i)
  594. {
  595. i = slapi_valueset_next_value(objclassvals, i, &v);
  596. if (-1 != i)
  597. {
  598. myattrs = slapi_schema_list_objectclass_attributes(
  599. (const char *)v->bv.bv_val,
  600. SLAPI_OC_FLAG_REQUIRED|SLAPI_OC_FLAG_ALLOWED);
  601. /* check if this entry is an extensble object or not */
  602. ocname = slapi_value_get_string(v);
  603. if ( strcasecmp( ocname, "extensibleobject" ) == 0 )
  604. {
  605. isextensibleobj = 1;
  606. }
  607. charray_merge_nodup(&allattrs, myattrs, 1/*copy_strs*/);
  608. charray_free(myattrs);
  609. }
  610. }
  611. }
  612. slapi_valueset_free(objclassvals);
  613. }
  614. /* get operational attrs */
  615. opattrs = slapi_schema_list_attribute_names(SLAPI_ATTR_FLAG_OPATTR);
  616. noexpattrs = slapi_schema_list_attribute_names(SLAPI_ATTR_FLAG_NOEXPOSE);
  617. /* subtract no expose attrs from opattrs (e.g., unhashed pw) */
  618. charray_subtract(opattrs, noexpattrs, NULL);
  619. if (isextensibleobj)
  620. {
  621. for ( i = 0; attrs[i]; i++ )
  622. {
  623. if ('\0' == *attrs[i]) {
  624. continue; /* skip an empty attr */
  625. }
  626. _ger_get_attr_rights ( gerpb, e, subjectndn, attrs[i], gerstr,
  627. gerstrsize, gerstrcap, isfirstattr, errbuf );
  628. isfirstattr = 0;
  629. }
  630. }
  631. else
  632. {
  633. if (hasstar && hasplus)
  634. {
  635. GER_GET_ATTR_RIGHTS(allattrs);
  636. GER_GET_ATTR_RIGHTS(opattrs);
  637. }
  638. else if (hasstar)
  639. {
  640. GER_GET_ATTR_RIGHTS(allattrs);
  641. GER_GET_ATTR_RIGHTA_EXT('*', opattrs, allattrs);
  642. }
  643. else if (hasplus)
  644. {
  645. GER_GET_ATTR_RIGHTS(opattrs);
  646. GER_GET_ATTR_RIGHTA_EXT('+', allattrs, opattrs);
  647. }
  648. else
  649. {
  650. for ( i = 0; attrs[i]; i++ )
  651. {
  652. if ('\0' == *attrs[i]) {
  653. continue; /* skip an empty attr */
  654. }
  655. if (charray_inlist(noexpattrs, attrs[i]))
  656. {
  657. continue;
  658. }
  659. else if (charray_inlist(allattrs, attrs[i]) ||
  660. charray_inlist(opattrs, attrs[i]) ||
  661. (0 == strcasecmp(attrs[i], "dn")) ||
  662. (0 == strcasecmp(attrs[i], "distinguishedName")))
  663. {
  664. _ger_get_attr_rights ( gerpb, e, subjectndn, attrs[i],
  665. gerstr, gerstrsize, gerstrcap, isfirstattr, errbuf );
  666. isfirstattr = 0;
  667. }
  668. else
  669. {
  670. /* if the attr does not belong to the entry,
  671. "<attr>:none" is returned */
  672. if (!isfirstattr)
  673. {
  674. _append_gerstr(gerstr, gerstrsize, gerstrcap, ", ", NULL);
  675. }
  676. _append_gerstr(gerstr, gerstrsize, gerstrcap, attrs[i], ":");
  677. _append_gerstr(gerstr, gerstrsize, gerstrcap, "none", NULL);
  678. isfirstattr = 0;
  679. }
  680. }
  681. }
  682. }
  683. charray_free(allattrs);
  684. charray_free(opattrs);
  685. }
  686. else
  687. {
  688. Slapi_Attr *prevattr = NULL, *attr;
  689. char *type;
  690. while ( slapi_entry_next_attr ( e, prevattr, &attr ) == 0 )
  691. {
  692. if ( ! slapi_attr_flag_is_set (attr, SLAPI_ATTR_FLAG_OPATTR) )
  693. {
  694. slapi_attr_get_type ( attr, &type );
  695. _ger_get_attr_rights ( gerpb, e, subjectndn, type, gerstr,
  696. gerstrsize, gerstrcap, isfirstattr, errbuf );
  697. isfirstattr = 0;
  698. }
  699. prevattr = attr;
  700. }
  701. }
  702. if ( isfirstattr )
  703. {
  704. /* not a single attribute was retrived or specified */
  705. _append_gerstr(gerstr, gerstrsize, gerstrcap, "*:none", NULL);
  706. }
  707. return;
  708. }
  709. /*
  710. * controlType = LDAP_CONTROL_GET_EFFECTIVE_RIGHTS;
  711. * criticality = n/a;
  712. * controlValue = OCTET STRING of BER encoding of the SEQUENCE of
  713. * ENUMERATED LDAP code
  714. */
  715. void
  716. _ger_set_response_control (
  717. Slapi_PBlock *pb,
  718. int iscritical,
  719. int rc
  720. )
  721. {
  722. LDAPControl **resultctrls = NULL;
  723. LDAPControl gerrespctrl;
  724. BerElement *ber = NULL;
  725. struct berval *berval = NULL;
  726. int found = 0;
  727. int i;
  728. if ( (ber = der_alloc ()) == NULL )
  729. {
  730. goto bailout;
  731. }
  732. /* begin sequence, enumeration, end sequence */
  733. ber_printf ( ber, "{e}", rc );
  734. if ( ber_flatten ( ber, &berval ) != LDAP_SUCCESS )
  735. {
  736. goto bailout;
  737. }
  738. gerrespctrl.ldctl_oid = LDAP_CONTROL_GET_EFFECTIVE_RIGHTS;
  739. gerrespctrl.ldctl_iscritical = iscritical;
  740. gerrespctrl.ldctl_value.bv_val = berval->bv_val;
  741. gerrespctrl.ldctl_value.bv_len = berval->bv_len;
  742. slapi_pblock_get ( pb, SLAPI_RESCONTROLS, &resultctrls );
  743. for (i = 0; resultctrls && resultctrls[i]; i++)
  744. {
  745. if (strcmp(resultctrls[i]->ldctl_oid, LDAP_CONTROL_GET_EFFECTIVE_RIGHTS) == 0)
  746. {
  747. /*
  748. * We get here if search returns more than one entry
  749. * and this is not the first entry.
  750. */
  751. ldap_control_free ( resultctrls[i] );
  752. resultctrls[i] = slapi_dup_control (&gerrespctrl);
  753. found = 1;
  754. break;
  755. }
  756. }
  757. if ( !found )
  758. {
  759. /* slapi_pblock_set() will dup the control */
  760. slapi_pblock_set ( pb, SLAPI_ADD_RESCONTROL, &gerrespctrl );
  761. }
  762. bailout:
  763. ber_free ( ber, 1 ); /* ber_free() checks for NULL param */
  764. ber_bvfree ( berval ); /* ber_bvfree() checks for NULL param */
  765. }
  766. int
  767. _ger_generate_template_entry (
  768. Slapi_PBlock *pb
  769. )
  770. {
  771. Slapi_Entry *e = NULL;
  772. char **gerattrs = NULL;
  773. char **attrs = NULL;
  774. char **allowedattrs = NULL;
  775. char *templateentry = NULL;
  776. char *object = NULL;
  777. char *superior = NULL;
  778. char *p = NULL;
  779. const char *dn = NULL;
  780. Slapi_DN *sdn = NULL;
  781. char *dntype = NULL;
  782. int siz = 0;
  783. int len = 0;
  784. int i = 0;
  785. int notfirst = 0;
  786. int rc = LDAP_SUCCESS;
  787. slapi_pblock_get( pb, SLAPI_SEARCH_GERATTRS, &gerattrs );
  788. if (NULL == gerattrs)
  789. {
  790. slapi_log_error(SLAPI_LOG_ERR, plugin_name,
  791. "_ger_generate_template_entry - Objectclass info is expected "
  792. "in the attr list, e.g., \"*@person\"\n");
  793. rc = LDAP_SUCCESS;
  794. goto bailout;
  795. }
  796. for (i = 0; gerattrs && gerattrs[i]; i++)
  797. {
  798. object = strchr(gerattrs[i], '@');
  799. if (NULL != object && '\0' != *(++object))
  800. {
  801. break;
  802. }
  803. }
  804. if (NULL == object)
  805. {
  806. rc = LDAP_SUCCESS; /* no objectclass info; ok to return */
  807. goto bailout;
  808. }
  809. /*
  810. * Either @objectclass or @objectclass:dntype is accepted.
  811. * If @objectclass, the first MUST attributetype (or the first MAY
  812. * attributetype if MUST does not exist) is used for the attribute
  813. * type in the leaf RDN.
  814. * If @objectclass:dntype, dntype is used for the attribute type in the
  815. * leaf RDN.
  816. */
  817. dntype = strchr(object, ':');
  818. if (dntype) { /* @objectclasse:dntype */
  819. *dntype++ = '\0';
  820. }
  821. attrs = slapi_schema_list_objectclass_attributes(
  822. (const char *)object, SLAPI_OC_FLAG_REQUIRED);
  823. allowedattrs = slapi_schema_list_objectclass_attributes(
  824. (const char *)object, SLAPI_OC_FLAG_ALLOWED);
  825. charray_merge(&attrs, allowedattrs, 0 /* no copy */);
  826. slapi_ch_free((void **)&allowedattrs); /* free just allowedattrs */
  827. if (NULL == attrs) {
  828. rc = LDAP_SUCCESS; /* bogus objectclass info; ok to return */
  829. goto bailout;
  830. }
  831. for (i = 0; attrs[i]; i++)
  832. {
  833. if (0 == strcasecmp(attrs[i], "objectclass"))
  834. {
  835. /* <*attrp>: <object>\n\0 */
  836. siz += strlen(attrs[i]) + 4 + strlen(object);
  837. }
  838. else
  839. {
  840. /* <*attrp>: (template_attribute)\n\0 */
  841. siz += strlen(attrs[i]) + 4 + 20;
  842. }
  843. }
  844. /* get the target dn where the template entry is located */
  845. slapi_pblock_get( pb, SLAPI_TARGET_SDN, &sdn );
  846. dn = slapi_sdn_get_dn(sdn);
  847. if (dn)
  848. {
  849. /* dn: <attr>=<template_name>,<dn>\n\0 */
  850. if (dntype) {
  851. siz += strlen(dntype) + 30 + strlen(object) + strlen(dn);
  852. } else {
  853. siz += strlen(attrs[0]) + 30 + strlen(object) + strlen(dn);
  854. }
  855. }
  856. else
  857. {
  858. /* dn: <attr>=<template_name>\n\0 */
  859. if (dntype) {
  860. siz += strlen(dntype) + 30 + strlen(object);
  861. } else {
  862. siz += strlen(attrs[0]) + 30 + strlen(object);
  863. }
  864. }
  865. templateentry = (char *)slapi_ch_malloc(siz);
  866. if (NULL != dn && strlen(dn) > 0)
  867. {
  868. PR_snprintf(templateentry, siz,
  869. "dn: %s=template_%s_objectclass,%s\n",
  870. dntype?dntype:attrs[0], object, dn);
  871. }
  872. else
  873. {
  874. PR_snprintf(templateentry, siz,
  875. "dn: %s=template_%s_objectclass\n",
  876. dntype?dntype:attrs[0], object);
  877. }
  878. for (--i; i >= 0; i--)
  879. {
  880. len = strlen(templateentry);
  881. p = templateentry + len;
  882. if (0 == strcasecmp(attrs[i], "objectclass"))
  883. {
  884. PR_snprintf(p, siz - len, "%s: %s\n", attrs[i], object);
  885. }
  886. else
  887. {
  888. PR_snprintf(p, siz - len, "%s: (template_attribute)\n", attrs[i]);
  889. }
  890. }
  891. charray_free(attrs);
  892. while ((superior = slapi_schema_get_superior_name(object)) &&
  893. (0 != strcasecmp(superior, "top")))
  894. {
  895. if (notfirst)
  896. {
  897. slapi_ch_free_string(&object);
  898. }
  899. notfirst = 1;
  900. object = superior;
  901. attrs = slapi_schema_list_objectclass_attributes(
  902. (const char *)superior, SLAPI_OC_FLAG_REQUIRED);
  903. for (i = 0; attrs && attrs[i]; i++)
  904. {
  905. if (0 == strcasecmp(attrs[i], "objectclass"))
  906. {
  907. /* <*attrp>: <object>\n\0 */
  908. siz += strlen(attrs[i]) + 4 + strlen(object);
  909. }
  910. }
  911. templateentry = (char *)slapi_ch_realloc(templateentry, siz);
  912. for (--i; i >= 0; i--)
  913. {
  914. len = strlen(templateentry);
  915. p = templateentry + len;
  916. if (0 == strcasecmp(attrs[i], "objectclass"))
  917. {
  918. PR_snprintf(p, siz - len, "%s: %s\n", attrs[i], object);
  919. }
  920. }
  921. charray_free(attrs);
  922. }
  923. if (notfirst)
  924. {
  925. slapi_ch_free_string(&object);
  926. }
  927. slapi_ch_free_string(&superior);
  928. siz += 18; /* objectclass: top\n\0 */
  929. len = strlen(templateentry);
  930. templateentry = (char *)slapi_ch_realloc(templateentry, siz);
  931. p = templateentry + len;
  932. PR_snprintf(p, siz - len, "objectclass: top\n");
  933. e = slapi_str2entry(templateentry, SLAPI_STR2ENTRY_NOT_WELL_FORMED_LDIF);
  934. /* set the template entry to send the result to clients */
  935. slapi_pblock_set(pb, SLAPI_SEARCH_RESULT_ENTRY, e);
  936. bailout:
  937. slapi_ch_free_string(&templateentry);
  938. return rc;
  939. }
  940. int
  941. acl_get_effective_rights (
  942. Slapi_PBlock *pb,
  943. Slapi_Entry *e, /* target entry */
  944. char **attrs, /* Attribute of the entry */
  945. struct berval *val, /* value of attr. NOT USED */
  946. int access, /* requested access rights */
  947. char **errbuf
  948. )
  949. {
  950. Slapi_PBlock *gerpb = NULL;
  951. void *aclcb = NULL;
  952. char *subjectndn = NULL;
  953. char *gerstr = NULL;
  954. size_t gerstrsize = 0;
  955. size_t gerstrcap = 0;
  956. int iscritical = 0; /* critical may be missing or false http://tools.ietf.org/html/draft-ietf-ldapext-acl-model-08 */
  957. int rc = LDAP_SUCCESS;
  958. *errbuf = NULL;
  959. if (NULL == e) /* create a template entry from SLAPI_SEARCH_GERATTRS */
  960. {
  961. rc = _ger_generate_template_entry ( pb );
  962. slapi_pblock_get ( pb, SLAPI_SEARCH_RESULT_ENTRY, &e );
  963. if ( rc != LDAP_SUCCESS || NULL == e )
  964. {
  965. goto bailout;
  966. }
  967. }
  968. /*
  969. * Get the subject
  970. */
  971. rc = _ger_parse_control (pb, &subjectndn, &iscritical, errbuf );
  972. if ( rc != LDAP_SUCCESS )
  973. {
  974. goto bailout;
  975. }
  976. /*
  977. * The requestor should have g permission on the entry
  978. * to get the effective rights.
  979. */
  980. rc = _ger_g_permission_granted (pb, e, subjectndn, errbuf);
  981. if ( rc != LDAP_SUCCESS )
  982. {
  983. goto bailout;
  984. }
  985. /*
  986. * Construct a new pb
  987. */
  988. rc = _ger_new_gerpb ( pb, e, subjectndn, &gerpb, &aclcb, errbuf );
  989. if ( rc != LDAP_SUCCESS )
  990. {
  991. goto bailout;
  992. }
  993. /* Get entry level effective rights */
  994. _ger_get_entry_rights ( gerpb, e, subjectndn, &gerstr, &gerstrsize, &gerstrcap, errbuf );
  995. /*
  996. * Attribute level effective rights may not be NULL
  997. * even if entry level's is.
  998. */
  999. _ger_get_attrs_rights ( gerpb, e, subjectndn, attrs, &gerstr, &gerstrsize, &gerstrcap, errbuf );
  1000. bailout:
  1001. /*
  1002. * Now construct the response control
  1003. */
  1004. _ger_set_response_control ( pb, iscritical, rc );
  1005. if ( rc != LDAP_SUCCESS )
  1006. {
  1007. gerstr = slapi_ch_smprintf("entryLevelRights: %d\nattributeLevelRights: *:%d", rc, rc );
  1008. }
  1009. slapi_log_error(SLAPI_LOG_ACLSUMMARY, plugin_name,
  1010. "###### Effective Rights on Entry (%s) for Subject (%s) ######\n",
  1011. e?slapi_entry_get_ndn(e):"null", subjectndn?subjectndn:"null");
  1012. slapi_log_error(SLAPI_LOG_ACLSUMMARY, plugin_name, "%s\n", gerstr);
  1013. /* Restore pb */
  1014. _ger_release_gerpb ( &gerpb, &aclcb, pb );
  1015. /*
  1016. * General plugin uses SLAPI_RESULT_TEXT for error text. Here
  1017. * SLAPI_PB_RESULT_TEXT is exclusively shared with add, dse and schema.
  1018. * slapi_pblock_set() will free any previous data, and
  1019. * pblock_done() will free SLAPI_PB_RESULT_TEXT.
  1020. */
  1021. slapi_pblock_set (pb, SLAPI_PB_RESULT_TEXT, gerstr);
  1022. if ( !iscritical )
  1023. {
  1024. /*
  1025. * If return code is not LDAP_SUCCESS, the server would
  1026. * abort sending the data of the entry to the client.
  1027. */
  1028. rc = LDAP_SUCCESS;
  1029. }
  1030. slapi_ch_free ( (void **) &subjectndn );
  1031. slapi_ch_free ( (void **) &gerstr );
  1032. return rc;
  1033. }