aclutil.c 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473
  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. #include "acl.h"
  42. /**************************************************************************
  43. * Defines and usefuls stuff
  44. ****************************************************************************/
  45. /*************************************************************************
  46. * Prototypes
  47. *************************************************************************/
  48. static void aclutil__typestr (int type , char str[]);
  49. static void aclutil__Ruletypestr (int type , char str[]);
  50. static char* __aclutil_extract_dn_component ( char **e_dns, int position,
  51. char *attrName );
  52. static int acl_find_comp_start(char * s, int pos );
  53. static PRIntn acl_ht_free_entry_and_value(PLHashEntry *he, PRIntn i,
  54. void *arg);
  55. static PLHashNumber acl_ht_hash( const void *key);
  56. #ifdef FOR_DEBUGGING
  57. static PRIntn acl_ht_display_entry(PLHashEntry *he, PRIntn i, void *arg);
  58. #endif
  59. /***************************************************************************/
  60. /* UTILITY FUNCTIONS */
  61. /***************************************************************************/
  62. int
  63. aclutil_str_append(char **str1, const char *str2)
  64. {
  65. int new_len;
  66. if ( str1 == NULL || str2 == NULL )
  67. return(0);
  68. if ( *str1 == NULL ) {
  69. new_len = strlen(str2) + 1;
  70. *str1 = (char *)slapi_ch_malloc(new_len);
  71. *str1[0] = 0;
  72. } else {
  73. new_len = strlen(*str1) + strlen(str2) + 1;
  74. *str1 = (char *)slapi_ch_realloc(*str1, new_len);
  75. }
  76. if ( *str1 == NULL )
  77. return(-1);
  78. strcat(*str1, str2);
  79. return(0);
  80. }
  81. /*
  82. * dlen: the length of the buffer *dest (not the string length in *dest)
  83. */
  84. int
  85. aclutil_str_append_ext(char **dest, size_t *dlen, const char *src, size_t slen)
  86. {
  87. char *ptr = NULL;
  88. int rc = 0;
  89. if ( dest == NULL || src == NULL ) {
  90. return rc;
  91. }
  92. if (0 == slen) {
  93. slen = strlen(src);
  94. }
  95. if (*dest && dlen > 0) {
  96. size_t dest_strlen = strlen(*dest);
  97. size_t new_len = dest_strlen + slen + 1;
  98. if (new_len > *dlen) {
  99. *dest = (char *)slapi_ch_realloc(*dest, new_len);
  100. *dlen = new_len;
  101. ptr = *dest + dest_strlen;
  102. } else {
  103. ptr = *dest + dest_strlen;
  104. }
  105. } else {
  106. *dlen = slen + 1;
  107. *dest = (char *)slapi_ch_malloc(*dlen);
  108. ptr = *dest;
  109. }
  110. memcpy(ptr, src, slen);
  111. *(ptr + slen) = '\0';
  112. return rc;
  113. }
  114. /***************************************************************************/
  115. /* Print routines */
  116. /***************************************************************************/
  117. /* print eroror message returned from the ACL Library */
  118. #define ACLUTIL_ACLLIB_MSGBUF_LEN 200
  119. void
  120. acl_print_acllib_err (NSErr_t *errp , char * str)
  121. {
  122. char msgbuf[ ACLUTIL_ACLLIB_MSGBUF_LEN ];
  123. if ((NULL == errp ) || !slapi_is_loglevel_set ( SLAPI_LOG_ACL ) )
  124. return;
  125. aclErrorFmt(errp, msgbuf, ACLUTIL_ACLLIB_MSGBUF_LEN, 1);
  126. msgbuf[ACLUTIL_ACLLIB_MSGBUF_LEN-1] = '\0';
  127. if (strlen(msgbuf) > 0) {
  128. slapi_log_error(SLAPI_LOG_ACL, plugin_name,"ACL LIB ERR:(%s)(%s)\n",
  129. msgbuf, str ? str: "NULL");
  130. } else {
  131. slapi_log_error(SLAPI_LOG_ACL, plugin_name,"ACL LIB ERR:(%s)\n",
  132. str ? str: "NULL");
  133. }
  134. }
  135. void
  136. aclutil_print_aci (aci_t *aci_item, char *type)
  137. {
  138. char str[BUFSIZ];
  139. const char *dn;
  140. if ( ! slapi_is_loglevel_set ( SLAPI_LOG_ACL ) )
  141. return;
  142. if (!aci_item) {
  143. slapi_log_error (SLAPI_LOG_ACL, plugin_name,
  144. "acl__print_aci: Null item\n");
  145. return;
  146. }
  147. slapi_log_error (SLAPI_LOG_ACL, plugin_name,
  148. "***BEGIN ACL INFO[ Name:%s]***\n", aci_item->aclName);
  149. slapi_log_error (SLAPI_LOG_ACL, plugin_name,
  150. "ACL Index:%d ACL_ELEVEL:%d\n", aci_item->aci_index, aci_item->aci_elevel );
  151. aclutil__access_str (aci_item->aci_access, str);
  152. aclutil__typestr (aci_item->aci_type, &str[strlen(str)]);
  153. slapi_log_error (SLAPI_LOG_ACL, plugin_name,
  154. "ACI type:(%s)\n", str);
  155. aclutil__Ruletypestr (aci_item->aci_ruleType, str);
  156. slapi_log_error (SLAPI_LOG_ACL, plugin_name,
  157. "ACI RULE type:(%s)\n",str);
  158. dn = slapi_sdn_get_dn ( aci_item->aci_sdn );
  159. slapi_log_error (SLAPI_LOG_ACL, plugin_name, "Slapi_Entry DN:%s\n", dn);
  160. slapi_log_error (SLAPI_LOG_ACL, plugin_name,
  161. "***END ACL INFO*****************************\n");
  162. }
  163. void
  164. aclutil_print_err (int rv , const Slapi_DN *sdn, const struct berval* val,
  165. char **errbuf)
  166. {
  167. char ebuf [BUFSIZ];
  168. /*
  169. * The maximum size of line is ebuf_size + the log message
  170. * itself (less than 200 characters for all but potentially ACL_INVALID_TARGET)
  171. */
  172. char line [BUFSIZ + 200];
  173. char str [1024];
  174. const char *dn;
  175. char *lineptr = line;
  176. char *newline = NULL;
  177. if ( rv >= 0)
  178. return;
  179. if (val->bv_len > 0 && val->bv_val != NULL) {
  180. PR_snprintf (str, sizeof(str), "%.1023s", val->bv_val);
  181. } else {
  182. str[0] = '\0';
  183. }
  184. dn = slapi_sdn_get_dn ( sdn );
  185. if (dn && (rv == ACL_INVALID_TARGET) && ((strlen(dn) + strlen(str)) > BUFSIZ)) {
  186. /*
  187. * if (str_length + dn_length + 200 char message) > (BUFSIZ + 200) line
  188. * we have to make space for a bigger line...
  189. */
  190. newline = slapi_ch_malloc(strlen(dn) + strlen(str) + 200);
  191. lineptr = newline;
  192. }
  193. switch (rv) {
  194. case ACL_TARGET_FILTER_ERR:
  195. sprintf (line, "ACL Internal Error(%d): "
  196. "Error in generating the target filter for the ACL(%s)\n",
  197. rv, escape_string_with_punctuation (str, ebuf));
  198. break;
  199. case ACL_TARGETATTR_FILTER_ERR:
  200. sprintf (line, "ACL Internal Error(%d): "
  201. "Error in generating the targetattr filter for the ACL(%s)\n",
  202. rv, escape_string_with_punctuation (str, ebuf));
  203. break;
  204. case ACL_TARGETFILTER_ERR:
  205. sprintf (line, "ACL Internal Error(%d): "
  206. "Error in generating the targetfilter filter for the ACL(%s)\n",
  207. rv, escape_string_with_punctuation (str, ebuf));
  208. break;
  209. case ACL_SYNTAX_ERR:
  210. sprintf (line, "ACL Syntax Error(%d):%s\n",
  211. rv, escape_string_with_punctuation (str, ebuf));
  212. break;
  213. case ACL_ONEACL_TEXT_ERR:
  214. sprintf (line, "ACL Syntax Error in the Bind Rules(%d):%s\n",
  215. rv, escape_string_with_punctuation (str, ebuf));
  216. break;
  217. case ACL_ERR_CONCAT_HANDLES:
  218. sprintf (line, "ACL Internal Error(%d): "
  219. "Error in Concatenating List handles\n",
  220. rv);
  221. break;
  222. case ACL_INVALID_TARGET:
  223. sprintf (lineptr, "ACL Invalid Target Error(%d): "
  224. "Target is beyond the scope of the ACL(SCOPE:%s)",
  225. rv, dn ? escape_string_with_punctuation (dn, ebuf) : "NULL");
  226. sprintf (lineptr + strlen(lineptr), " %s\n", escape_string_with_punctuation (str, ebuf));
  227. break;
  228. case ACL_INVALID_AUTHMETHOD:
  229. sprintf (line, "ACL Multiple auth method Error(%d):"
  230. "Multiple Authentication Metod in the ACL(%s)\n",
  231. rv, escape_string_with_punctuation (str, ebuf));
  232. break;
  233. case ACL_INVALID_AUTHORIZATION:
  234. sprintf (line, "ACL Syntax Error(%d):"
  235. "Invalid Authorization statement in the ACL(%s)\n",
  236. rv, escape_string_with_punctuation (str, ebuf));
  237. break;
  238. case ACL_INCORRECT_ACI_VERSION:
  239. sprintf (line, "ACL Syntax Error(%d):"
  240. "Incorrect version Number in the ACL(%s)\n",
  241. rv, escape_string_with_punctuation (str, ebuf));
  242. break;
  243. default:
  244. sprintf (line, "ACL Internal Error(%d):"
  245. "ACL generic error (%s)\n",
  246. rv, escape_string_with_punctuation (str, ebuf));
  247. break;
  248. }
  249. if (errbuf) {
  250. /* If a buffer is provided, then copy the error */
  251. aclutil_str_append(errbuf, lineptr );
  252. }
  253. slapi_log_error( SLAPI_LOG_FATAL, plugin_name, "%s", lineptr);
  254. slapi_ch_free_string(&newline);
  255. }
  256. /***************************************************************************
  257. * Convert access to str
  258. ***************************************************************************/
  259. char*
  260. aclutil__access_str (int type , char str[])
  261. {
  262. char *p;
  263. str[0] = '\0';
  264. p = str;
  265. if (type & SLAPI_ACL_COMPARE) {
  266. strcpy (p, "compare ");
  267. p = strchr (p, '\0');
  268. }
  269. if (type & SLAPI_ACL_SEARCH) {
  270. strcpy (p, "search ");
  271. p = strchr (p, '\0');
  272. }
  273. if (type & SLAPI_ACL_READ) {
  274. strcpy (p, "read ");
  275. p = strchr (p, '\0');
  276. }
  277. if (type & SLAPI_ACL_WRITE) {
  278. strcpy (p, "write ");
  279. p = strchr (p, '\0');
  280. }
  281. if (type & SLAPI_ACL_DELETE) {
  282. strcpy (p, "delete ");
  283. p = strchr (p, '\0');
  284. }
  285. if (type & SLAPI_ACL_ADD) {
  286. strcpy (p, "add ");
  287. p = strchr (p, '\0');
  288. }
  289. if (type & SLAPI_ACL_SELF) {
  290. strcpy (p, "self ");
  291. p = strchr (p, '\0');
  292. }
  293. if (type & SLAPI_ACL_PROXY) {
  294. strcpy (p, "proxy ");
  295. }
  296. return str;
  297. }
  298. /***************************************************************************
  299. * Convert type to str
  300. ***************************************************************************/
  301. static void
  302. aclutil__typestr (int type , char str[])
  303. {
  304. char *p;
  305. /* Start copying in at whatever location is passed in */
  306. p = str;
  307. if (type & ACI_TARGET_DN) {
  308. strcpy (p, "target_DN ");
  309. p = strchr (p, '\0');
  310. }
  311. if (type & ACI_TARGET_ATTR) {
  312. strcpy (p, "target_attr ");
  313. p = strchr (p, '\0');
  314. }
  315. if (type & ACI_TARGET_PATTERN) {
  316. strcpy (p, "target_patt ");
  317. p = strchr (p, '\0');
  318. }
  319. if ((type & ACI_TARGET_ATTR_ADD_FILTERS) | (type & ACI_TARGET_ATTR_DEL_FILTERS)) {
  320. strcpy (p, "targetattrfilters ");
  321. p = strchr (p, '\0');
  322. }
  323. if (type & ACI_TARGET_FILTER) {
  324. strcpy (p, "target_filter ");
  325. p = strchr (p, '\0');
  326. }
  327. if (type & ACI_ACLTXT) {
  328. strcpy (p, "acltxt ");
  329. p = strchr (p, '\0');
  330. }
  331. if (type & ACI_TARGET_NOT) {
  332. strcpy (p, "target_not ");
  333. p = strchr (p, '\0');
  334. }
  335. if (type & ACI_TARGET_ATTR_NOT) {
  336. strcpy (p, "target_attr_not ");
  337. p = strchr (p, '\0');
  338. }
  339. if (type & ACI_TARGET_FILTER_NOT) {
  340. strcpy (p, "target_filter_not ");
  341. p = strchr (p, '\0');
  342. }
  343. if (type & ACI_HAS_ALLOW_RULE) {
  344. strcpy (p, "allow_rule ");
  345. p = strchr (p, '\0');
  346. }
  347. if (type & ACI_HAS_DENY_RULE) {
  348. strcpy (p, "deny_rule ");
  349. }
  350. }
  351. static void
  352. aclutil__Ruletypestr (int type , char str[])
  353. {
  354. char *p;
  355. str[0] = '\0';
  356. p = str;
  357. if ( type & ACI_USERDN_RULE) {
  358. strcpy (p, "userdn ");
  359. p = strchr (p, '\0');
  360. }
  361. if ( type & ACI_USERDNATTR_RULE) {
  362. strcpy (p, "userdnattr ");
  363. p = strchr (p, '\0');
  364. }
  365. if ( type & ACI_USERATTR_RULE) {
  366. strcpy (p, "userattr ");
  367. p = strchr (p, '\0');
  368. }
  369. if ( type & ACI_GROUPDN_RULE) {
  370. strcpy (p, "groupdn ");
  371. p = strchr (p, '\0');
  372. }
  373. if ( type & ACI_GROUPDNATTR_RULE) {
  374. strcpy (p, "groupdnattr ");
  375. p = strchr (p, '\0');
  376. }
  377. if ( type & ACI_ROLEDN_RULE) {
  378. strcpy (p, "roledn ");
  379. p = strchr (p, '\0');
  380. }
  381. if ( type & ACI_IP_RULE) {
  382. strcpy (p, "ip ");
  383. p = strchr (p, '\0');
  384. }
  385. if ( type & ACI_DNS_RULE) {
  386. strcpy (p, "dns ");
  387. p = strchr (p, '\0');
  388. }
  389. if ( type & ACI_TIMEOFDAY_RULE) {
  390. strcpy (p, "timeofday ");
  391. p = strchr (p, '\0');
  392. }
  393. if ( type & ACI_DAYOFWEEK_RULE) {
  394. strcpy (p, "dayofweek ");
  395. p = strchr (p, '\0');
  396. }
  397. if ( type & ACI_AUTHMETHOD_RULE) {
  398. strcpy (p, "authmethod ");
  399. p = strchr (p, '\0');
  400. }
  401. if ( type & ACI_PARAM_DNRULE) {
  402. strcpy (p, "paramdn ");
  403. p = strchr (p, '\0');
  404. }
  405. if ( type & ACI_PARAM_ATTRRULE) {
  406. strcpy (p, "paramAttr ");
  407. p = strchr (p, '\0');
  408. }
  409. if ( type & ACI_SSF_RULE) {
  410. strcpy (p, "ssf ");
  411. }
  412. }
  413. /*
  414. ** acl_gen_err_msg
  415. ** This function is called by backend to generate the error message
  416. ** if access is denied.
  417. */
  418. void
  419. acl_gen_err_msg(int access, char *edn, char *attr, char **errbuf)
  420. {
  421. char *line = NULL;
  422. if (access & SLAPI_ACL_WRITE) {
  423. line = PR_smprintf(
  424. "Insufficient 'write' privilege to the '%s' attribute of entry '%s'.\n",
  425. attr ? attr: "NULL", edn);
  426. } else if ( access & SLAPI_ACL_ADD ) {
  427. line = PR_smprintf(
  428. "Insufficient 'add' privilege to add the entry '%s'.\n",edn);
  429. } else if ( access & SLAPI_ACL_DELETE ) {
  430. line = PR_smprintf(
  431. "Insufficient 'delete' privilege to delete the entry '%s'.\n",edn);
  432. }
  433. aclutil_str_append(errbuf, line );
  434. if (line) {
  435. PR_smprintf_free(line);
  436. line = NULL;
  437. }
  438. }
  439. short
  440. aclutil_gen_signature ( short c_signature )
  441. {
  442. short o_signature = 0;
  443. short randval = (short)slapi_rand();
  444. o_signature = c_signature ^ (randval % 32768);
  445. if (!o_signature) {
  446. randval = (short)slapi_rand();
  447. o_signature = c_signature ^ (randval % 32768);
  448. }
  449. return o_signature;
  450. }
  451. void
  452. aclutil_print_resource( struct acl_pblock *aclpb, char *right , char *attr, char *clientdn )
  453. {
  454. char str[BUFSIZ];
  455. const char *dn;
  456. if ( aclpb == NULL) return;
  457. if ( ! slapi_is_loglevel_set ( SLAPI_LOG_ACL ) )
  458. return;
  459. slapi_log_error (SLAPI_LOG_ACL, plugin_name, " ************ RESOURCE INFO STARTS *********\n");
  460. slapi_log_error (SLAPI_LOG_ACL, plugin_name, " Client DN: %s\n",
  461. clientdn ? clientdn : "NULL");
  462. aclutil__access_str (aclpb->aclpb_access, str);
  463. aclutil__typestr (aclpb->aclpb_res_type, &str[strlen(str)]);
  464. slapi_log_error (SLAPI_LOG_ACL, plugin_name, " resource type:%d(%s)\n",
  465. aclpb->aclpb_res_type, str);
  466. dn = slapi_sdn_get_dn ( aclpb->aclpb_curr_entry_sdn );
  467. slapi_log_error (SLAPI_LOG_ACL, plugin_name, " Slapi_Entry DN: %s\n",
  468. dn ? dn : "NULL");
  469. slapi_log_error (SLAPI_LOG_ACL, plugin_name, " ATTR: %s\n", attr ? attr : "NULL");
  470. slapi_log_error (SLAPI_LOG_ACL, plugin_name, " rights:%s\n", right ? right: "NULL");
  471. slapi_log_error (SLAPI_LOG_ACL, plugin_name, " ************ RESOURCE INFO ENDS *********\n");
  472. }
  473. /*
  474. * The input string contains a rule like
  475. * "cn=helpdesk, ou=$attr.deptName, o=$dn.o, o=ISP"
  476. *
  477. * Where $attr -- means look into the attribute list for values
  478. * $dn -- means look into the entry's dn
  479. *
  480. * We extract the values from the entry and returned a string
  481. * with the values added.
  482. * For "$attr" rule - if we find multiple values then it is
  483. * the pattern is not expanded.
  484. * For "$dn" rule, if we find multiple of them, we use the relative
  485. * position.
  486. * NOTE: The caller is responsible in freeing the memory.
  487. */
  488. char *
  489. aclutil_expand_paramString ( char *str, Slapi_Entry *e )
  490. {
  491. char **e_dns;
  492. char **a_dns;
  493. char *attrName;
  494. char *s, *p;
  495. char *attrVal = NULL;
  496. int i, len;
  497. int ncomponents, type;
  498. int rc = -1;
  499. char *buf = NULL;
  500. if ((NULL == slapi_entry_get_ndn ( e )) || (NULL == str)) {
  501. return NULL;
  502. }
  503. e_dns = slapi_ldap_explode_dn ( slapi_entry_get_ndn ( e ), 0 );
  504. a_dns = slapi_ldap_explode_dn ( str, 0 );
  505. if ((NULL == e_dns) || (NULL == a_dns)) {
  506. goto cleanup;
  507. }
  508. i = 0;
  509. ncomponents = 0;
  510. while ( a_dns[ncomponents] )
  511. ncomponents++;
  512. for (i=0; i < ncomponents; i++ ) {
  513. /* Look for"$" char */
  514. if ( (s = strchr ( a_dns[i], '$') ) != NULL) {
  515. p = s;
  516. s++;
  517. if ( strncasecmp (s, "dn", 2) == 0 )
  518. type = 1;
  519. else if ( strncasecmp (s, "attr", 4) == 0 )
  520. type = 2;
  521. else {
  522. /* error */
  523. goto cleanup;
  524. }
  525. *p = '\0';
  526. aclutil_str_append ( &buf,a_dns[i]);
  527. if ( type == 1 ) {
  528. /* xyz = $dn.o */
  529. s +=3;
  530. attrName = s;
  531. attrVal = __aclutil_extract_dn_component (e_dns,
  532. ncomponents-i, attrName);
  533. if ( NULL == attrVal ) /*error*/
  534. goto cleanup;
  535. } else {
  536. Slapi_Attr *attr;
  537. const struct berval *attrValue;
  538. int kk;
  539. Slapi_Value *sval, *t_sval;
  540. /* The pattern is x=$attr.o" */
  541. s +=5;
  542. attrName = s;
  543. slapi_entry_attr_find ( e, attrName, &attr );
  544. if ( NULL == attr )
  545. goto cleanup;
  546. kk= slapi_attr_first_value ( attr, &sval );
  547. if ( kk != -1 ) {
  548. t_sval = sval;
  549. kk= slapi_attr_next_value( attr, kk, &sval );
  550. if ( kk != -1 ) /* can't handle multiple --error */
  551. goto cleanup;
  552. attrValue = slapi_value_get_berval ( t_sval );
  553. attrVal = attrValue->bv_val;
  554. }
  555. }
  556. } else {
  557. attrVal = a_dns[i];
  558. }
  559. aclutil_str_append ( &buf, attrVal);
  560. aclutil_str_append ( &buf, ",");
  561. }
  562. rc = 0; /* everything is okay*/
  563. /* remove the last comma */
  564. if (buf) {
  565. len = strlen ( buf);
  566. buf[len-1] = '\0';
  567. }
  568. cleanup:
  569. slapi_ldap_value_free ( a_dns );
  570. slapi_ldap_value_free ( e_dns );
  571. if ( 0 != rc ) /* error */ {
  572. slapi_ch_free_string ( &buf );
  573. }
  574. return buf;
  575. }
  576. static char *
  577. __aclutil_extract_dn_component ( char **e_dns, int position, char *attrName )
  578. {
  579. int i, matched, len;
  580. char *s;
  581. int matchedPosition = 0;
  582. len = strlen ( attrName );
  583. /* First check if there thare are multiple of these */
  584. i = matched = 0;
  585. while ( e_dns[i] ) {
  586. if (0 == strncasecmp (e_dns[i], attrName, len) ) {
  587. matched++;
  588. matchedPosition = i;
  589. }
  590. i++;
  591. }
  592. if (!matched )
  593. return NULL;
  594. if ( matched > 1 ) {
  595. matchedPosition = i - position;
  596. }
  597. if ( NULL == e_dns[matchedPosition])
  598. return NULL;
  599. s = strstr ( e_dns[matchedPosition], "=");
  600. if ( NULL == s)
  601. return NULL;
  602. else
  603. return s+1;
  604. }
  605. /*
  606. * Does the first component of ndn match the first component of match_this ?
  607. */
  608. int
  609. acl_dn_component_match( const char *ndn, char *match_this, int component_number) {
  610. return(1);
  611. }
  612. /*
  613. * Here, ndn is a resource dn and match_this is a dn, containing a macro, ($dn).
  614. *
  615. * eg. ndn is cn=fred,ou=groups,ou=people,ou=icnc,o=ISP and
  616. * match_this is "ou=Groups,($dn),o=ISP" or
  617. * "cn=*,ou=Groups,($dn),o=ISP".
  618. *
  619. * They match if:
  620. * match_this is a suffix of ndn
  621. *
  622. * It returns NULL, if they do not match.
  623. * Otherwise it returns a copy of the substring of ndn that matches the ($dn).
  624. *
  625. * eg. in the above example, "ou=people,ou=icnc"
  626. */
  627. char *
  628. acl_match_macro_in_target( const char *ndn, char * match_this,
  629. char *macro_ptr) {
  630. char *macro_prefix = NULL;
  631. int macro_prefix_len = 0;
  632. char *macro_suffix = NULL;
  633. char *tmp_ptr = NULL;
  634. char *matched_val = NULL;
  635. char *ret_val = NULL;
  636. int ndn_len = 0;
  637. int macro_suffix_len = 0;
  638. int ndn_prefix_len = 0;
  639. int ndn_prefix_end = 0;
  640. int matched_val_len = 0;
  641. /*
  642. * First, grab the macro_suffix--the bit after the ($dn)
  643. *
  644. */
  645. if (strlen(macro_ptr) == strlen(ACL_TARGET_MACRO_DN_KEY)) {
  646. macro_suffix = NULL; /* just ($dn) */
  647. } else {
  648. if ( macro_ptr[strlen(ACL_TARGET_MACRO_DN_KEY)] == ',') {
  649. macro_suffix = &macro_ptr[strlen(ACL_TARGET_MACRO_DN_KEY) + 1];
  650. } else {
  651. macro_suffix = &macro_ptr[strlen(ACL_TARGET_MACRO_DN_KEY)];
  652. }
  653. }
  654. /*
  655. * First ensure that the suffix of match_this is
  656. * a suffix of ndn.
  657. */
  658. ndn_len = strlen(ndn);
  659. if ( macro_suffix != NULL) {
  660. macro_suffix_len = strlen(macro_suffix);
  661. if( macro_suffix_len >= ndn_len ) {
  662. /*
  663. * eg ndn: o=icnc,o=sun.com
  664. * match_this: ($dn),o=icnc,o=sun.com
  665. */
  666. return(NULL); /* ($dn) must match something. */
  667. } else {
  668. /*
  669. * eg ndn: ou=People,o=icnc,o=sun.com
  670. * match_this: ($dn),o=icnc,o=sun.com
  671. *
  672. * we can do a direct strncmp() because we know that
  673. * there can be no "*" after the ($dn)...by definition.
  674. */
  675. if (strncasecmp( macro_suffix, &ndn[ndn_len-macro_suffix_len],
  676. macro_suffix_len) != 0) {
  677. return(NULL); /* suffix must match */
  678. }
  679. }
  680. }
  681. /* Here, macro_suffix is a suffix of ndn.
  682. *
  683. *
  684. * Now, look at macro_prefix, if it is NULL, then ($dn) matches
  685. * ndn[0..ndn_len-macro_suffix_len].
  686. * (eg, ndn: cn=fred,ou=People,o=sun.com
  687. * match_this: ($dn),o=sun.com.
  688. *
  689. */
  690. macro_prefix = slapi_ch_strdup(match_this);
  691. /* we know it's got a $(dn) */
  692. tmp_ptr = strstr(macro_prefix, ACL_TARGET_MACRO_DN_KEY);
  693. if (!tmp_ptr) {
  694. LDAPDebug(LDAP_DEBUG_ACL,"acl_match_macro_in_target: "
  695. "Target macro DN key \"%s\" not found in \"%s\".\n",
  696. ACL_TARGET_MACRO_DN_KEY, macro_prefix, 0);
  697. slapi_ch_free_string(&macro_prefix);
  698. return ret_val;
  699. }
  700. *tmp_ptr = '\0';
  701. /* There may be a NULL prefix eg. match_this: ($dn),o=sun.com */
  702. macro_prefix_len = strlen(macro_prefix);
  703. if (macro_prefix_len == 0) {
  704. slapi_ch_free_string(&macro_prefix);
  705. macro_prefix = NULL;
  706. }
  707. if (macro_prefix == NULL ) {
  708. /*
  709. * ($dn) matches ndn[0..ndn_len-macro_suffix_len]
  710. */
  711. int matched_val_len = 0;
  712. matched_val_len = ndn_len-macro_suffix_len;
  713. matched_val = (char *)slapi_ch_malloc(matched_val_len + 1);
  714. strncpy(matched_val, ndn, ndn_len-macro_suffix_len);
  715. /*
  716. * Null terminate matched_val, removing trailing "," if there is
  717. * one.
  718. */
  719. if (matched_val_len > 1) {
  720. if (matched_val[matched_val_len-1] == ',' ) {
  721. matched_val[matched_val_len-1] = '\0';
  722. } else {
  723. matched_val[matched_val_len] = '\0';
  724. }
  725. }
  726. ret_val = matched_val;
  727. } else {
  728. /*
  729. * If it is not NULL, then if macro_prefix contains a * then
  730. * it needs to be an exact prefix of ndn (modulo the * component
  731. * which matches anything) becuase that's the semantics
  732. * of target patterns containing *'s, except that we just
  733. * make it match one component.
  734. * If it is such a prefix then ($dn) matches that portion of ndn
  735. * from the end of the prefix, &ndn[ndn_prefix_end] to
  736. * ndn_suffix_start.
  737. * If ndn_prefix_len > ndn_len-macro_suffix_len then return(NULL),
  738. * otherwise $(dn) matches ndn[ndn_prefix_len..ndn_len-macro_suffix_len].
  739. *
  740. *
  741. * eg. ndn: cn=fred,ou=P,o=sun.com
  742. * match_this: cn=*,($dn),o=sun.com
  743. */
  744. if ( strstr(macro_prefix, "=*") != NULL ) {
  745. int exact_match = 0;
  746. ndn_prefix_len = acl_match_prefix( macro_prefix, ndn, &exact_match);
  747. if ( ndn_prefix_len != -1 ) {
  748. /*
  749. * ndn[0..ndn_prefix_len] is the prefix in ndn.
  750. * ndn[ndn_prefix_len..ndn_len-macro_suffix_len] is the
  751. * matched string.
  752. */
  753. if (ndn_prefix_len >= ndn_len-macro_suffix_len) {
  754. /*
  755. * eg ndn: cn=fred,ou=People,o=icnc,o=sun.com
  756. * cn=*,ou=People,o=icnc,($dn),o=icnc,o=sun.com
  757. */
  758. ret_val = NULL; /* matched string is empty */
  759. } else {
  760. /*
  761. * eg ndn: cn=fred,ou=People,o=icnc,o=sun.com
  762. * cn=*,ou=People,($dn),o=sun.com
  763. */
  764. matched_val_len = ndn_len-macro_suffix_len-ndn_prefix_len;
  765. matched_val = (char *)slapi_ch_malloc(matched_val_len + 1);
  766. strncpy(matched_val, &ndn[ndn_prefix_len], matched_val_len);
  767. if (matched_val_len > 1) {
  768. if (matched_val[matched_val_len-1] == ',' ) {
  769. matched_val[matched_val_len-1] = '\0';
  770. } else {
  771. matched_val[matched_val_len] = '\0';
  772. }
  773. }
  774. matched_val[matched_val_len] = '\0';
  775. ret_val = matched_val;
  776. }
  777. } else {
  778. /* Was not a prefix so not a match */
  779. ret_val = NULL;
  780. }
  781. } else {
  782. /*
  783. *
  784. * If macro_prefix is not NULL and it does not
  785. * contain a =* then
  786. * we need to ensure that macro_prefix is a substring
  787. * ndn.
  788. * If it is and the position of the character after it's end in
  789. * ndn is
  790. * ndn_prefix_end then ($dn) matches
  791. * ndn[ndn_prefix_end..ndn_len-macro_suffix_len].
  792. *
  793. *
  794. * One important principal is that ($dn) matches a maximal
  795. * chunk--this way it will serve to make the link
  796. * between resources and users at each level of the structure.
  797. *
  798. * eg. ndn: ou=Groups,ou=Groups,ou=Groups,c=fr
  799. * macro_prefix: ou=Groups,($dn),c=fr
  800. *
  801. * then ($dn) matches ou=Groups,ou=Groups.
  802. *
  803. *
  804. *
  805. * If it is not a substring, then there is no match.
  806. * If it is a substring and
  807. * ndn[ndn_prefix_end..ndn_len-macro_suffix_len] is empty then
  808. * it's also not a match as we demand that ($dn) match a non-empty
  809. * string.
  810. *
  811. *
  812. *
  813. * (eg. ndn: cn=fred,o=icnc,ou=People,o=sun.com
  814. * match_this: o=icnc,($dn),o=sun.com.)
  815. *
  816. *
  817. * (eg. ndn: cn=fred,o=menlo park,ou=People,o=icnc,o=sun.com
  818. * match_this: o=menlo park,ou=People,($dn),o=sun.com
  819. *
  820. */
  821. ndn_prefix_end = acl_strstr((char *)ndn, macro_prefix);
  822. if ( ndn_prefix_end == -1) {
  823. ret_val = NULL;
  824. } else {
  825. /* Is a substring */
  826. ndn_prefix_end += macro_prefix_len;
  827. /*
  828. * make sure the matching part is non-empty:
  829. *
  830. * ndn[ndn_prefix_end..mndn_len-macro_suffix_len].
  831. */
  832. if ( ndn_prefix_end >= ndn_len-macro_suffix_len) {
  833. ret_val = NULL;
  834. } else {
  835. /*
  836. * ($dn) matches the non-empty string segment
  837. * ndn[ndn_prefix_end..mndn_len-macro_suffix_len]
  838. * the -1 is because macro_suffix_eln does not include
  839. * the coma before the suffix.
  840. */
  841. matched_val_len = ndn_len-macro_suffix_len-
  842. ndn_prefix_end - 1;
  843. matched_val = (char *)slapi_ch_malloc(matched_val_len + 1);
  844. strncpy(matched_val, &ndn[ndn_prefix_end],
  845. matched_val_len);
  846. matched_val[matched_val_len] = '\0';
  847. ret_val = matched_val;
  848. }
  849. }
  850. }/* contains an =* */
  851. slapi_ch_free_string(&macro_prefix);
  852. }/* macro_prefix != NULL */
  853. return(ret_val);
  854. }
  855. /*
  856. * Checks to see if macro_prefix is an exact prefix of ndn.
  857. * macro_prefix may contain a * component.
  858. *
  859. * The length of the matched prefix in ndn is returned.
  860. * If it was not a match, a negative int is returned.
  861. * Also, if the string matched exactly,
  862. * exact_match is set to 1, other wise it was a proper prefix.
  863. *
  864. */
  865. int
  866. acl_match_prefix( char *macro_prefix, const char *ndn, int *exact_match) {
  867. int ret_code = -1;
  868. int macro_prefix_len = 0;
  869. int ndn_len = 0;
  870. int i = 0;
  871. int j = 0;
  872. int done = 0;
  873. int t = 0;
  874. char * tmp_str = NULL;
  875. int k,l = 0;
  876. *exact_match = 0; /* default to not an exact match */
  877. /* The NULL prefix matches everthing*/
  878. if (macro_prefix == NULL) {
  879. if ( ndn == NULL ) {
  880. *exact_match = 1;
  881. }
  882. return(0);
  883. } else {
  884. /* macro_prefix is not null, so if ndn is NULL, it's not a match. */
  885. if ( ndn == NULL) {
  886. return(-1);
  887. }
  888. }
  889. /*
  890. * Here, neither macro_prefix nor ndn are NULL.
  891. *
  892. * eg. macro_prefix: cn=*,ou=people,o=sun.com
  893. * ndn : cn=fred,ou=people,o=sun.com
  894. */
  895. /*
  896. * Here, there is a component with a * (eg. cn=* ) so
  897. * we need to step through the macro_prefix, and where there is
  898. * such a * match on that component,
  899. * when we run out of * componenets, jsut do a straight match.
  900. *
  901. * Out of interest, the following extended regular expression
  902. * will match just one ou rdn value from a string:
  903. * "^uid=admin,ou=\([^,]*\\\,\)*[^,]*,o=sun.com$"
  904. *
  905. *
  906. * eg. cn=fred,ou=People,o=sun.com
  907. *
  908. *
  909. * s points to the = of the component.
  910. */
  911. macro_prefix_len = strlen(macro_prefix);
  912. ndn_len = strlen(ndn);
  913. i = 0;
  914. j = 0;
  915. done = 0;
  916. while ( !done ) {
  917. /* Here ndn[0..i] has matched macro_prefix[0..j] && j<= i
  918. * i<=ndn_len j<=macro_prefix_len */
  919. if ( (t = acl_strstr(&macro_prefix[j], "=*")) < 0 ) {
  920. /*
  921. * No more *'s, do a straight match on
  922. * macro_prefix[j..macro_prefix_len] and
  923. * ndn[i..macro_prefix_len]
  924. */
  925. if( macro_prefix_len-j > ndn_len-i) {
  926. /* Not a prefix, nor a match */
  927. *exact_match = 0;
  928. ret_code = -1;
  929. done = 1;
  930. } else {
  931. /*
  932. * ndn_len-i >= macro_prefix_len - j
  933. * if macro_prefix_len-j is 0, then
  934. * it's a null prefix, so it matches.
  935. * If in addition ndn_len-i is 0 then it's
  936. * an exact match.
  937. * Otherwise, do the cmp.
  938. */
  939. if ( macro_prefix_len-j == 0) {
  940. done = 1;
  941. ret_code = i;
  942. if ( ndn_len-i == 0) {
  943. *exact_match = 1;
  944. }
  945. }else {
  946. if (strncasecmp(&macro_prefix[j], &ndn[i],
  947. macro_prefix_len-j) == 0) {
  948. *exact_match = (macro_prefix_len-j == ndn_len-i);
  949. ret_code = i + macro_prefix_len -j;
  950. done = 1;
  951. } else {
  952. /* not a prefix not a match */
  953. *exact_match = 0;
  954. ret_code = -1;
  955. done = 1;
  956. }
  957. }
  958. }
  959. }else {
  960. /*
  961. * Is another * component, so:
  962. * 1. match that component in macro_prefix (at pos k say)
  963. * with the corresponding compoent (at pos l say ) in ndn
  964. *
  965. * 2. match the intervening string ndn[i..l] and
  966. * macro_prefix[j..k].
  967. */
  968. /* First, find the start of the component in macro_prefix. */
  969. t++; /* move to the--this way we will look for "ou=" in ndn */
  970. k = acl_find_comp_start(macro_prefix, t);
  971. /* Now identify that component in ndn--if it's not there no match */
  972. tmp_str = slapi_ch_malloc(t-k+1);
  973. strncpy(tmp_str, &macro_prefix[k], t-k);
  974. tmp_str[t-k] = '\0';
  975. l = acl_strstr((char*)&ndn[i], tmp_str);
  976. if (l == -1) {
  977. *exact_match = 0;
  978. ret_code = -1;
  979. done = 1;
  980. } else {
  981. /*
  982. * Found the comp in ndn, so the comp matches.
  983. * Now test the intervening string segments:
  984. * ndn[i..l] and macro_prefix[j..k]
  985. */
  986. if ( k-j != l-i ) {
  987. *exact_match = 0;
  988. ret_code = -1;
  989. done = 1;
  990. } else{
  991. if (strncasecmp(&macro_prefix[j], &ndn[i], k-j) != 0) {
  992. *exact_match = 0;
  993. ret_code = -1;
  994. done = 1;
  995. } else {
  996. /* Matched, so bump i and j and keep going.*/
  997. i += acl_find_comp_end((char*)&ndn[l]);
  998. j += acl_find_comp_end((char*)&macro_prefix[k]);
  999. }
  1000. }
  1001. }
  1002. slapi_ch_free_string(&tmp_str);
  1003. }
  1004. }/* while */
  1005. return(ret_code);
  1006. }
  1007. /*
  1008. * returns the index in s of where the component at position
  1009. * s[pos] starts.
  1010. * This is the index of the character after the first unescaped comma
  1011. * moving backwards in s from pos.
  1012. * If this is not found then return 0, ie. the start of the string.
  1013. * If the index returned is > strlen(s) then could not find it.
  1014. * only such case is if you pass ",", in which case there is no component start.
  1015. */
  1016. static int
  1017. acl_find_comp_start(char * s, int pos ) {
  1018. int i =0;
  1019. int comp_start = 0;
  1020. i = pos;
  1021. while( i > 0 && (s[i] != ',' ||
  1022. s[i-1] == '\\')) {
  1023. i--;
  1024. }
  1025. /*
  1026. * i == 0 || (s[i] == ',' && s[i-1] != '\\')
  1027. */
  1028. if (i==0) {
  1029. /* Got all the way with no unescaped comma */
  1030. if (s[i] == ',') {
  1031. comp_start = i+1;
  1032. } else {
  1033. comp_start = i;
  1034. }
  1035. } else { /* Found an unescaped comma */
  1036. comp_start = i + 1;
  1037. }
  1038. return( comp_start);
  1039. }
  1040. /*
  1041. * returns the index in s of the first character after the
  1042. * first unescaped comma.
  1043. * If ther is no such character, returns strlen(s);
  1044. */
  1045. int
  1046. acl_find_comp_end( char * s) {
  1047. int i = 0;
  1048. int s_len = 0;
  1049. s_len = strlen(s);
  1050. if ( s_len == 0 || s_len == 1) {
  1051. return(s_len);
  1052. }
  1053. /* inv: i+1<s_len && (s[i] == '\\' || s[i+1] != ',')*/
  1054. i = 0;
  1055. while( i+1 < s_len && (s[i] == '\\' ||
  1056. s[i+1] != ',')) {
  1057. i++;
  1058. }
  1059. if ( i + 1 == s_len) {
  1060. return(s_len);
  1061. } else {
  1062. return(i+2);
  1063. }
  1064. }
  1065. /*
  1066. * return the index in s where substr occurs, if none
  1067. * returns -1.
  1068. */
  1069. int
  1070. acl_strstr(char * s, char *substr) {
  1071. char *t = NULL;
  1072. char *tmp_str = NULL;
  1073. tmp_str = slapi_ch_strdup(s);
  1074. if ( (t = strstr(tmp_str, substr)) == NULL ) {
  1075. slapi_ch_free_string(&tmp_str);
  1076. return(-1);
  1077. } else {
  1078. int l = 0;
  1079. *t = '\0';
  1080. l = strlen(tmp_str);
  1081. slapi_ch_free_string(&tmp_str);
  1082. return(l);
  1083. }
  1084. }
  1085. /*
  1086. * replace all occurences of substr in s with replace_str.
  1087. *
  1088. * returns a malloced version of the patched string.
  1089. */
  1090. char *
  1091. acl_replace_str(char * s, char *substr, char* replace_with_str) {
  1092. char *str = NULL;
  1093. char *working_s, *suffix, *prefix, *patched;
  1094. int replace_with_len, substr_len, prefix_len, suffix_len;
  1095. if (strstr(s, substr) == NULL) {
  1096. return(slapi_ch_strdup(s));
  1097. } else {
  1098. replace_with_len = strlen(replace_with_str);
  1099. substr_len = strlen(substr);
  1100. working_s = slapi_ch_strdup(s);
  1101. prefix = working_s;
  1102. str = strstr(prefix, substr);
  1103. while (str != NULL) {
  1104. /*
  1105. * working_s is a copy of the string to be patched
  1106. * str points to a substr to be patched
  1107. * prefix points to working_s
  1108. */
  1109. *str = '\0';
  1110. suffix = &str[substr_len];
  1111. prefix_len = strlen(prefix);
  1112. suffix_len = strlen(suffix);
  1113. patched = (char *)slapi_ch_malloc(prefix_len +
  1114. replace_with_len +
  1115. suffix_len +1 );
  1116. strcpy(patched, prefix);
  1117. strcat(patched, replace_with_str);
  1118. strcat(patched, suffix);
  1119. slapi_ch_free_string(&working_s);
  1120. working_s = patched;
  1121. prefix = working_s;
  1122. str = strstr(prefix, substr);
  1123. }
  1124. return(working_s);
  1125. }
  1126. }
  1127. /*
  1128. * Start at index and return a malloced string that is the
  1129. * next component in dn (eg. "ou=People"),
  1130. * or NULL if couldn't find the next one.
  1131. */
  1132. char *
  1133. get_next_component(char *dn, int *index) {
  1134. int dn_len = strlen(dn);
  1135. int start_next = -1;
  1136. int i = 0;
  1137. char *ret_comp;
  1138. if (*index>= dn_len) {
  1139. return(NULL);
  1140. }
  1141. start_next = acl_find_comp_end( &dn[*index]);
  1142. if ( start_next >= dn_len ) {
  1143. *index = start_next;
  1144. return(NULL); /* no next comp */
  1145. }
  1146. /*
  1147. *Here, start_next should be the start of the next
  1148. * component--so far have not run off the end.
  1149. */
  1150. i = acl_find_comp_end( &dn[start_next]);
  1151. /*
  1152. * Here, the matched string is all from start_next to i.
  1153. */
  1154. ret_comp = (char *)slapi_ch_malloc(i - start_next +1);
  1155. memcpy( ret_comp, &dn[start_next], i-start_next);
  1156. ret_comp[i-start_next] = '\0';
  1157. return(ret_comp);
  1158. }
  1159. char *
  1160. get_this_component(char *dn, int *index) {
  1161. int dn_len = strlen(dn);
  1162. int i = 0;
  1163. char *ret_comp;
  1164. if (*index>= dn_len) {
  1165. return(NULL);
  1166. }
  1167. if (dn_len == *index + 1) {
  1168. /* Just return a copy of the string. */
  1169. return(slapi_ch_strdup(dn));
  1170. }else {
  1171. /* *index + 1 < dn_len */
  1172. i = *index+1;
  1173. while( (dn[i] != '\0') && dn[i] != ',' && dn[i-1] != '\\') {
  1174. i += 1;
  1175. }
  1176. /*
  1177. * Here, the matched string is all from *index to i.
  1178. */
  1179. ret_comp = (char *)slapi_ch_malloc(i - *index +1);
  1180. memcpy( ret_comp, &dn[*index], i - *index);
  1181. ret_comp[i-*index] = '\0';
  1182. if (i < dn_len) {
  1183. /* Found a comma before the end */
  1184. *index = i + 1; /* skip it */
  1185. }
  1186. return(ret_comp);
  1187. }
  1188. }
  1189. /* acl hash table funcs */
  1190. /*
  1191. * Add the key adn value to the ht.
  1192. * If it already exists then remove the old one and free
  1193. * the value.
  1194. */
  1195. void acl_ht_add_and_freeOld(acl_ht_t * acl_ht,
  1196. PLHashNumber key,
  1197. char *value){
  1198. char *old_value = NULL;
  1199. uintptr_t pkey = (uintptr_t)key;
  1200. if ( (old_value = (char *)acl_ht_lookup( acl_ht, key)) != NULL ) {
  1201. acl_ht_remove( acl_ht, key);
  1202. slapi_ch_free_string(&old_value);
  1203. }
  1204. PL_HashTableAdd( acl_ht, (const void *)pkey, value);
  1205. }
  1206. /*
  1207. * Return a new acl_ht_t *
  1208. */
  1209. acl_ht_t *acl_ht_new(void) {
  1210. return(PL_NewHashTable(30, acl_ht_hash, /* key hasher */
  1211. PL_CompareValues, /* keyCompare */
  1212. PL_CompareStrings, 0, 0)); /* value compare */
  1213. }
  1214. static PLHashNumber acl_ht_hash( const void *key) {
  1215. return( (PLHashNumber)((uintptr_t)key) );
  1216. }
  1217. /* Free all the values in the ht */
  1218. void acl_ht_free_all_entries_and_values( acl_ht_t *acl_ht) {
  1219. PL_HashTableEnumerateEntries( acl_ht, acl_ht_free_entry_and_value,
  1220. NULL);
  1221. }
  1222. static PRIntn
  1223. acl_ht_free_entry_and_value(PLHashEntry *he, PRIntn i, void *arg)
  1224. {
  1225. slapi_ch_free((void **)&he->value); /* free value */
  1226. /* Free this entry anfd go on to next one */
  1227. return ( HT_ENUMERATE_NEXT | HT_ENUMERATE_REMOVE);
  1228. }
  1229. /* Free all the values in the ht */
  1230. void acl_ht_display_ht( acl_ht_t *acl_ht) {
  1231. #ifdef FOR_DEBUGGING
  1232. PL_HashTableEnumerateEntries( acl_ht, acl_ht_display_entry, NULL);
  1233. #endif
  1234. }
  1235. #ifdef FOR_DEBUGGING
  1236. static PRIntn
  1237. acl_ht_display_entry(PLHashEntry *he, PRIntn i, void *arg)
  1238. {
  1239. PLHashNumber aci_index = (PLHashNumber)he->key;
  1240. char *matched_val = (char *)he->value;
  1241. LDAPDebug(LDAP_DEBUG_ACL,"macro ht entry: key='%d' matched_val='%s'"
  1242. "keyhash='%d'\n",
  1243. aci_index, (matched_val ? matched_val: "NULL"),
  1244. (PLHashNumber)he->keyHash);
  1245. return HT_ENUMERATE_NEXT;
  1246. }
  1247. #endif
  1248. /* remove this entry from the ht--doesn't free the value.*/
  1249. void acl_ht_remove( acl_ht_t *acl_ht, PLHashNumber key) {
  1250. PL_HashTableRemove( acl_ht, (const void *)((uintptr_t)key) );
  1251. }
  1252. /* Retrieve a pointer to the value of the entry with key */
  1253. void *acl_ht_lookup( acl_ht_t *acl_ht,
  1254. PLHashNumber key) {
  1255. return( PL_HashTableLookup( acl_ht, (const void *)((uintptr_t)key)) );
  1256. }
  1257. /***************************************************************************/
  1258. /* E N D */
  1259. /***************************************************************************/