regex.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2009 Red Hat, Inc.
  3. * All rights reserved.
  4. *
  5. * License: GPL (version 3 or any later version).
  6. * See LICENSE for details.
  7. * END COPYRIGHT BLOCK **/
  8. #ifdef HAVE_CONFIG_H
  9. # include <config.h>
  10. #endif
  11. /* number of elements in the output vector */
  12. #define OVECCOUNT 30 /* should be a multiple of 3; store up to \9 */
  13. #include "slap.h"
  14. #include "slapi-plugin.h"
  15. /* Perl Compatible Regular Expression */
  16. #include <pcre.h>
  17. struct slapi_regex_handle {
  18. pcre *re_pcre; /* contains the compiled pattern */
  19. int *re_ovector; /* output vector */
  20. int re_oveccount; /* count of the elements in output vector */
  21. };
  22. /**
  23. * Compiles a regular expression pattern.
  24. *
  25. * \param pat Pattern to be compiled.
  26. * \param error The error string is set if the compile fails.
  27. * \return This function returns a pointer to the regex handler which stores
  28. * the compiled pattern. NULL if the compile fails.
  29. * \warning The regex handler should be released by slapi_re_free().
  30. */
  31. Slapi_Regex *
  32. slapi_re_comp( const char *pat, const char **error )
  33. {
  34. Slapi_Regex *re_handle = NULL;
  35. pcre *re = NULL;
  36. const char *myerror = NULL;
  37. int erroffset;
  38. re = pcre_compile(pat, 0, &myerror, &erroffset, NULL);
  39. if (error) {
  40. *error = myerror;
  41. }
  42. if (re) {
  43. re_handle = (Slapi_Regex *)slapi_ch_calloc(sizeof(Slapi_Regex), 1);
  44. re_handle->re_pcre = re;
  45. }
  46. return re_handle;
  47. }
  48. /**
  49. * Matches a compiled regular expression pattern against a given string.
  50. * A thin wrapper of pcre_exec.
  51. *
  52. * \param re_handle The regex handler returned from slapi_re_comp.
  53. * \param subject A string to be checked against the compiled pattern.
  54. * \param time_up If the current time is larger than the value, this function
  55. * returns immediately. (-1) means no time limit.
  56. * \return This function returns 0 if the string did not match.
  57. * \return This function returns 1 if the string matched.
  58. * \return This function returns other values if any error occurred.
  59. * \warning The regex handler should be released by slapi_re_free().
  60. */
  61. int
  62. slapi_re_exec( Slapi_Regex *re_handle, const char *subject, time_t time_up )
  63. {
  64. int rc;
  65. time_t curtime = current_time();
  66. if (NULL == re_handle || NULL == re_handle->re_pcre || NULL == subject) {
  67. return LDAP_PARAM_ERROR;
  68. }
  69. if ( time_up != -1 && curtime > time_up ) {
  70. return LDAP_TIMELIMIT_EXCEEDED;
  71. }
  72. if (NULL == re_handle->re_ovector) {
  73. re_handle->re_oveccount = OVECCOUNT;
  74. re_handle->re_ovector = (int *)slapi_ch_malloc(sizeof(int) * OVECCOUNT);
  75. }
  76. rc = pcre_exec( re_handle->re_pcre, /* the compiled pattern */
  77. NULL, /* no extra data */
  78. subject, /* the subject string */
  79. strlen(subject), /* the length of the subject */
  80. 0, /* start at offset 0 in the subject */
  81. 0, /* default options */
  82. re_handle->re_ovector, /* output vector for substring info */
  83. re_handle->re_oveccount ); /* number of elems in the ovector */
  84. if (rc >= 0) {
  85. return 1; /* matched */
  86. } else {
  87. return 0; /* did not match */
  88. }
  89. return rc;
  90. }
  91. /**
  92. * Substitutes '&' or '\#' in the param src with the matched string.
  93. *
  94. * \param re_handle The regex handler returned from slapi_re_comp.
  95. * \param subject A string checked against the compiled pattern.
  96. * \param src A given string which could contain the substitution symbols.
  97. * \param dst A pointer pointing to the memory which stores the output string.
  98. * \param dstlen Size of the memory dst.
  99. * \return This function returns 0 if the substitution was successful.
  100. * \return This function returns -1 if the substitution failed.
  101. * \warning The regex handler should be released by slapi_re_free().
  102. */
  103. int
  104. slapi_re_subs( Slapi_Regex *re_handle, const char *subject,
  105. const char *src, char **dst, unsigned long dstlen)
  106. {
  107. return slapi_re_subs_ext(re_handle, subject, src, dst, dstlen, 0 /* not a filter */);
  108. }
  109. int
  110. slapi_re_subs_ext( Slapi_Regex *re_handle, const char *subject,
  111. const char *src, char **dst, unsigned long dstlen, int filter )
  112. {
  113. int thislen = 0;
  114. /* was int, should match the type we compare to in the end! */
  115. unsigned long len = 0;
  116. int pin;
  117. int *ovector;
  118. char *mydst;
  119. const char *prev;
  120. const char *substring_start;
  121. const char *p;
  122. if (NULL == src || NULL == re_handle || NULL == re_handle->re_ovector) {
  123. memset(*dst, '\0', dstlen);
  124. return -1;
  125. } else if (NULL == dst || NULL == *dst || 0 == dstlen) {
  126. return -1;
  127. }
  128. ovector = re_handle->re_ovector;
  129. mydst = *dst;
  130. prev = src;
  131. for (p = src; *p != '\0'; p++) {
  132. if ('&' == *p) {
  133. /* Don't replace '&' if it's a filter AND: "(&(cn=a)(sn=b))" */
  134. if(!filter || !(*prev == '(' && *(p+1) == '(')){
  135. if (re_handle->re_oveccount <= 1) {
  136. memset(*dst, '\0', dstlen);
  137. return -1;
  138. }
  139. substring_start = subject + ovector[0];
  140. thislen = ovector[1] - ovector[0];
  141. len += thislen;
  142. } else { /* is a filter AND clause */
  143. /* just copy it into the filter */
  144. substring_start = p;
  145. thislen = 1;
  146. len++;
  147. }
  148. } else if (('\\' == *p) && ('0' <= *(p+1) && *(p+1) <= '9')) {
  149. pin = *(++p) - '0';
  150. if (re_handle->re_oveccount <= 2*pin+1) {
  151. memset(*dst, '\0', dstlen);
  152. return -1;
  153. }
  154. substring_start = subject + ovector[2*pin];
  155. thislen = ovector[2*pin+1] - ovector[2*pin];
  156. len += thislen;
  157. } else {
  158. substring_start = p;
  159. thislen = 1;
  160. len++;
  161. }
  162. if (len >= dstlen) {
  163. int offset = mydst - *dst;
  164. dstlen = len * 2;
  165. *dst = (char *)slapi_ch_realloc(*dst, dstlen);
  166. mydst = *dst + offset;
  167. }
  168. memcpy(mydst, substring_start, thislen);
  169. mydst += thislen;
  170. prev = p;
  171. }
  172. *mydst = '\0';
  173. return 0;
  174. }
  175. /**
  176. * Releases the regex handler which was returned from slapi_re_comp.
  177. *
  178. * \param re_handle The regex handler to be released.
  179. * \return nothing
  180. */
  181. void
  182. slapi_re_free(Slapi_Regex *re_handle)
  183. {
  184. if (re_handle) {
  185. if (re_handle->re_pcre) {
  186. pcre_free(re_handle->re_pcre);
  187. }
  188. slapi_ch_free((void **)&re_handle->re_ovector);
  189. slapi_ch_free((void **)&re_handle);
  190. }
  191. }