str2filter.c 8.8 KB

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