dsalib_dn.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  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. #if defined( XP_WIN32 )
  42. #include <windows.h>
  43. #else
  44. #include <sys/types.h>
  45. #endif
  46. #include <string.h>
  47. #include "dsalib.h"
  48. #include "portable.h"
  49. #include <stdlib.h>
  50. #define DNSEPARATOR(c) (c == ',' || c == ';')
  51. #define SEPARATOR(c) (c == ',' || c == ';' || c == '+')
  52. #define SPACE(c) (c == ' ' || c == '\n')
  53. #define NEEDSESCAPE(c) (c == '\\' || c == '"')
  54. #define B4TYPE 0
  55. #define INTYPE 1
  56. #define B4EQUAL 2
  57. #define B4VALUE 3
  58. #define INVALUE 4
  59. #define INQUOTEDVALUE 5
  60. #define B4SEPARATOR 6
  61. DS_EXPORT_SYMBOL char*
  62. dn_normalize( char *dn )
  63. {
  64. char *d, *s;
  65. int state, gotesc;
  66. /* Debug( LDAP_DEBUG_TRACE, "=> dn_normalize \"%s\"\n", dn, 0, 0 ); */
  67. gotesc = 0;
  68. state = B4TYPE;
  69. for ( d = s = dn; *s; s++ ) {
  70. switch ( state ) {
  71. case B4TYPE:
  72. if ( ! SPACE( *s ) ) {
  73. state = INTYPE;
  74. *d++ = *s;
  75. }
  76. break;
  77. case INTYPE:
  78. if ( *s == '=' ) {
  79. state = B4VALUE;
  80. *d++ = *s;
  81. } else if ( SPACE( *s ) ) {
  82. state = B4EQUAL;
  83. } else {
  84. *d++ = *s;
  85. }
  86. break;
  87. case B4EQUAL:
  88. if ( *s == '=' ) {
  89. state = B4VALUE;
  90. *d++ = *s;
  91. } else if ( ! SPACE( *s ) ) {
  92. /* not a valid dn - but what can we do here? */
  93. *d++ = *s;
  94. }
  95. break;
  96. case B4VALUE:
  97. if ( *s == '"' ) {
  98. state = INQUOTEDVALUE;
  99. *d++ = *s;
  100. } else if ( ! SPACE( *s ) ) {
  101. state = INVALUE;
  102. *d++ = *s;
  103. }
  104. break;
  105. case INVALUE:
  106. if ( !gotesc && SEPARATOR( *s ) ) {
  107. while ( SPACE( *(d - 1) ) )
  108. d--;
  109. state = B4TYPE;
  110. if ( *s == '+' ) {
  111. *d++ = *s;
  112. } else {
  113. *d++ = ',';
  114. }
  115. } else if ( gotesc && !NEEDSESCAPE( *s ) &&
  116. !SEPARATOR( *s ) ) {
  117. *--d = *s;
  118. d++;
  119. } else {
  120. *d++ = *s;
  121. }
  122. break;
  123. case INQUOTEDVALUE:
  124. if ( !gotesc && *s == '"' ) {
  125. state = B4SEPARATOR;
  126. *d++ = *s;
  127. } else if ( gotesc && !NEEDSESCAPE( *s ) ) {
  128. *--d = *s;
  129. d++;
  130. } else {
  131. *d++ = *s;
  132. }
  133. break;
  134. case B4SEPARATOR:
  135. if ( SEPARATOR( *s ) ) {
  136. state = B4TYPE;
  137. if ( *s == '+' ) {
  138. *d++ = *s;
  139. } else {
  140. *d++ = ',';
  141. }
  142. }
  143. break;
  144. default:
  145. break;
  146. }
  147. if ( *s == '\\' ) {
  148. gotesc = 1;
  149. } else {
  150. gotesc = 0;
  151. }
  152. }
  153. *d = '\0';
  154. /* Debug( LDAP_DEBUG_TRACE, "<= dn_normalize \"%s\"\n", dn, 0, 0 ); */
  155. return( dn );
  156. }
  157. DS_EXPORT_SYMBOL char*
  158. ds_dn_expand (char* dn)
  159. {
  160. char* edn;
  161. size_t i = 0;
  162. char* s;
  163. int state = B4TYPE;
  164. int gotesc = 0;
  165. if (dn == NULL) return NULL;
  166. edn = strdup (dn);
  167. if (edn == NULL) return NULL;
  168. for (s = dn; *s != '\0'; ++s, ++i) {
  169. switch (state) {
  170. case B4TYPE:
  171. if ( ! SPACE (*s)) {
  172. state = INTYPE;
  173. }
  174. break;
  175. case INTYPE:
  176. if (*s == '=') {
  177. state = B4VALUE;
  178. } else if (SPACE (*s)) {
  179. state = B4EQUAL;
  180. }
  181. break;
  182. case B4EQUAL:
  183. if (*s == '=') {
  184. state = B4VALUE;
  185. }
  186. break;
  187. case B4VALUE:
  188. if (*s == '"') {
  189. state = INQUOTEDVALUE;
  190. } else if ( ! SPACE (*s)) {
  191. state = INVALUE;
  192. }
  193. break;
  194. case INQUOTEDVALUE:
  195. if (gotesc) {
  196. if ( ! NEEDSESCAPE (*s)) {
  197. --i;
  198. memmove (edn+i, edn+i+1, strlen (edn+i));
  199. }
  200. } else {
  201. if (*s == '"') {
  202. state = B4SEPARATOR;
  203. }
  204. }
  205. break;
  206. case INVALUE:
  207. if (gotesc) {
  208. if ( ! NEEDSESCAPE (*s) && ! SEPARATOR (*s)) {
  209. --i;
  210. memmove (edn+i, edn+i+1, strlen (edn+i));
  211. }
  212. break;
  213. }
  214. case B4SEPARATOR:
  215. if (SEPARATOR (*s)) {
  216. state = B4TYPE;
  217. if ( ! SPACE (s[1])) {
  218. /* insert a space following edn[i] */
  219. edn = (char*) realloc (edn, strlen (edn)+2);
  220. ++i;
  221. memmove (edn+i+1, edn+i, strlen (edn+i)+1);
  222. edn[i] = ' ';
  223. }
  224. }
  225. break;
  226. default:
  227. break;
  228. }
  229. gotesc = (*s == '\\');
  230. }
  231. return edn;
  232. }
  233. int
  234. hexchar2int( char c )
  235. {
  236. if ( '0' <= c && c <= '9' ) {
  237. return( c - '0' );
  238. }
  239. if ( 'a' <= c && c <= 'f' ) {
  240. return( c - 'a' + 10 );
  241. }
  242. if ( 'A' <= c && c <= 'F' ) {
  243. return( c - 'A' + 10 );
  244. }
  245. return( -1 );
  246. }
  247. /*
  248. * substr_dn_normalize - map a DN to a canonical form.
  249. * The DN is read from *dn through *(end-1) and normalized in place.
  250. * The new end is returned; that is, the canonical form is in
  251. * *dn through *(the_return_value-1).
  252. */
  253. /* The goals of this function are:
  254. * 1. be compatible with previous implementations. Especially, enable
  255. * a server running this code to find database index keys that were
  256. * computed by Directory Server 3.0 with a prior version of this code.
  257. * 2. Normalize in place; that is, avoid allocating memory to contain
  258. * the canonical form.
  259. * 3. eliminate insignificant differences; that is, any two DNs are
  260. * not significantly different if and only if their canonical forms
  261. * are identical (ignoring upper/lower case).
  262. * 4. handle a DN in the syntax defined by RFC 2253.
  263. * 5. handle a DN in the syntax defined by RFC 1779.
  264. *
  265. * Goals 3 through 5 are not entirely achieved by this implementation,
  266. * because it can't be done without violating goal 1. Specifically,
  267. * DNs like cn="a,b" and cn=a\,b are not mapped to the same canonical form,
  268. * although they're not significantly different. Likewise for any pair
  269. * of DNs that differ only in their choice of quoting convention.
  270. * A previous version of this code changed all DNs to the most compact
  271. * quoting convention, but that violated goal 1, since Directory Server
  272. * 3.0 did not.
  273. *
  274. * Also, this implementation handles the \xx convention of RFC 2253 and
  275. * consequently violates RFC 1779, according to which this type of quoting
  276. * would be interpreted as a sequence of 2 numerals (not a single byte).
  277. */
  278. DS_EXPORT_SYMBOL char *
  279. dn_normalize_convert( char *dn )
  280. {
  281. /* \xx is changed to \c.
  282. \c is changed to c, unless this would change its meaning.
  283. All values that contain 2 or more separators are "enquoted";
  284. all other values are not enquoted.
  285. */
  286. char *value, *value_separator;
  287. char *d, *s;
  288. char *end;
  289. int gotesc = 0;
  290. int state = B4TYPE;
  291. if (NULL == dn)
  292. return dn;
  293. end = dn + strlen(dn);
  294. for ( d = s = dn; s != end; s++ ) {
  295. switch ( state ) {
  296. case B4TYPE:
  297. if ( ! SPACE( *s ) ) {
  298. state = INTYPE;
  299. *d++ = *s;
  300. }
  301. break;
  302. case INTYPE:
  303. if ( *s == '=' ) {
  304. state = B4VALUE;
  305. *d++ = *s;
  306. } else if ( SPACE( *s ) ) {
  307. state = B4EQUAL;
  308. } else {
  309. *d++ = *s;
  310. }
  311. break;
  312. case B4EQUAL:
  313. if ( *s == '=' ) {
  314. state = B4VALUE;
  315. *d++ = *s;
  316. } else if ( ! SPACE( *s ) ) {
  317. /* not a valid dn - but what can we do here? */
  318. *d++ = *s;
  319. }
  320. break;
  321. case B4VALUE:
  322. if ( *s == '"' || ! SPACE( *s ) ) {
  323. value_separator = NULL;
  324. value = d;
  325. state = ( *s == '"' ) ? INQUOTEDVALUE : INVALUE;
  326. *d++ = *s;
  327. }
  328. break;
  329. case INVALUE:
  330. if ( gotesc ) {
  331. if ( SEPARATOR( *s ) ) {
  332. if ( value_separator ) value_separator = dn;
  333. else value_separator = d;
  334. } else if ( ! NEEDSESCAPE( *s ) ) {
  335. --d; /* eliminate the \ */
  336. }
  337. } else if ( SEPARATOR( *s ) ) {
  338. while ( SPACE( *(d - 1) ) )
  339. d--;
  340. if ( value_separator == dn ) { /* 2 or more separators */
  341. /* convert to quoted value: */
  342. auto char *L = NULL;
  343. auto char *R;
  344. for ( R = value; (R = strchr( R, '\\' )) && (R < d); L = ++R ) {
  345. if ( SEPARATOR( R[1] )) {
  346. if ( L == NULL ) {
  347. auto const size_t len = R - value;
  348. if ( len > 0 ) memmove( value+1, value, len );
  349. *value = '"'; /* opening quote */
  350. value = R + 1;
  351. } else {
  352. auto const size_t len = R - L;
  353. if ( len > 0 ) {
  354. memmove( value, L, len );
  355. value += len;
  356. }
  357. --d;
  358. }
  359. }
  360. }
  361. memmove( value, L, d - L + 1 );
  362. *d++ = '"'; /* closing quote */
  363. }
  364. state = B4TYPE;
  365. *d++ = (*s == '+') ? '+' : ',';
  366. break;
  367. }
  368. *d++ = *s;
  369. break;
  370. case INQUOTEDVALUE:
  371. if ( gotesc ) {
  372. if ( ! NEEDSESCAPE( *s ) ) {
  373. --d; /* eliminate the \ */
  374. }
  375. } else if ( *s == '"' ) {
  376. state = B4SEPARATOR;
  377. if ( value_separator == dn /* 2 or more separators */
  378. || SPACE( value[1] ) || SPACE( d[-1] ) ) {
  379. *d++ = *s;
  380. } else {
  381. /* convert to non-quoted value: */
  382. if ( value_separator == NULL ) { /* no separators */
  383. memmove ( value, value+1, (d-value)-1 );
  384. --d;
  385. } else { /* 1 separator */
  386. memmove ( value, value+1, (value_separator-value)-1 );
  387. *(value_separator - 1) = '\\';
  388. }
  389. }
  390. break;
  391. }
  392. if ( SEPARATOR( *s )) {
  393. if ( value_separator ) value_separator = dn;
  394. else value_separator = d;
  395. }
  396. *d++ = *s;
  397. break;
  398. case B4SEPARATOR:
  399. if ( SEPARATOR( *s ) ) {
  400. state = B4TYPE;
  401. *d++ = (*s == '+') ? '+' : ',';
  402. }
  403. break;
  404. default:
  405. /* LDAPDebug( LDAP_DEBUG_ANY,
  406. "slapi_dn_normalize - unknown state %d\n", state, 0, 0 );*/
  407. break;
  408. }
  409. if ( *s != '\\' ) {
  410. gotesc = 0;
  411. } else {
  412. gotesc = 1;
  413. if ( s+2 < end ) {
  414. auto int n = hexchar2int( s[1] );
  415. if ( n >= 0 ) {
  416. auto int n2 = hexchar2int( s[2] );
  417. if ( n2 >= 0 ) {
  418. n = (n << 4) + n2;
  419. if (n == 0) { /* don't change \00 */
  420. *d++ = *++s;
  421. *d++ = *++s;
  422. gotesc = 0;
  423. } else { /* change \xx to a single char */
  424. ++s;
  425. *(unsigned char*)(s+1) = n;
  426. }
  427. }
  428. }
  429. }
  430. }
  431. }
  432. /* Trim trailing spaces */
  433. while ( d != dn && *(d - 1) == ' ' ) d--;
  434. *d = 0;
  435. return( dn );
  436. }
  437. /* if dn contains an unescaped quote return true */
  438. DS_EXPORT_SYMBOL int
  439. ds_dn_uses_LDAPv2_quoting(const char *dn)
  440. {
  441. const char ESC = '\\';
  442. const char Q = '"';
  443. int ret = 0;
  444. const char *p = 0;
  445. /* check dn for a even number (incl. 0) of ESC followed by Q */
  446. if (!dn)
  447. return ret;
  448. p = strchr(dn, Q);
  449. if (p)
  450. {
  451. int nESC = 0;
  452. for (--p; (p >= dn) && (*p == ESC); --p)
  453. ++nESC;
  454. if (!(nESC % 2))
  455. ret = 1;
  456. }
  457. return ret;
  458. }