aclplugin.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /*
  42. * There are 3 ACL PLUGIN points
  43. * PREOP, POSTOP and ACL plugin
  44. *
  45. */
  46. #include "acl.h"
  47. static Slapi_PluginDesc pdesc = { "acl", VENDOR, DS_PACKAGE_VERSION, "acl access check plugin" };
  48. char *plugin_name = ACL_PLUGIN_NAME;
  49. /* Prototypes */
  50. static int aclplugin_preop_search ( Slapi_PBlock *pb );
  51. static int aclplugin_preop_modify ( Slapi_PBlock *pb );
  52. int aclplugin_preop_common ( Slapi_PBlock *pb );
  53. /*******************************************************************************
  54. * ACL PLUGIN Architecture
  55. *
  56. * There are 3 registered plugins:
  57. *
  58. * 1) PREOP ACL Plugin
  59. * The preop plugin does all the initialization. It allocate the ACL
  60. * PBlock and copies stuff from the connection if it needs to.
  61. *
  62. * 2) POSTOP ACL Plugin
  63. * The Postop plugin cleans up the ACL PBlock. It copies Back to the
  64. * connection struct. The Postop bind & Unbind cleans up the
  65. * ACL CBlock ( struct hanging from conn struct ).
  66. *
  67. * 3) ACCESSCONTROL Plugin
  68. * Main module which does the access check. There are 5 entry point
  69. * from this plugin
  70. * a) Initilize the ACL system i.e read all the ACLs and generate the
  71. * the ACL List.
  72. * b) Check for ACI syntax.
  73. * c) Check for normal access.
  74. * d) Check for access to a mod request.
  75. * e) Update the in-memory ACL List.
  76. *
  77. *******************************************************************************/
  78. /*******************************************************************************
  79. * PREOP
  80. *******************************************************************************/
  81. /* Plugin identity is passed by the server in the plugin init function and must
  82. be supplied by the plugin to all internal operations it initiates
  83. */
  84. void* g_acl_preop_plugin_identity;
  85. int
  86. acl_preopInit (Slapi_PBlock *pb)
  87. {
  88. int rc = 0;
  89. /* save plugin identity to later pass to internal operations */
  90. rc = slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &g_acl_preop_plugin_identity);
  91. /* Declare plugin version */
  92. rc = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01);
  93. /* Provide descriptive information */
  94. rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void*)&pdesc);
  95. /* Register functions */
  96. rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_SEARCH_FN, (void*)aclplugin_preop_search);
  97. rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_COMPARE_FN, (void*)aclplugin_preop_search);
  98. rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_ADD_FN, (void*)aclplugin_preop_modify);
  99. rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODIFY_FN, (void*)aclplugin_preop_modify);
  100. rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODRDN_FN, (void*)aclplugin_preop_modify);
  101. rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_DELETE_FN, (void*)aclplugin_preop_modify);
  102. #if 0
  103. /*
  104. * XXXmcs: In order to support access control checking from
  105. * extended operations, we need a SLAPI_PLUGIN_PRE_EXTENDED_FN hook.
  106. * But today no such entry point exists.
  107. */
  108. rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_EXTENDED_FN, (void*)aclplugin_preop_modify);
  109. #endif
  110. slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "<= acl_preop_Init %d\n", rc );
  111. return( rc );
  112. }
  113. /* For preop search we do two things:
  114. * 1) based on the search base, we preselect the acls.
  115. * 2) also get hold of a acl_pblock for use
  116. */
  117. static int
  118. aclplugin_preop_search ( Slapi_PBlock *pb )
  119. {
  120. int scope;
  121. const char *base = NULL;
  122. Slapi_DN *sdn = NULL;
  123. int optype;
  124. int isRoot;
  125. int rc = 0;
  126. TNF_PROBE_0_DEBUG(aclplugin_preop_search_start ,"ACL","");
  127. slapi_pblock_get ( pb, SLAPI_OPERATION_TYPE, &optype );
  128. slapi_pblock_get ( pb, SLAPI_REQUESTOR_ISROOT, &isRoot );
  129. if ( isRoot ) {
  130. TNF_PROBE_1_DEBUG(aclplugin_preop_search_end ,"ACL","",
  131. tnf_string,isroot,"");
  132. return rc;
  133. }
  134. slapi_pblock_get( pb, SLAPI_SEARCH_TARGET_SDN, &sdn );
  135. base = slapi_sdn_get_dn(sdn);
  136. /* For anonymous client doing search nothing needs to be set up */
  137. if ( optype == SLAPI_OPERATION_SEARCH && aclanom_is_client_anonymous ( pb ) &&
  138. ! slapi_dn_issuffix( base, "cn=monitor") ) {
  139. TNF_PROBE_1_DEBUG(aclplugin_preop_search_end ,"ACL","",
  140. tnf_string,anon,"");
  141. return rc;
  142. }
  143. if ( 0 == ( rc = aclplugin_preop_common( pb ))) {
  144. slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope );
  145. acllist_init_scan ( pb, scope, base );
  146. }
  147. TNF_PROBE_0_DEBUG(aclplugin_preop_search_end ,"ACL","");
  148. return rc;
  149. }
  150. /*
  151. * For rest of the opertion type, we get a hold of the acl
  152. * private Block.
  153. */
  154. static int
  155. aclplugin_preop_modify ( Slapi_PBlock *pb )
  156. {
  157. /*
  158. * Note: since we don't keep the anom profile for modifies, we have to go
  159. * through the regular process to check the access.
  160. */
  161. return aclplugin_preop_common( pb );
  162. }
  163. /*
  164. * Common function that is called by aclplugin_preop_search() and
  165. * aclplugin_preop_modify().
  166. *
  167. * Return values:
  168. * 0 - all is well; proceed.
  169. * 1 - fatal error; result has been sent to client.
  170. */
  171. int
  172. aclplugin_preop_common( Slapi_PBlock *pb )
  173. {
  174. char *proxy_dn = NULL; /* id being assumed */
  175. char *dn; /* proxy master */
  176. char *errtext = NULL;
  177. int lderr;
  178. Acl_PBlock *aclpb;
  179. TNF_PROBE_0_DEBUG(aclplugin_preop_common_start ,"ACL","");
  180. aclpb = acl_get_aclpb ( pb, ACLPB_BINDDN_PBLOCK );
  181. if (aclpb == NULL) {
  182. slapi_log_error( SLAPI_LOG_ACL, plugin_name, "aclplugin_preop_common: Error: aclpb is NULL\n" );
  183. slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
  184. return 1;
  185. }
  186. /* See if we have initialized already */
  187. if ( aclpb->aclpb_state & ACLPB_INITIALIZED ) goto done;
  188. /*
  189. * The following mallocs memory for proxy_dn, but not the dn.
  190. * The proxy_dn is the id being assumed, while dn
  191. * is the "proxy master".
  192. */
  193. if ( LDAP_SUCCESS != ( lderr = proxyauth_get_dn( pb, &proxy_dn, &errtext ))) {
  194. /*
  195. * Fatal error -- send a result to the client and arrange to skip
  196. * any further processing.
  197. */
  198. slapi_send_ldap_result( pb, lderr, NULL, errtext, 0, NULL );
  199. TNF_PROBE_1_DEBUG(aclplugin_preop_common_end ,"ACL","",
  200. tnf_string,proxid_error,"");
  201. slapi_ch_free_string(&proxy_dn);
  202. return 1; /* skip any further processing */
  203. }
  204. slapi_pblock_get ( pb, SLAPI_REQUESTOR_DN, &dn );
  205. /*
  206. * The dn is copied into the aclpb during initialization.
  207. */
  208. if ( proxy_dn) {
  209. TNF_PROBE_0_DEBUG(proxyacpb_init_start,"ACL","");
  210. slapi_log_error( SLAPI_LOG_ACL, plugin_name,
  211. "proxied authorization dn is (%s)\n", proxy_dn );
  212. acl_init_aclpb ( pb, aclpb, proxy_dn, 1 );
  213. aclpb = acl_new_proxy_aclpb ( pb );
  214. acl_init_aclpb ( pb, aclpb, dn, 0 );
  215. slapi_ch_free ( (void **) &proxy_dn );
  216. TNF_PROBE_0_DEBUG(proxyacpb_init_end,"ACL","");
  217. } else {
  218. TNF_PROBE_0_DEBUG(aclpb_init_start,"ACL","");
  219. acl_init_aclpb ( pb, aclpb, dn, 1 );
  220. TNF_PROBE_0_DEBUG(aclpb_init_end,"ACL","");
  221. }
  222. done:
  223. TNF_PROBE_0_DEBUG(aclplugin_preop_common_end ,"ACL","");
  224. return 0;
  225. }
  226. /*******************************************************************************
  227. * POSTOP
  228. *******************************************************************************/
  229. /*******************************************************************************
  230. * ACCESSCONTROL PLUGIN
  231. *******************************************************************************/
  232. void* g_acl_plugin_identity;
  233. /* For now, the acl component is implemented as 2 different plugins */
  234. /* Return the right plugin identity */
  235. void * aclplugin_get_identity(int plug) {
  236. if (plug == ACL_PLUGIN_IDENTITY)
  237. return g_acl_plugin_identity;
  238. if (plug == ACL_PREOP_PLUGIN_IDENTITY)
  239. return g_acl_preop_plugin_identity;
  240. return NULL;
  241. }
  242. int
  243. aclplugin_init (Slapi_PBlock *pb )
  244. {
  245. int rc = 0; /* OK */
  246. rc = aclinit_main ( pb );
  247. return rc;
  248. }
  249. int
  250. aclplugin_stop ( Slapi_PBlock *pb )
  251. {
  252. int rc = 0; /* OK */
  253. ACL_Destroy();
  254. acl_destroy_aclpb_pool();
  255. ACL_AttrGetterHashDestroy();
  256. ACL_MethodHashDestroy();
  257. ACL_DestroyPools();
  258. free_acl_avl_list();
  259. aclanom__del_profile(1);
  260. aclgroup_free();
  261. //aclext_free_lockarray();
  262. acllist_free();
  263. return rc;
  264. }
  265. int
  266. acl_init( Slapi_PBlock *pb )
  267. {
  268. int rc =0;
  269. slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "=> acl_init\n" );
  270. if ( 0 != acl_init_ext() ) {
  271. slapi_log_error ( SLAPI_LOG_FATAL, plugin_name,
  272. "Unable to initialize the extensions\n");
  273. return 1;
  274. }
  275. /* save plugin identity to later pass to internal operations */
  276. rc = slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &g_acl_plugin_identity);
  277. rc = slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
  278. (void *) SLAPI_PLUGIN_VERSION_01 );
  279. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
  280. (void *)&pdesc );
  281. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_START_FN, (void *) aclplugin_init );
  282. rc = slapi_pblock_set( pb, SLAPI_PLUGIN_CLOSE_FN, (void *) aclplugin_stop );
  283. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_ACL_SYNTAX_CHECK,
  284. (void *) acl_verify_aci_syntax );
  285. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_ACL_ALLOW_ACCESS,
  286. (void *) acl_access_allowed_main );
  287. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_ACL_MODS_ALLOWED,
  288. (void *) acl_check_mods );
  289. rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_ACL_MODS_UPDATE,
  290. (void *) acl_modified );
  291. slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "<= acl_init %d\n", rc);
  292. return( rc );
  293. }
  294. /*
  295. *
  296. * acl_access_allowed_main
  297. * Main interface to the plugin. Calls different access check functions
  298. * based on the flag.
  299. *
  300. *
  301. * Returns:
  302. * LDAP_SUCCESS -- access is granted
  303. * LDAP_INSUFFICIENT_ACCESS -- access denied
  304. * <other ldap error> -- ex: opererations error
  305. *
  306. */
  307. int
  308. acl_access_allowed_main ( Slapi_PBlock *pb, Slapi_Entry *e, char **attrs,
  309. struct berval *val, int access , int flags, char **errbuf)
  310. {
  311. int rc =0;
  312. char *attr = NULL;
  313. TNF_PROBE_0_DEBUG(acl_access_allowed_main_start,"ACL","");
  314. if (attrs && *attrs) attr = attrs[0];
  315. if (ACLPLUGIN_ACCESS_READ_ON_ENTRY == flags) {
  316. rc = acl_read_access_allowed_on_entry ( pb, e, attrs, access);
  317. } else if ( ACLPLUGIN_ACCESS_READ_ON_ATTR == flags) {
  318. if (attr == NULL) {
  319. slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "Missing attribute\n" );
  320. rc = LDAP_OPERATIONS_ERROR;
  321. } else {
  322. rc = acl_read_access_allowed_on_attr ( pb, e, attr, val, access);
  323. }
  324. } else if ( ACLPLUGIN_ACCESS_READ_ON_VLV == flags)
  325. rc = acl_access_allowed_disjoint_resource ( pb, e, attr, val, access);
  326. else if ( ACLPLUGIN_ACCESS_MODRDN == flags)
  327. rc = acl_access_allowed_modrdn ( pb, e, attr, val, access);
  328. else if ( ACLPLUGIN_ACCESS_GET_EFFECTIVE_RIGHTS == flags)
  329. rc = acl_get_effective_rights ( pb, e, attrs, val, access, errbuf );
  330. else
  331. rc = acl_access_allowed ( pb, e, attr, val, access);
  332. /* generate the appropriate error message */
  333. if ( ( rc != LDAP_SUCCESS ) && errbuf &&
  334. ( ACLPLUGIN_ACCESS_GET_EFFECTIVE_RIGHTS != flags ) &&
  335. ( access & ( SLAPI_ACL_WRITE | SLAPI_ACL_ADD | SLAPI_ACL_DELETE | SLAPI_ACL_MODDN ))) {
  336. char *edn = slapi_entry_get_dn ( e );
  337. acl_gen_err_msg(access, edn, attr, errbuf);
  338. }
  339. TNF_PROBE_0_DEBUG(acl_access_allowed_main_end,"ACL","");
  340. return rc;
  341. }
  342. #ifdef _WIN32
  343. int *module_ldap_debug = 0;
  344. void plugin_init_debug_level ( int *level_ptr )
  345. {
  346. module_ldap_debug = level_ptr;
  347. }
  348. #endif