aclplugin.c 12 KB

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