aclplugin.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  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. /*
  13. * There are 3 ACL PLUGIN points
  14. * PREOP, POSTOP and ACL plugin
  15. *
  16. */
  17. #include "acl.h"
  18. static Slapi_PluginDesc pdesc = { "acl", VENDOR, DS_PACKAGE_VERSION, "acl access check plugin" };
  19. char *plugin_name = ACL_PLUGIN_NAME;
  20. /* Prototypes */
  21. static int aclplugin_preop_search ( Slapi_PBlock *pb );
  22. static int aclplugin_preop_modify ( Slapi_PBlock *pb );
  23. int aclplugin_preop_common ( Slapi_PBlock *pb );
  24. /*******************************************************************************
  25. * ACL PLUGIN Architecture
  26. *
  27. * There are 3 registered plugins:
  28. *
  29. * 1) PREOP ACL Plugin
  30. * The preop plugin does all the initialization. It allocate the ACL
  31. * PBlock and copies stuff from the connection if it needs to.
  32. *
  33. * 2) POSTOP ACL Plugin
  34. * The Postop plugin cleans up the ACL PBlock. It copies Back to the
  35. * connection struct. The Postop bind & Unbind cleans up the
  36. * ACL CBlock ( struct hanging from conn struct ).
  37. *
  38. * 3) ACCESSCONTROL Plugin
  39. * Main module which does the access check. There are 5 entry point
  40. * from this plugin
  41. * a) Initilize the ACL system i.e read all the ACLs and generate the
  42. * the ACL List.
  43. * b) Check for ACI syntax.
  44. * c) Check for normal access.
  45. * d) Check for access to a mod request.
  46. * e) Update the in-memory ACL List.
  47. *
  48. *******************************************************************************/
  49. /*******************************************************************************
  50. * PREOP
  51. *******************************************************************************/
  52. /* Plugin identity is passed by the server in the plugin init function and must
  53. be supplied by the plugin to all internal operations it initiates
  54. */
  55. void* g_acl_preop_plugin_identity;
  56. int
  57. acl_preopInit (Slapi_PBlock *pb)
  58. {
  59. int rc = 0;
  60. /* save plugin identity to later pass to internal operations */
  61. rc = slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &g_acl_preop_plugin_identity);
  62. /* Declare plugin version */
  63. rc = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01);
  64. /* Provide descriptive information */
  65. rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void*)&pdesc);
  66. /* Register functions */
  67. rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_SEARCH_FN, (void*)aclplugin_preop_search);
  68. rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_COMPARE_FN, (void*)aclplugin_preop_search);
  69. rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_ADD_FN, (void*)aclplugin_preop_modify);
  70. rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODIFY_FN, (void*)aclplugin_preop_modify);
  71. rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODRDN_FN, (void*)aclplugin_preop_modify);
  72. rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_DELETE_FN, (void*)aclplugin_preop_modify);
  73. #if 0
  74. /*
  75. * XXXmcs: In order to support access control checking from
  76. * extended operations, we need a SLAPI_PLUGIN_PRE_EXTENDED_FN hook.
  77. * But today no such entry point exists.
  78. */
  79. rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_EXTENDED_FN, (void*)aclplugin_preop_modify);
  80. #endif
  81. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "<= acl_preop_Init %d\n", rc );
  82. return( rc );
  83. }
  84. /* For preop search we do two things:
  85. * 1) based on the search base, we preselect the acls.
  86. * 2) also get hold of a acl_pblock for use
  87. */
  88. static int
  89. aclplugin_preop_search ( Slapi_PBlock *pb )
  90. {
  91. int scope;
  92. const char *base = NULL;
  93. Slapi_DN *sdn = NULL;
  94. int optype;
  95. int isRoot;
  96. int isProxy = 0;
  97. int rc = 0;
  98. char *errtxt = NULL;
  99. char *proxy_dn = NULL;
  100. TNF_PROBE_0_DEBUG(aclplugin_preop_search_start ,"ACL","");
  101. slapi_pblock_get ( pb, SLAPI_OPERATION_TYPE, &optype );
  102. slapi_pblock_get ( pb, SLAPI_REQUESTOR_ISROOT, &isRoot );
  103. if (LDAP_SUCCESS == proxyauth_get_dn(pb, &proxy_dn, &errtxt) && proxy_dn) {
  104. isProxy = 1;
  105. }
  106. slapi_ch_free_string(&proxy_dn);
  107. if ( isRoot && !isProxy) {
  108. TNF_PROBE_1_DEBUG(aclplugin_preop_search_end ,"ACL","",
  109. tnf_string,isroot,"");
  110. return rc;
  111. }
  112. slapi_pblock_get( pb, SLAPI_SEARCH_TARGET_SDN, &sdn );
  113. base = slapi_sdn_get_dn(sdn);
  114. /* For anonymous client doing search nothing needs to be set up */
  115. if ( optype == SLAPI_OPERATION_SEARCH && aclanom_is_client_anonymous ( pb ) &&
  116. ! slapi_dn_issuffix( base, "cn=monitor") ) {
  117. TNF_PROBE_1_DEBUG(aclplugin_preop_search_end ,"ACL","",
  118. tnf_string,anon,"");
  119. return rc;
  120. }
  121. if ( 0 == ( rc = aclplugin_preop_common( pb ))) {
  122. slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope );
  123. acllist_init_scan ( pb, scope, base );
  124. }
  125. TNF_PROBE_0_DEBUG(aclplugin_preop_search_end ,"ACL","");
  126. return rc;
  127. }
  128. /*
  129. * For rest of the opertion type, we get a hold of the acl
  130. * private Block.
  131. */
  132. static int
  133. aclplugin_preop_modify ( Slapi_PBlock *pb )
  134. {
  135. /*
  136. * Note: since we don't keep the anom profile for modifies, we have to go
  137. * through the regular process to check the access.
  138. */
  139. return aclplugin_preop_common( pb );
  140. }
  141. /*
  142. * Common function that is called by aclplugin_preop_search() and
  143. * aclplugin_preop_modify().
  144. *
  145. * Return values:
  146. * 0 - all is well; proceed.
  147. * 1 - fatal error; result has been sent to client.
  148. */
  149. int
  150. aclplugin_preop_common( Slapi_PBlock *pb )
  151. {
  152. char *proxy_dn = NULL; /* id being assumed */
  153. char *dn; /* proxy master */
  154. char *errtext = NULL;
  155. int lderr;
  156. Acl_PBlock *aclpb;
  157. TNF_PROBE_0_DEBUG(aclplugin_preop_common_start ,"ACL","");
  158. aclpb = acl_get_aclpb ( pb, ACLPB_BINDDN_PBLOCK );
  159. if (aclpb == NULL) {
  160. slapi_log_error(SLAPI_LOG_ACL, plugin_name, "aclplugin_preop_common - Error: aclpb is NULL\n" );
  161. slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
  162. return 1;
  163. }
  164. /* See if we have initialized already */
  165. if ( aclpb->aclpb_state & ACLPB_INITIALIZED ) goto done;
  166. /*
  167. * The following mallocs memory for proxy_dn, but not the dn.
  168. * The proxy_dn is the id being assumed, while dn
  169. * is the "proxy master".
  170. */
  171. if ( LDAP_SUCCESS != ( lderr = proxyauth_get_dn( pb, &proxy_dn, &errtext ))) {
  172. /*
  173. * Fatal error -- send a result to the client and arrange to skip
  174. * any further processing.
  175. */
  176. slapi_send_ldap_result( pb, lderr, NULL, errtext, 0, NULL );
  177. TNF_PROBE_1_DEBUG(aclplugin_preop_common_end ,"ACL","",
  178. tnf_string,proxid_error,"");
  179. slapi_ch_free_string(&proxy_dn);
  180. return 1; /* skip any further processing */
  181. }
  182. slapi_pblock_get ( pb, SLAPI_REQUESTOR_DN, &dn );
  183. /*
  184. * The dn is copied into the aclpb during initialization.
  185. */
  186. if ( proxy_dn) {
  187. TNF_PROBE_0_DEBUG(proxyacpb_init_start,"ACL","");
  188. slapi_log_error(SLAPI_LOG_ACL, plugin_name,
  189. "aclplugin_preop_common - Proxied authorization dn is (%s)\n", proxy_dn );
  190. acl_init_aclpb ( pb, aclpb, proxy_dn, 1 );
  191. aclpb = acl_new_proxy_aclpb ( pb );
  192. acl_init_aclpb ( pb, aclpb, dn, 0 );
  193. slapi_ch_free ( (void **) &proxy_dn );
  194. TNF_PROBE_0_DEBUG(proxyacpb_init_end,"ACL","");
  195. } else {
  196. TNF_PROBE_0_DEBUG(aclpb_init_start,"ACL","");
  197. acl_init_aclpb ( pb, aclpb, dn, 1 );
  198. TNF_PROBE_0_DEBUG(aclpb_init_end,"ACL","");
  199. }
  200. done:
  201. TNF_PROBE_0_DEBUG(aclplugin_preop_common_end ,"ACL","");
  202. return 0;
  203. }
  204. /*******************************************************************************
  205. * POSTOP
  206. *******************************************************************************/
  207. /*******************************************************************************
  208. * ACCESSCONTROL PLUGIN
  209. *******************************************************************************/
  210. void* g_acl_plugin_identity;
  211. /* For now, the acl component is implemented as 2 different plugins */
  212. /* Return the right plugin identity */
  213. void * aclplugin_get_identity(int plug) {
  214. if (plug == ACL_PLUGIN_IDENTITY)
  215. return g_acl_plugin_identity;
  216. if (plug == ACL_PREOP_PLUGIN_IDENTITY)
  217. return g_acl_preop_plugin_identity;
  218. return NULL;
  219. }
  220. int
  221. aclplugin_init (Slapi_PBlock *pb )
  222. {
  223. int rc = 0; /* OK */
  224. rc = aclinit_main();
  225. return rc;
  226. }
  227. int
  228. aclplugin_stop ( Slapi_PBlock *pb )
  229. {
  230. int rc = 0; /* OK */
  231. free_acl_avl_list();
  232. ACL_Destroy();
  233. acl_destroy_aclpb_pool();
  234. acl_remove_ext();
  235. ACL_AttrGetterHashDestroy();
  236. ACL_MethodHashDestroy();
  237. ACL_DestroyPools();
  238. aclanom__del_profile(1);
  239. aclgroup_free();
  240. //aclext_free_lockarray();
  241. acllist_free();
  242. return rc;
  243. }
  244. int
  245. acl_init( Slapi_PBlock *pb )
  246. {
  247. int rc =0;
  248. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "=> acl_init\n" );
  249. if ( 0 != acl_init_ext() ) {
  250. slapi_log_error(SLAPI_LOG_ERR, plugin_name,
  251. "acl_init - Unable to initialize the extensions\n");
  252. return 1;
  253. }
  254. /* save plugin identity to later pass to internal operations */
  255. rc = slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &g_acl_plugin_identity);
  256. rc = slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
  257. (void *) SLAPI_PLUGIN_VERSION_01 );
  258. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
  259. (void *)&pdesc );
  260. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_START_FN, (void *) aclplugin_init );
  261. rc = slapi_pblock_set( pb, SLAPI_PLUGIN_CLOSE_FN, (void *) aclplugin_stop );
  262. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_ACL_SYNTAX_CHECK,
  263. (void *) acl_verify_aci_syntax );
  264. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_ACL_ALLOW_ACCESS,
  265. (void *) acl_access_allowed_main );
  266. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_ACL_MODS_ALLOWED,
  267. (void *) acl_check_mods );
  268. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_ACL_MODS_UPDATE,
  269. (void *) acl_modified );
  270. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "<= acl_init %d\n", rc);
  271. return( rc );
  272. }
  273. /*
  274. *
  275. * acl_access_allowed_main
  276. * Main interface to the plugin. Calls different access check functions
  277. * based on the flag.
  278. *
  279. *
  280. * Returns:
  281. * LDAP_SUCCESS -- access is granted
  282. * LDAP_INSUFFICIENT_ACCESS -- access denied
  283. * <other ldap error> -- ex: opererations error
  284. *
  285. */
  286. int
  287. acl_access_allowed_main ( Slapi_PBlock *pb, Slapi_Entry *e, char **attrs,
  288. struct berval *val, int access , int flags, char **errbuf)
  289. {
  290. int rc =0;
  291. char *attr = NULL;
  292. TNF_PROBE_0_DEBUG(acl_access_allowed_main_start,"ACL","");
  293. if (attrs && *attrs) attr = attrs[0];
  294. if (ACLPLUGIN_ACCESS_READ_ON_ENTRY == flags) {
  295. rc = acl_read_access_allowed_on_entry ( pb, e, attrs, access);
  296. } else if ( ACLPLUGIN_ACCESS_READ_ON_ATTR == flags) {
  297. if (attr == NULL) {
  298. slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "acl_access_allowed_main - Missing attribute\n" );
  299. rc = LDAP_OPERATIONS_ERROR;
  300. } else {
  301. rc = acl_read_access_allowed_on_attr ( pb, e, attr, val, access);
  302. }
  303. } else if ( ACLPLUGIN_ACCESS_READ_ON_VLV == flags)
  304. rc = acl_access_allowed_disjoint_resource ( pb, e, attr, val, access);
  305. else if ( ACLPLUGIN_ACCESS_MODRDN == flags)
  306. rc = acl_access_allowed_modrdn ( pb, e, attr, val, access);
  307. else if ( ACLPLUGIN_ACCESS_GET_EFFECTIVE_RIGHTS == flags)
  308. rc = acl_get_effective_rights ( pb, e, attrs, val, access, errbuf );
  309. else
  310. rc = acl_access_allowed ( pb, e, attr, val, access);
  311. /* generate the appropriate error message */
  312. if ( ( rc != LDAP_SUCCESS ) && errbuf &&
  313. ( ACLPLUGIN_ACCESS_GET_EFFECTIVE_RIGHTS != flags ) &&
  314. ( access & ( SLAPI_ACL_WRITE | SLAPI_ACL_ADD | SLAPI_ACL_DELETE | SLAPI_ACL_MODDN ))) {
  315. char *edn = slapi_entry_get_dn ( e );
  316. acl_gen_err_msg(access, edn, attr, errbuf);
  317. }
  318. TNF_PROBE_0_DEBUG(acl_access_allowed_main_end,"ACL","");
  319. return rc;
  320. }