rootdse.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  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. /* rootdse.c - routines to manage the root DSE */
  42. #include <stdio.h>
  43. #include "slap.h"
  44. #include "fe.h"
  45. /* XXXmcs: why not look at the NO-USER-MODIFICATION flag instead? */
  46. static char *readonly_attributes[] = {
  47. "namingcontexts",
  48. "nsBackendSuffix",
  49. "subschemasubentry",
  50. "supportedldapversion",
  51. "supportedcontrol",
  52. "supportedextension",
  53. "supportedsaslmechanisms",
  54. "dataversion",
  55. "ref",
  56. "vendorName",
  57. "vendorVersion",
  58. ATTR_NETSCAPEMDSUFFIX,
  59. NULL
  60. };
  61. static char *writable_attributes[] = {
  62. "copiedfrom",
  63. "copyingfrom",
  64. "aci",
  65. NULL
  66. };
  67. /*
  68. * function: is_readonly_attr
  69. * args: attr - candidate attribute name
  70. * returns: 0 if this attribute may be written to the root DSE
  71. * 1 if it may not be written.
  72. * notes: should probably be integrated into syntax AVL tree, so that
  73. * this list can be configured at runtime.
  74. */
  75. static int
  76. rootdse_is_readonly_attr( char *attr )
  77. {
  78. int i;
  79. if ( NULL == attr ) {
  80. return 1; /* I guess. It's not really an attribute at all */
  81. }
  82. if ( NULL == readonly_attributes ) {
  83. return 0;
  84. }
  85. /*
  86. * optimization: check for attributes we're likely to be writing
  87. * frequently.
  88. */
  89. for ( i = 0; NULL != writable_attributes[ i ]; i++ ) {
  90. if ( strncasecmp( attr, writable_attributes[ i ],
  91. strlen( writable_attributes[ i ])) == 0 ) {
  92. return 0;
  93. }
  94. }
  95. for ( i = 0; NULL != readonly_attributes[ i ]; i++ ) {
  96. if ( strncasecmp( attr, readonly_attributes[ i ],
  97. strlen( readonly_attributes[ i ])) == 0 ) {
  98. return 1;
  99. }
  100. }
  101. return 0;
  102. }
  103. /*
  104. * Handle a read operation on the root DSE (the entry with DN "");
  105. * Note: we're copying a lot of attributes here. It might be better
  106. * to keep track of which we really need to free, and arrange that
  107. * the others are unlinked from the attribute list of the entry
  108. * before calling slapi_entry_free().
  109. */
  110. int
  111. read_root_dse( Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg )
  112. {
  113. int i;
  114. struct berval *vals[2];
  115. struct berval val;
  116. struct berval **bvals;
  117. Slapi_Backend *be;
  118. char *cookie = NULL;
  119. char **strs;
  120. void *node;
  121. Slapi_DN *sdn;
  122. /*
  123. * Check that we were doing a base search on the root dse.
  124. */
  125. {
  126. int scope;
  127. slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope );
  128. if(scope!=LDAP_SCOPE_BASE)
  129. {
  130. *returncode= LDAP_NO_SUCH_OBJECT;
  131. return SLAPI_DSE_CALLBACK_ERROR;
  132. }
  133. }
  134. vals[0] = &val;
  135. vals[1] = NULL;
  136. /* loop through backend suffixes to get namingcontexts attr */
  137. attrlist_delete( &e->e_attrs, "namingcontexts");
  138. sdn = slapi_get_first_suffix(&node, 0);
  139. while (sdn)
  140. {
  141. val.bv_val = (char*)slapi_sdn_get_dn(sdn); /* jcm: had to cast away const */
  142. val.bv_len = strlen( val.bv_val );
  143. attrlist_merge( &e->e_attrs, "namingcontexts", vals );
  144. sdn = slapi_get_next_suffix(&node, 0);
  145. }
  146. attrlist_delete( &e->e_attrs, "nsBackendSuffix");
  147. for (be = slapi_get_first_backend(&cookie); be != NULL;
  148. be = slapi_get_next_backend(cookie)) {
  149. char * base;
  150. char * be_name;
  151. const Slapi_DN *be_suffix;
  152. if (slapi_be_private(be)) continue;
  153. /* tolerate a backend under construction containing no suffix */
  154. if ((be_suffix = slapi_be_getsuffix(be, 0)) == NULL) continue;
  155. if ((base = (char *)slapi_sdn_get_dn(be_suffix)) == NULL) continue;
  156. if ((be_name = slapi_be_get_name(be)) == NULL) continue;
  157. val.bv_len = strlen(base)+strlen(be_name)+1;
  158. val.bv_val = slapi_ch_malloc(val.bv_len+1);
  159. sprintf(val.bv_val, "%s:%s", be_name, base);
  160. attrlist_merge(&e->e_attrs, "nsBackendSuffix", vals);
  161. slapi_ch_free((void **) &val.bv_val);
  162. }
  163. slapi_ch_free((void **)&cookie);
  164. /* schema entry */
  165. val.bv_val = SLAPD_SCHEMA_DN;
  166. val.bv_len = sizeof( SLAPD_SCHEMA_DN ) - 1;
  167. attrlist_replace( &e->e_attrs, "subschemasubentry", vals );
  168. /* supported extended operations */
  169. attrlist_delete( &e->e_attrs, "supportedExtension");
  170. if (( strs = slapi_get_supported_extended_ops_copy()) != NULL ) {
  171. for ( i = 0; strs[i] != NULL; ++i ) {
  172. val.bv_val = strs[i];
  173. val.bv_len = strlen( strs[i] );
  174. attrlist_merge( &e->e_attrs, "supportedExtension", vals );
  175. }
  176. charray_free(strs);
  177. }
  178. /* supported controls */
  179. attrlist_delete( &e->e_attrs, "supportedControl");
  180. if ( slapi_get_supported_controls_copy( &strs, NULL ) == 0
  181. && strs != NULL ) {
  182. for ( i = 0; strs[i] != NULL; ++i ) {
  183. val.bv_val = strs[i];
  184. val.bv_len = strlen( strs[i] );
  185. attrlist_merge( &e->e_attrs, "supportedControl", vals );
  186. }
  187. charray_free(strs);
  188. }
  189. /* supported sasl mechanisms */
  190. attrlist_delete( &e->e_attrs, "supportedSASLMechanisms");
  191. if (( strs = ids_sasl_listmech (pb)) != NULL ) {
  192. for ( i = 0; strs[i] != NULL; ++i ) {
  193. val.bv_val = strs[i];
  194. val.bv_len = strlen( strs[i] );
  195. attrlist_merge( &e->e_attrs, "supportedSASLMechanisms", vals );
  196. }
  197. charray_free(strs);
  198. }
  199. /* supported LDAP versions */
  200. val.bv_val = "2";
  201. val.bv_len = 1;
  202. attrlist_replace( &e->e_attrs, "supportedldapversion", vals );
  203. val.bv_val = "3";
  204. val.bv_len = 1;
  205. attrlist_merge( &e->e_attrs, "supportedldapversion", vals );
  206. /* superior references (ref attribute) */
  207. attrlist_delete( &e->e_attrs, "ref");
  208. if (( bvals = g_get_default_referral()) != NULL ) {
  209. for ( i = 0; bvals[i] != NULL; ++i ) {
  210. val.bv_val = bvals[i]->bv_val;
  211. val.bv_len = bvals[i]->bv_len;
  212. attrlist_merge( &e->e_attrs, "ref", vals );
  213. }
  214. }
  215. /* RFC 3045 attributes: vendorName and vendorVersion */
  216. val.bv_val = SLAPD_VENDOR_NAME;
  217. val.bv_len = strlen( val.bv_val );
  218. attrlist_replace( &e->e_attrs, "vendorName", vals );
  219. val.bv_val = slapd_get_version_value();
  220. val.bv_len = strlen( val.bv_val );
  221. attrlist_replace( &e->e_attrs, "vendorVersion", vals );
  222. slapi_ch_free( (void **)&val.bv_val );
  223. /* Server Data Version */
  224. if (( val.bv_val = (char*)get_server_dataversion()) != NULL ) { /* jcm cast away const */
  225. val.bv_len = strlen( val.bv_val );
  226. attrlist_replace( &e->e_attrs, attr_dataversion, vals );
  227. }
  228. /* machine data suffix
  229. * this has been added in 4.0 for replication purpose
  230. * and since 5.0 is now unused by the core server,
  231. * however some functionalities of the console framework 5.01
  232. * still depend on this
  233. */
  234. if (( val.bv_val = get_config_DN()) != NULL ) {
  235. val.bv_len = strlen( val.bv_val );
  236. attrlist_replace( &e->e_attrs, ATTR_NETSCAPEMDSUFFIX, vals );
  237. }
  238. #ifdef notdef
  239. /* XXXggood testing - print the size of the changelog db */
  240. {
  241. unsigned int clsize;
  242. clsize = get_changelog_size();
  243. sprintf( buf, "%u", clsize );
  244. val.bv_val = buf;
  245. val.bv_len = strlen( buf );
  246. attrlist_replace( &e->e_attrs, "changelogsize", vals );
  247. slapi_ch_free((void**)&val.bv_val );
  248. }
  249. #endif /* notdef */
  250. /* vlvsearch is list of dns to VLV Search Specifications */
  251. attrlist_delete( &e->e_attrs, "vlvsearch");
  252. cookie = NULL;
  253. be = slapi_get_first_backend(&cookie);
  254. while (be)
  255. {
  256. if(!be->be_private)
  257. {
  258. /* Generate searches to find the VLV Search Specifications */
  259. int r;
  260. Slapi_PBlock *resultpb= NULL;
  261. Slapi_Entry** entry = NULL;
  262. Slapi_DN dn;
  263. slapi_sdn_init(&dn);
  264. be_getconfigdn(be,&dn);
  265. resultpb= slapi_search_internal( slapi_sdn_get_ndn(&dn), LDAP_SCOPE_ONELEVEL, "objectclass=vlvsearch", NULL, NULL, 1);
  266. slapi_sdn_done(&dn);
  267. slapi_pblock_get( resultpb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entry );
  268. slapi_pblock_get( resultpb, SLAPI_PLUGIN_INTOP_RESULT, &r );
  269. if(r==LDAP_SUCCESS)
  270. {
  271. for (; *entry; ++entry)
  272. {
  273. val.bv_val = slapi_entry_get_dn(*entry);
  274. val.bv_len = strlen( val.bv_val );
  275. attrlist_merge( &e->e_attrs, "vlvsearch", vals );
  276. }
  277. }
  278. slapi_free_search_results_internal(resultpb);
  279. slapi_pblock_destroy(resultpb);
  280. }
  281. be = slapi_get_next_backend (cookie);
  282. }
  283. slapi_ch_free ((void **)&cookie);
  284. *returncode= LDAP_SUCCESS;
  285. return SLAPI_DSE_CALLBACK_OK;
  286. }
  287. /*
  288. * Handle a modification request on the root DSE. Only certain
  289. * attributes are writable. If an attempt to modify an attribute
  290. * which is not allowed, return LDAP_UNWILLING_TO_PERFORM, unless
  291. * the modification is disallowed because of ACL checking, in which
  292. * case LDAP_INSUFFICIENT_ACCESS is returned.
  293. */
  294. int
  295. modify_root_dse( Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry *e, int *returncode, char *returntext, void *arg )
  296. {
  297. LDAPMod **mods;
  298. /*
  299. * Make a pass through the attributes and check them
  300. * to make sure none are computed. Also check for
  301. * reflected attributes and reject those as well.
  302. * Eventually, some reflected attributes might be
  303. * writable, but for now, none are.
  304. */
  305. slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
  306. if ( NULL != mods )
  307. {
  308. int i;
  309. for ( i = 0; NULL != mods[ i ]; i++ )
  310. {
  311. if ( rootdse_is_readonly_attr( mods[ i ]->mod_type ))
  312. {
  313. /* The modification is disallowed */
  314. *returncode = LDAP_UNWILLING_TO_PERFORM;
  315. strcpy(returntext,"Modification of these root DSE attributes not allowed");
  316. return SLAPI_DSE_CALLBACK_ERROR;
  317. }
  318. }
  319. }
  320. *returncode= LDAP_SUCCESS;
  321. return SLAPI_DSE_CALLBACK_OK; /* success -- apply the changes */
  322. }