str2filter.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  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. /* slapi_str2filter.c - parse an rfc 1588 string filter */
  42. #include <stdio.h>
  43. #include <string.h>
  44. #include <sys/types.h>
  45. #ifndef _WIN32
  46. #include <sys/socket.h>
  47. #endif
  48. #include "slap.h"
  49. static struct slapi_filter *str2list();
  50. static int str2subvals();
  51. struct slapi_filter *
  52. slapi_str2filter( char *str )
  53. {
  54. struct slapi_filter *f = NULL;
  55. char *end;
  56. LDAPDebug( LDAP_DEBUG_FILTER, "slapi_str2filter \"%s\"\n", str, 0, 0 );
  57. if ( str == NULL || *str == '\0' ) {
  58. return( NULL );
  59. }
  60. switch ( *str ) {
  61. case '(':
  62. if ( (end = slapi_find_matching_paren( str )) == NULL ) {
  63. slapi_filter_free( f, 1 );
  64. return( NULL );
  65. }
  66. *end = '\0';
  67. str++;
  68. switch ( *str ) {
  69. case '&':
  70. LDAPDebug( LDAP_DEBUG_FILTER, "slapi_str2filter: AND\n",
  71. 0, 0, 0 );
  72. str++;
  73. f = str2list( str, LDAP_FILTER_AND );
  74. break;
  75. case '|':
  76. LDAPDebug( LDAP_DEBUG_FILTER, "put_filter: OR\n",
  77. 0, 0, 0 );
  78. str++;
  79. f = str2list( str, LDAP_FILTER_OR );
  80. break;
  81. case '!':
  82. LDAPDebug( LDAP_DEBUG_FILTER, "put_filter: NOT\n",
  83. 0, 0, 0 );
  84. str++;
  85. f = str2list( str, LDAP_FILTER_NOT );
  86. break;
  87. default:
  88. LDAPDebug( LDAP_DEBUG_FILTER, "slapi_str2filter: simple\n",
  89. 0, 0, 0 );
  90. f = str2simple( str , 1 /* unescape_filter */);
  91. break;
  92. }
  93. *end = ')';
  94. break;
  95. default: /* assume it's a simple type=value filter */
  96. LDAPDebug( LDAP_DEBUG_FILTER, "slapi_str2filter: default\n", 0, 0,
  97. 0 );
  98. f = str2simple( str , 1 /* unescape_filter */);
  99. break;
  100. }
  101. return( f );
  102. }
  103. /*
  104. * Put a list of filters like this "(filter1)(filter2)..."
  105. */
  106. static struct slapi_filter *
  107. str2list( char *str, unsigned long ftype )
  108. {
  109. struct slapi_filter *f;
  110. struct slapi_filter **fp;
  111. char *next;
  112. char save;
  113. LDAPDebug( LDAP_DEBUG_FILTER, "str2list \"%s\"\n", str, 0, 0 );
  114. f = (struct slapi_filter *) slapi_ch_calloc( 1, sizeof(struct slapi_filter) );
  115. f->f_choice = ftype;
  116. fp = &f->f_list;
  117. while ( *str ) {
  118. while ( *str && ldap_utf8isspace( str ) )
  119. LDAP_UTF8INC( str );
  120. if ( *str == '\0' )
  121. break;
  122. if ( (next = slapi_find_matching_paren( str )) == NULL ) {
  123. slapi_filter_free( f, 1 );
  124. return( NULL );
  125. }
  126. save = *++next;
  127. *next = '\0';
  128. /* now we have "(filter)" with str pointing to it */
  129. if ( (*fp = slapi_str2filter( str )) == NULL ) {
  130. slapi_filter_free( f, 1 );
  131. *next = save;
  132. return( NULL );
  133. }
  134. *next = save;
  135. str = next;
  136. f->f_flags |= ((*fp)->f_flags & SLAPI_FILTER_LDAPSUBENTRY);
  137. f->f_flags |= ((*fp)->f_flags & SLAPI_FILTER_TOMBSTONE);
  138. f->f_flags |= ((*fp)->f_flags & SLAPI_FILTER_RUV);
  139. fp = &(*fp)->f_next;
  140. }
  141. *fp = NULL;
  142. filter_compute_hash(f);
  143. return( f );
  144. }
  145. static char*
  146. str_find_star (char* s)
  147. /* Like strchr(s, '*'), except ignore "\*" */
  148. {
  149. char* r;
  150. if (s == NULL) return s;
  151. r = strchr (s, '*');
  152. if (r != s) while (r != NULL && r[-1] == '\\') {
  153. r = strchr (r+1, '*');
  154. }
  155. return r;
  156. }
  157. /*
  158. * unescape a string into another buffer -- note that an unescaped ldap
  159. * string may contain nulls if 'binary' is set! this is sort of a mix
  160. * between the LDAP SDK version and terry hayes' version. optimally it
  161. * would be nice if the LDAP SDK exported something like this.
  162. *
  163. * if 'binary' is set, "\00" is allowed, otherwise it's not.
  164. *
  165. * returns: 0 on error, 1 on success
  166. * (*outlen) is the actual length of the unescaped string
  167. */
  168. static int
  169. filt_unescape_str(const char *instr, char *outstr, size_t outsize, size_t* outlen, int binary)
  170. {
  171. const char *inp;
  172. char *outp;
  173. int ival;
  174. *outlen = 0;
  175. if (!outstr) return -1;
  176. for (inp = instr, outp = outstr; *inp; inp++)
  177. {
  178. if (! outsize)
  179. return 0; /* fail */
  180. if (*inp == '\\')
  181. {
  182. if (! *(++inp))
  183. return 0; /* fail */
  184. if (((ival = hexchar2int(inp[0])) < 0) || (hexchar2int(inp[1]) < 0))
  185. {
  186. /* LDAPv2 (RFC1960) escape sequence */
  187. *outp++ = *inp;
  188. (*outlen)++, outsize--;
  189. }
  190. else
  191. {
  192. /* LDAPv3 hex escape sequence */
  193. if (! *(++inp))
  194. return 0; /* fail */
  195. *outp = (ival << 4) | hexchar2int(*inp);
  196. if ((!binary) && (!*outp))
  197. return 0; /* fail: "\00" not allowed unless it's binary */
  198. outp++;
  199. (*outlen)++, outsize--;
  200. }
  201. }
  202. else
  203. {
  204. *outp++ = *inp;
  205. (*outlen)++, outsize--;
  206. }
  207. }
  208. return 1; /* ok */
  209. }
  210. /*
  211. * The caller unescapes it if unescape_filter == 0.
  212. */
  213. struct slapi_filter *
  214. str2simple( char *str , int unescape_filter)
  215. {
  216. struct slapi_filter *f;
  217. char *s;
  218. char *value, savechar;
  219. LDAPDebug( LDAP_DEBUG_FILTER, "str2simple \"%s\"\n", str, 0, 0 );
  220. PR_ASSERT(str);
  221. if ( (s = strchr( str, '=' )) == NULL ) {
  222. return( NULL );
  223. }
  224. value = s;
  225. LDAP_UTF8INC(value);
  226. LDAP_UTF8DEC(s);
  227. f = (struct slapi_filter *) slapi_ch_calloc( 1, sizeof(struct slapi_filter) );
  228. switch ( *s ) {
  229. case '<':
  230. f->f_choice = LDAP_FILTER_LE;
  231. break;
  232. case '>':
  233. f->f_choice = LDAP_FILTER_GE;
  234. break;
  235. case '~':
  236. f->f_choice = LDAP_FILTER_APPROX;
  237. break;
  238. default:
  239. LDAP_UTF8INC(s);
  240. if ( str_find_star( value ) == NULL ) {
  241. f->f_choice = LDAP_FILTER_EQUALITY;
  242. } else if ( strcmp( value, "*" ) == 0 ) {
  243. f->f_choice = LDAP_FILTER_PRESENT;
  244. } else {
  245. f->f_choice = LDAP_FILTER_SUBSTRINGS;
  246. savechar = *s;
  247. *s = 0;
  248. f->f_sub_type = slapi_ch_strdup( str );
  249. *s = savechar;
  250. if ( str2subvals( value, f , unescape_filter) != 0 ) {
  251. slapi_filter_free( f, 1 );
  252. return( NULL );
  253. }
  254. filter_compute_hash(f);
  255. return( f );
  256. }
  257. break;
  258. }
  259. if ( f->f_choice == LDAP_FILTER_PRESENT ) {
  260. savechar = *s;
  261. *s = 0;
  262. f->f_type = slapi_ch_strdup( str );
  263. *s = savechar;
  264. } else if ( unescape_filter ) {
  265. int r;
  266. char *unqstr;
  267. size_t len = strlen(value), len2;
  268. /* dup attr */
  269. savechar = *s;
  270. *s = 0;
  271. f->f_avtype = slapi_ch_strdup( str );
  272. *s = savechar;
  273. /* dup value */
  274. savechar = value[len];
  275. value[len] = 0;
  276. unqstr = slapi_ch_calloc( 1, len+1);
  277. r= filt_unescape_str(value, unqstr, len, &len2, 1);
  278. value[len] = savechar;
  279. if (!r) {
  280. slapi_filter_free(f, 1);
  281. return NULL;
  282. }
  283. f->f_avvalue.bv_val = unqstr;
  284. f->f_avvalue.bv_len = len2;
  285. if((f->f_choice == LDAP_FILTER_EQUALITY) &&
  286. (0 == strncasecmp (str,"objectclass",strlen("objectclass")))) {
  287. if (0 == strcasecmp (unqstr,"ldapsubentry"))
  288. f->f_flags |= SLAPI_FILTER_LDAPSUBENTRY;
  289. if (0 == strcasecmp (unqstr,SLAPI_ATTR_VALUE_TOMBSTONE))
  290. f->f_flags |= SLAPI_FILTER_TOMBSTONE;
  291. }
  292. if((f->f_choice == LDAP_FILTER_EQUALITY) &&
  293. (0 == strncasecmp (str,"nsuniqueid",strlen("nsuniqueid")))) {
  294. if (0 == strcasecmp (unqstr, "ffffffff-ffffffff-ffffffff-ffffffff"))
  295. f->f_flags |= SLAPI_FILTER_RUV;
  296. }
  297. } if ( !unescape_filter ) {
  298. f->f_avtype = slapi_ch_strdup( str );
  299. f->f_avvalue.bv_val = slapi_ch_strdup ( value );
  300. f->f_avvalue.bv_len = strlen ( f->f_avvalue.bv_val );
  301. }
  302. filter_compute_hash(f);
  303. return( f );
  304. }
  305. static int
  306. str2subvals( char *val, struct slapi_filter *f, int unescape_filter )
  307. {
  308. char *nextstar, *unqval;
  309. int gotstar;
  310. size_t len, outlen;
  311. LDAPDebug( LDAP_DEBUG_FILTER, "str2subvals \"%s\"\n", val, 0, 0 );
  312. gotstar = 0;
  313. while ( val != NULL && *val ) {
  314. if ( (nextstar = str_find_star( val )) != NULL )
  315. *nextstar = '\0';
  316. if ( unescape_filter ) {
  317. len = strlen(val);
  318. unqval = slapi_ch_malloc(len+1);
  319. if (!filt_unescape_str(val, unqval, len, &outlen, 0)) {
  320. slapi_ch_free((void **)&unqval);
  321. return -1;
  322. }
  323. unqval[outlen]= '\0';
  324. } else {
  325. unqval = slapi_ch_strdup ( val );
  326. }
  327. if (unqval && unqval[0]) {
  328. if (gotstar == 0) {
  329. f->f_sub_initial = unqval;
  330. } else if ( nextstar == NULL ) {
  331. f->f_sub_final = unqval;
  332. } else {
  333. charray_add( &f->f_sub_any, unqval );
  334. }
  335. } else {
  336. slapi_ch_free((void **)&unqval);
  337. }
  338. gotstar = 1;
  339. if ( nextstar != NULL )
  340. *nextstar++ = '*';
  341. val = nextstar;
  342. }
  343. return( 0 );
  344. }
  345. /*
  346. * find_matching_paren - return a pointer to the right paren in s matching
  347. * the left paren to which *s currently points
  348. */
  349. char *
  350. slapi_find_matching_paren( const char *s )
  351. {
  352. int balance, escape;
  353. balance = 0;
  354. escape = 0;
  355. for ( ; *s; s++ ) {
  356. if ( escape == 0 ) {
  357. if ( *s == '(' )
  358. balance++;
  359. else if ( *s == ')' )
  360. balance--;
  361. }
  362. if ( balance == 0 ) {
  363. return( (char *)s );
  364. }
  365. if ( *s == '\\' && ! escape )
  366. escape = 1;
  367. else
  368. escape = 0;
  369. }
  370. return( NULL );
  371. }