url.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653
  1. /* LIBLDAP url.c -- LDAP URL (RFC 4516) related routines */
  2. /* $OpenLDAP$ */
  3. /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  4. *
  5. * Copyright 1998-2022 The OpenLDAP Foundation.
  6. * All rights reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted only as authorized by the OpenLDAP
  10. * Public License.
  11. *
  12. * A copy of this license is available in the file LICENSE in the
  13. * top-level directory of the distribution or, alternatively, at
  14. * <http://www.OpenLDAP.org/license.html>.
  15. */
  16. /* Portions Copyright (c) 1996 Regents of the University of Michigan.
  17. * All rights reserved.
  18. */
  19. /*
  20. * LDAP URLs look like this:
  21. * [p]ldap[is]://host[:port][/[dn[?[attributes][?[scope][?[filter][?exts]]]]]]
  22. *
  23. * where:
  24. * attributes is a comma separated list
  25. * scope is one of these three strings: base one sub (default=base)
  26. * filter is an string-represented filter as in RFC 4515
  27. *
  28. * e.g., ldap://host:port/dc=com?o,cn?base?(o=openldap)?extension
  29. *
  30. * We also tolerate URLs that look like: <ldapurl> and <URL:ldapurl>
  31. */
  32. #include "portable.h"
  33. #include <stdio.h>
  34. #include <ac/stdlib.h>
  35. #include <ac/ctype.h>
  36. #include <ac/socket.h>
  37. #include <ac/string.h>
  38. #include <ac/time.h>
  39. #include "ldap-int.h"
  40. /* local functions */
  41. static const char* skip_url_prefix LDAP_P((
  42. const char *url,
  43. int *enclosedp,
  44. const char **scheme ));
  45. int ldap_pvt_url_scheme2proto( const char *scheme )
  46. {
  47. assert( scheme != NULL );
  48. if( scheme == NULL ) {
  49. return -1;
  50. }
  51. if( strcmp("ldap", scheme) == 0 || strcmp("pldap", scheme) == 0 ) {
  52. return LDAP_PROTO_TCP;
  53. }
  54. if( strcmp("ldapi", scheme) == 0 ) {
  55. return LDAP_PROTO_IPC;
  56. }
  57. if( strcmp("ldaps", scheme) == 0 || strcmp("pldaps", scheme) == 0 ) {
  58. return LDAP_PROTO_TCP;
  59. }
  60. #ifdef LDAP_CONNECTIONLESS
  61. if( strcmp("cldap", scheme) == 0 ) {
  62. return LDAP_PROTO_UDP;
  63. }
  64. #endif
  65. return -1;
  66. }
  67. int ldap_pvt_url_scheme_port( const char *scheme, int port )
  68. {
  69. assert( scheme != NULL );
  70. if( port ) return port;
  71. if( scheme == NULL ) return port;
  72. if( strcmp("ldap", scheme) == 0 || strcmp("pldap", scheme) == 0 ) {
  73. return LDAP_PORT;
  74. }
  75. if( strcmp("ldapi", scheme) == 0 ) {
  76. return -1;
  77. }
  78. if( strcmp("ldaps", scheme) == 0 || strcmp("pldaps", scheme) == 0 ) {
  79. return LDAPS_PORT;
  80. }
  81. #ifdef LDAP_CONNECTIONLESS
  82. if( strcmp("cldap", scheme) == 0 ) {
  83. return LDAP_PORT;
  84. }
  85. #endif
  86. return -1;
  87. }
  88. int
  89. ldap_pvt_url_scheme2tls( const char *scheme )
  90. {
  91. assert( scheme != NULL );
  92. if( scheme == NULL ) {
  93. return -1;
  94. }
  95. return strcmp("ldaps", scheme) == 0 || strcmp("pldaps", scheme) == 0;
  96. }
  97. int
  98. ldap_pvt_url_scheme2proxied( const char *scheme )
  99. {
  100. assert( scheme != NULL );
  101. if( scheme == NULL ) {
  102. return -1;
  103. }
  104. return strcmp("pldap", scheme) == 0 || strcmp("pldaps", scheme) == 0;
  105. }
  106. int
  107. ldap_is_ldap_url( LDAP_CONST char *url )
  108. {
  109. int enclosed;
  110. const char * scheme;
  111. if( url == NULL ) {
  112. return 0;
  113. }
  114. if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) {
  115. return 0;
  116. }
  117. return 1;
  118. }
  119. int
  120. ldap_is_ldaps_url( LDAP_CONST char *url )
  121. {
  122. int enclosed;
  123. const char * scheme;
  124. if( url == NULL ) {
  125. return 0;
  126. }
  127. if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) {
  128. return 0;
  129. }
  130. return strcmp(scheme, "ldaps") == 0 || strcmp(scheme, "pldaps") == 0;
  131. }
  132. int
  133. ldap_is_ldapi_url( LDAP_CONST char *url )
  134. {
  135. int enclosed;
  136. const char * scheme;
  137. if( url == NULL ) {
  138. return 0;
  139. }
  140. if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) {
  141. return 0;
  142. }
  143. return strcmp(scheme, "ldapi") == 0;
  144. }
  145. #ifdef LDAP_CONNECTIONLESS
  146. int
  147. ldap_is_ldapc_url( LDAP_CONST char *url )
  148. {
  149. int enclosed;
  150. const char * scheme;
  151. if( url == NULL ) {
  152. return 0;
  153. }
  154. if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) {
  155. return 0;
  156. }
  157. return strcmp(scheme, "cldap") == 0;
  158. }
  159. #endif
  160. static const char*
  161. skip_url_prefix(
  162. const char *url,
  163. int *enclosedp,
  164. const char **scheme )
  165. {
  166. /*
  167. * return non-zero if this looks like a LDAP URL; zero if not
  168. * if non-zero returned, *urlp will be moved past "ldap://" part of URL
  169. */
  170. const char *p;
  171. if ( url == NULL ) {
  172. return( NULL );
  173. }
  174. p = url;
  175. /* skip leading '<' (if any) */
  176. if ( *p == '<' ) {
  177. *enclosedp = 1;
  178. ++p;
  179. } else {
  180. *enclosedp = 0;
  181. }
  182. /* skip leading "URL:" (if any) */
  183. if ( strncasecmp( p, LDAP_URL_URLCOLON, LDAP_URL_URLCOLON_LEN ) == 0 ) {
  184. p += LDAP_URL_URLCOLON_LEN;
  185. }
  186. /* check for "ldap://" prefix */
  187. if ( strncasecmp( p, LDAP_URL_PREFIX, LDAP_URL_PREFIX_LEN ) == 0 ) {
  188. /* skip over "ldap://" prefix and return success */
  189. p += LDAP_URL_PREFIX_LEN;
  190. *scheme = "ldap";
  191. return( p );
  192. }
  193. /* check for "pldap://" prefix */
  194. if ( strncasecmp( p, PLDAP_URL_PREFIX, PLDAP_URL_PREFIX_LEN ) == 0 ) {
  195. /* skip over "pldap://" prefix and return success */
  196. p += PLDAP_URL_PREFIX_LEN;
  197. *scheme = "pldap";
  198. return( p );
  199. }
  200. /* check for "ldaps://" prefix */
  201. if ( strncasecmp( p, LDAPS_URL_PREFIX, LDAPS_URL_PREFIX_LEN ) == 0 ) {
  202. /* skip over "ldaps://" prefix and return success */
  203. p += LDAPS_URL_PREFIX_LEN;
  204. *scheme = "ldaps";
  205. return( p );
  206. }
  207. /* check for "pldaps://" prefix */
  208. if ( strncasecmp( p, PLDAPS_URL_PREFIX, PLDAPS_URL_PREFIX_LEN ) == 0 ) {
  209. /* skip over "pldaps://" prefix and return success */
  210. p += PLDAPS_URL_PREFIX_LEN;
  211. *scheme = "pldaps";
  212. return( p );
  213. }
  214. /* check for "ldapi://" prefix */
  215. if ( strncasecmp( p, LDAPI_URL_PREFIX, LDAPI_URL_PREFIX_LEN ) == 0 ) {
  216. /* skip over "ldapi://" prefix and return success */
  217. p += LDAPI_URL_PREFIX_LEN;
  218. *scheme = "ldapi";
  219. return( p );
  220. }
  221. #ifdef LDAP_CONNECTIONLESS
  222. /* check for "cldap://" prefix */
  223. if ( strncasecmp( p, LDAPC_URL_PREFIX, LDAPC_URL_PREFIX_LEN ) == 0 ) {
  224. /* skip over "cldap://" prefix and return success */
  225. p += LDAPC_URL_PREFIX_LEN;
  226. *scheme = "cldap";
  227. return( p );
  228. }
  229. #endif
  230. return( NULL );
  231. }
  232. int
  233. ldap_pvt_scope2bv( int scope, struct berval *bv )
  234. {
  235. switch ( scope ) {
  236. case LDAP_SCOPE_BASE:
  237. BER_BVSTR( bv, "base" );
  238. break;
  239. case LDAP_SCOPE_ONELEVEL:
  240. BER_BVSTR( bv, "one" );
  241. break;
  242. case LDAP_SCOPE_SUBTREE:
  243. BER_BVSTR( bv, "sub" );
  244. break;
  245. case LDAP_SCOPE_SUBORDINATE:
  246. BER_BVSTR( bv, "subordinate" );
  247. break;
  248. default:
  249. return LDAP_OTHER;
  250. }
  251. return LDAP_SUCCESS;
  252. }
  253. const char *
  254. ldap_pvt_scope2str( int scope )
  255. {
  256. struct berval bv;
  257. if ( ldap_pvt_scope2bv( scope, &bv ) == LDAP_SUCCESS ) {
  258. return bv.bv_val;
  259. }
  260. return NULL;
  261. }
  262. int
  263. ldap_pvt_bv2scope( struct berval *bv )
  264. {
  265. static struct {
  266. struct berval bv;
  267. int scope;
  268. } v[] = {
  269. { BER_BVC( "one" ), LDAP_SCOPE_ONELEVEL },
  270. { BER_BVC( "onelevel" ), LDAP_SCOPE_ONELEVEL },
  271. { BER_BVC( "base" ), LDAP_SCOPE_BASE },
  272. { BER_BVC( "sub" ), LDAP_SCOPE_SUBTREE },
  273. { BER_BVC( "subtree" ), LDAP_SCOPE_SUBTREE },
  274. { BER_BVC( "subord" ), LDAP_SCOPE_SUBORDINATE },
  275. { BER_BVC( "subordinate" ), LDAP_SCOPE_SUBORDINATE },
  276. { BER_BVC( "children" ), LDAP_SCOPE_SUBORDINATE },
  277. { BER_BVNULL, -1 }
  278. };
  279. int i;
  280. for ( i = 0; v[ i ].scope != -1; i++ ) {
  281. if ( ber_bvstrcasecmp( bv, &v[ i ].bv ) == 0 ) {
  282. return v[ i ].scope;
  283. }
  284. }
  285. return( -1 );
  286. }
  287. int
  288. ldap_pvt_str2scope( const char *p )
  289. {
  290. struct berval bv;
  291. ber_str2bv( p, 0, 0, &bv );
  292. return ldap_pvt_bv2scope( &bv );
  293. }
  294. static const char hex[] = "0123456789ABCDEF";
  295. #define URLESC_NONE 0x0000U
  296. #define URLESC_COMMA 0x0001U
  297. #define URLESC_SLASH 0x0002U
  298. static int
  299. hex_escape_len( const char *s, unsigned list )
  300. {
  301. int len;
  302. if ( s == NULL ) {
  303. return 0;
  304. }
  305. for ( len = 0; s[0]; s++ ) {
  306. switch ( s[0] ) {
  307. /* RFC 2396: reserved */
  308. case '?':
  309. len += 3;
  310. break;
  311. case ',':
  312. if ( list & URLESC_COMMA ) {
  313. len += 3;
  314. } else {
  315. len++;
  316. }
  317. break;
  318. case '/':
  319. if ( list & URLESC_SLASH ) {
  320. len += 3;
  321. } else {
  322. len++;
  323. }
  324. break;
  325. case ';':
  326. case ':':
  327. case '@':
  328. case '&':
  329. case '=':
  330. case '+':
  331. case '$':
  332. /* RFC 2396: unreserved mark */
  333. case '-':
  334. case '_':
  335. case '.':
  336. case '!':
  337. case '~':
  338. case '*':
  339. case '\'':
  340. case '(':
  341. case ')':
  342. len++;
  343. break;
  344. /* RFC 2396: unreserved alphanum */
  345. default:
  346. if ( !isalnum( (unsigned char) s[0] ) ) {
  347. len += 3;
  348. } else {
  349. len++;
  350. }
  351. break;
  352. }
  353. }
  354. return len;
  355. }
  356. static int
  357. hex_escape( char *buf, int len, const char *s, unsigned list )
  358. {
  359. int i;
  360. int pos;
  361. if ( s == NULL ) {
  362. return 0;
  363. }
  364. for ( pos = 0, i = 0; s[i] && pos < len; i++ ) {
  365. int escape = 0;
  366. switch ( s[i] ) {
  367. /* RFC 2396: reserved */
  368. case '?':
  369. escape = 1;
  370. break;
  371. case ',':
  372. if ( list & URLESC_COMMA ) {
  373. escape = 1;
  374. }
  375. break;
  376. case '/':
  377. if ( list & URLESC_SLASH ) {
  378. escape = 1;
  379. }
  380. break;
  381. case ';':
  382. case ':':
  383. case '@':
  384. case '&':
  385. case '=':
  386. case '+':
  387. case '$':
  388. /* RFC 2396: unreserved mark */
  389. case '-':
  390. case '_':
  391. case '.':
  392. case '!':
  393. case '~':
  394. case '*':
  395. case '\'':
  396. case '(':
  397. case ')':
  398. break;
  399. /* RFC 2396: unreserved alphanum */
  400. default:
  401. if ( !isalnum( (unsigned char) s[i] ) ) {
  402. escape = 1;
  403. }
  404. break;
  405. }
  406. if ( escape ) {
  407. buf[pos++] = '%';
  408. buf[pos++] = hex[ (s[i] >> 4) & 0x0f ];
  409. buf[pos++] = hex[ s[i] & 0x0f ];
  410. } else {
  411. buf[pos++] = s[i];
  412. }
  413. }
  414. buf[pos] = '\0';
  415. return pos;
  416. }
  417. static int
  418. hex_escape_len_list( char **s, unsigned flags )
  419. {
  420. int len;
  421. int i;
  422. if ( s == NULL ) {
  423. return 0;
  424. }
  425. len = 0;
  426. for ( i = 0; s[i] != NULL; i++ ) {
  427. if ( len ) {
  428. len++;
  429. }
  430. len += hex_escape_len( s[i], flags );
  431. }
  432. return len;
  433. }
  434. static int
  435. hex_escape_list( char *buf, int len, char **s, unsigned flags )
  436. {
  437. int pos;
  438. int i;
  439. if ( s == NULL ) {
  440. return 0;
  441. }
  442. pos = 0;
  443. for ( i = 0; s[i] != NULL; i++ ) {
  444. int curlen;
  445. if ( pos ) {
  446. buf[pos++] = ',';
  447. len--;
  448. }
  449. curlen = hex_escape( &buf[pos], len, s[i], flags );
  450. len -= curlen;
  451. pos += curlen;
  452. }
  453. return pos;
  454. }
  455. static int
  456. desc2str_len( LDAPURLDesc *u )
  457. {
  458. int sep = 0;
  459. int len = 0;
  460. int is_ipc = 0;
  461. struct berval scope;
  462. if ( u == NULL || u->lud_scheme == NULL ) {
  463. return -1;
  464. }
  465. if ( !strcmp( "ldapi", u->lud_scheme )) {
  466. is_ipc = 1;
  467. }
  468. if ( u->lud_exts ) {
  469. len += hex_escape_len_list( u->lud_exts, URLESC_COMMA );
  470. if ( !sep ) {
  471. sep = 5;
  472. }
  473. }
  474. if ( u->lud_filter ) {
  475. len += hex_escape_len( u->lud_filter, URLESC_NONE );
  476. if ( !sep ) {
  477. sep = 4;
  478. }
  479. }
  480. if ( ldap_pvt_scope2bv( u->lud_scope, &scope ) == LDAP_SUCCESS ) {
  481. len += scope.bv_len;
  482. if ( !sep ) {
  483. sep = 3;
  484. }
  485. }
  486. if ( u->lud_attrs ) {
  487. len += hex_escape_len_list( u->lud_attrs, URLESC_NONE );
  488. if ( !sep ) {
  489. sep = 2;
  490. }
  491. }
  492. if ( u->lud_dn && u->lud_dn[0] ) {
  493. len += hex_escape_len( u->lud_dn, URLESC_NONE );
  494. if ( !sep ) {
  495. sep = 1;
  496. }
  497. };
  498. len += sep;
  499. if ( u->lud_port ) {
  500. unsigned p = u->lud_port;
  501. if ( p > 65535 )
  502. return -1;
  503. len += (p > 999 ? 5 + (p > 9999) : p > 99 ? 4 : 2 + (p > 9));
  504. }
  505. if ( u->lud_host && u->lud_host[0] ) {
  506. char *ptr;
  507. len += hex_escape_len( u->lud_host, URLESC_SLASH );
  508. if ( !is_ipc && ( ptr = strchr( u->lud_host, ':' ))) {
  509. if ( strchr( ptr+1, ':' ))
  510. len += 2; /* IPv6, [] */
  511. }
  512. }
  513. len += strlen( u->lud_scheme ) + STRLENOF( "://" );
  514. return len;
  515. }
  516. static int
  517. desc2str( LDAPURLDesc *u, char *s, int len )
  518. {
  519. int i;
  520. int sep = 0;
  521. int sofar = 0;
  522. int is_v6 = 0;
  523. int is_ipc = 0;
  524. struct berval scope = BER_BVNULL;
  525. char *ptr;
  526. if ( u == NULL ) {
  527. return -1;
  528. }
  529. if ( s == NULL ) {
  530. return -1;
  531. }
  532. if ( u->lud_scheme && !strcmp( "ldapi", u->lud_scheme )) {
  533. is_ipc = 1;
  534. }
  535. ldap_pvt_scope2bv( u->lud_scope, &scope );
  536. if ( u->lud_exts ) {
  537. sep = 5;
  538. } else if ( u->lud_filter ) {
  539. sep = 4;
  540. } else if ( !BER_BVISEMPTY( &scope ) ) {
  541. sep = 3;
  542. } else if ( u->lud_attrs ) {
  543. sep = 2;
  544. } else if ( u->lud_dn && u->lud_dn[0] ) {
  545. sep = 1;
  546. }
  547. if ( !is_ipc && u->lud_host && ( ptr = strchr( u->lud_host, ':' ))) {
  548. if ( strchr( ptr+1, ':' ))
  549. is_v6 = 1;
  550. }
  551. if ( u->lud_port ) {
  552. sofar = sprintf( s, "%s://%s%s%s:%d", u->lud_scheme,
  553. is_v6 ? "[" : "",
  554. u->lud_host ? u->lud_host : "",
  555. is_v6 ? "]" : "",
  556. u->lud_port );
  557. len -= sofar;
  558. } else {
  559. sofar = sprintf( s, "%s://", u->lud_scheme );
  560. len -= sofar;
  561. if ( u->lud_host && u->lud_host[0] ) {
  562. if ( is_v6 ) {
  563. s[sofar++] = '[';
  564. len--;
  565. }
  566. i = hex_escape( &s[sofar], len, u->lud_host, URLESC_SLASH );
  567. sofar += i;
  568. len -= i;
  569. if ( is_v6 ) {
  570. s[sofar++] = ']';
  571. len--;
  572. }
  573. }
  574. }
  575. assert( len >= 0 );
  576. if ( sep < 1 ) {
  577. goto done;
  578. }
  579. s[sofar++] = '/';
  580. len--;
  581. assert( len >= 0 );
  582. if ( u->lud_dn && u->lud_dn[0] ) {
  583. i = hex_escape( &s[sofar], len, u->lud_dn, URLESC_NONE );
  584. sofar += i;
  585. len -= i;
  586. assert( len >= 0 );
  587. }
  588. if ( sep < 2 ) {
  589. goto done;
  590. }
  591. s[sofar++] = '?';
  592. len--;
  593. assert( len >= 0 );
  594. i = hex_escape_list( &s[sofar], len, u->lud_attrs, URLESC_NONE );
  595. sofar += i;
  596. len -= i;
  597. assert( len >= 0 );
  598. if ( sep < 3 ) {
  599. goto done;
  600. }
  601. s[sofar++] = '?';
  602. len--;
  603. assert( len >= 0 );
  604. if ( !BER_BVISNULL( &scope ) ) {
  605. strcpy( &s[sofar], scope.bv_val );
  606. sofar += scope.bv_len;
  607. len -= scope.bv_len;
  608. }
  609. assert( len >= 0 );
  610. if ( sep < 4 ) {
  611. goto done;
  612. }
  613. s[sofar++] = '?';
  614. len--;
  615. assert( len >= 0 );
  616. i = hex_escape( &s[sofar], len, u->lud_filter, URLESC_NONE );
  617. sofar += i;
  618. len -= i;
  619. assert( len >= 0 );
  620. if ( sep < 5 ) {
  621. goto done;
  622. }
  623. s[sofar++] = '?';
  624. len--;
  625. assert( len >= 0 );
  626. i = hex_escape_list( &s[sofar], len, u->lud_exts, URLESC_COMMA );
  627. sofar += i;
  628. len -= i;
  629. assert( len >= 0 );
  630. done:
  631. if ( len < 0 ) {
  632. return -1;
  633. }
  634. return sofar;
  635. }
  636. char *
  637. ldap_url_desc2str( LDAPURLDesc *u )
  638. {
  639. int len;
  640. char *s;
  641. if ( u == NULL ) {
  642. return NULL;
  643. }
  644. len = desc2str_len( u );
  645. if ( len < 0 ) {
  646. return NULL;
  647. }
  648. /* allocate enough to hex escape everything -- overkill */
  649. s = LDAP_MALLOC( len + 1 );
  650. if ( s == NULL ) {
  651. return NULL;
  652. }
  653. if ( desc2str( u, s, len ) != len ) {
  654. LDAP_FREE( s );
  655. return NULL;
  656. }
  657. s[len] = '\0';
  658. return s;
  659. }
  660. int
  661. ldap_url_parse_ext( LDAP_CONST char *url_in, LDAPURLDesc **ludpp, unsigned flags )
  662. {
  663. /*
  664. * Pick apart the pieces of an LDAP URL.
  665. */
  666. LDAPURLDesc *ludp;
  667. char *p, *q, *r;
  668. int i, enclosed, proto, is_v6 = 0;
  669. const char *scheme = NULL;
  670. const char *url_tmp;
  671. char *url;
  672. int check_dn = 1;
  673. if( url_in == NULL || ludpp == NULL ) {
  674. return LDAP_URL_ERR_PARAM;
  675. }
  676. #ifndef LDAP_INT_IN_KERNEL
  677. /* Global options may not be created yet
  678. * We can't test if the global options are initialized
  679. * because a call to LDAP_INT_GLOBAL_OPT() will try to allocate
  680. * the options and cause infinite recursion
  681. */
  682. Debug1( LDAP_DEBUG_TRACE, "ldap_url_parse_ext(%s)\n", url_in );
  683. #endif
  684. *ludpp = NULL; /* pessimistic */
  685. url_tmp = skip_url_prefix( url_in, &enclosed, &scheme );
  686. if ( url_tmp == NULL ) {
  687. return LDAP_URL_ERR_BADSCHEME;
  688. }
  689. assert( scheme != NULL );
  690. proto = ldap_pvt_url_scheme2proto( scheme );
  691. if ( proto == -1 ) {
  692. return LDAP_URL_ERR_BADSCHEME;
  693. }
  694. /* make working copy of the remainder of the URL */
  695. url = LDAP_STRDUP( url_tmp );
  696. if ( url == NULL ) {
  697. return LDAP_URL_ERR_MEM;
  698. }
  699. if ( enclosed ) {
  700. p = &url[strlen(url)-1];
  701. if( *p != '>' ) {
  702. LDAP_FREE( url );
  703. return LDAP_URL_ERR_BADENCLOSURE;
  704. }
  705. *p = '\0';
  706. }
  707. /* allocate return struct */
  708. ludp = (LDAPURLDesc *)LDAP_CALLOC( 1, sizeof( LDAPURLDesc ));
  709. if ( ludp == NULL ) {
  710. LDAP_FREE( url );
  711. return LDAP_URL_ERR_MEM;
  712. }
  713. ludp->lud_next = NULL;
  714. ludp->lud_host = NULL;
  715. ludp->lud_port = 0;
  716. ludp->lud_dn = NULL;
  717. ludp->lud_attrs = NULL;
  718. ludp->lud_scope = ( flags & LDAP_PVT_URL_PARSE_NODEF_SCOPE ) ? LDAP_SCOPE_BASE : LDAP_SCOPE_DEFAULT;
  719. ludp->lud_filter = NULL;
  720. ludp->lud_exts = NULL;
  721. ludp->lud_scheme = LDAP_STRDUP( scheme );
  722. if ( ludp->lud_scheme == NULL ) {
  723. LDAP_FREE( url );
  724. ldap_free_urldesc( ludp );
  725. return LDAP_URL_ERR_MEM;
  726. }
  727. /* scan forward for '/' that marks end of hostport and begin. of dn */
  728. p = strchr( url, '/' );
  729. q = NULL;
  730. if( p != NULL ) {
  731. /* terminate hostport; point to start of dn */
  732. *p++ = '\0';
  733. } else {
  734. /* check for Novell kludge, see below */
  735. p = strchr( url, '?' );
  736. if ( p ) {
  737. *p++ = '\0';
  738. q = p;
  739. p = NULL;
  740. }
  741. }
  742. if ( proto != LDAP_PROTO_IPC ) {
  743. /* IPv6 syntax with [ip address]:port */
  744. if ( *url == '[' ) {
  745. r = strchr( url, ']' );
  746. if ( r == NULL ) {
  747. LDAP_FREE( url );
  748. ldap_free_urldesc( ludp );
  749. return LDAP_URL_ERR_BADURL;
  750. }
  751. *r++ = '\0';
  752. q = strchr( r, ':' );
  753. if ( q && q != r ) {
  754. LDAP_FREE( url );
  755. ldap_free_urldesc( ludp );
  756. return LDAP_URL_ERR_BADURL;
  757. }
  758. is_v6 = 1;
  759. } else {
  760. q = strchr( url, ':' );
  761. }
  762. if ( q != NULL ) {
  763. char *next;
  764. *q++ = '\0';
  765. ldap_pvt_hex_unescape( q );
  766. if( *q == '\0' ) {
  767. LDAP_FREE( url );
  768. ldap_free_urldesc( ludp );
  769. return LDAP_URL_ERR_BADURL;
  770. }
  771. ludp->lud_port = strtol( q, &next, 10 );
  772. if ( next == q || next[0] != '\0' ) {
  773. LDAP_FREE( url );
  774. ldap_free_urldesc( ludp );
  775. return LDAP_URL_ERR_BADURL;
  776. }
  777. /* check for Novell kludge */
  778. if ( !p ) {
  779. if ( *next != '\0' ) {
  780. q = &next[1];
  781. } else {
  782. q = NULL;
  783. }
  784. }
  785. }
  786. if ( ( flags & LDAP_PVT_URL_PARSE_DEF_PORT ) && ludp->lud_port == 0 ) {
  787. if ( strcmp( ludp->lud_scheme, "ldaps" ) == 0 ) {
  788. ludp->lud_port = LDAPS_PORT;
  789. } else {
  790. ludp->lud_port = LDAP_PORT;
  791. }
  792. }
  793. }
  794. ldap_pvt_hex_unescape( url );
  795. /* If [ip address]:port syntax, url is [ip and we skip the [ */
  796. ludp->lud_host = LDAP_STRDUP( url + is_v6 );
  797. if( ludp->lud_host == NULL ) {
  798. LDAP_FREE( url );
  799. ldap_free_urldesc( ludp );
  800. return LDAP_URL_ERR_MEM;
  801. }
  802. if ( ( flags & LDAP_PVT_URL_PARSE_NOEMPTY_HOST )
  803. && ludp->lud_host != NULL
  804. && *ludp->lud_host == '\0' )
  805. {
  806. LDAP_FREE( ludp->lud_host );
  807. ludp->lud_host = NULL;
  808. }
  809. /*
  810. * Kludge. ldap://111.222.333.444:389??cn=abc,o=company
  811. *
  812. * On early Novell releases, search references/referrals were returned
  813. * in this format, i.e., the dn was kind of in the scope position,
  814. * but the required slash is missing. The whole thing is illegal syntax,
  815. * but we need to account for it. Fortunately it can't be confused with
  816. * anything real.
  817. */
  818. if( (p == NULL) && (q != NULL) && (*q == '?') ) {
  819. /* ? immediately followed by question */
  820. q++;
  821. if( *q != '\0' ) {
  822. /* parse dn part */
  823. ldap_pvt_hex_unescape( q );
  824. ludp->lud_dn = LDAP_STRDUP( q );
  825. } else if ( !( flags & LDAP_PVT_URL_PARSE_NOEMPTY_DN ) ) {
  826. ludp->lud_dn = LDAP_STRDUP( "" );
  827. } else {
  828. check_dn = 0;
  829. }
  830. if ( check_dn && ludp->lud_dn == NULL ) {
  831. LDAP_FREE( url );
  832. ldap_free_urldesc( ludp );
  833. return LDAP_URL_ERR_MEM;
  834. }
  835. }
  836. if( p == NULL ) {
  837. LDAP_FREE( url );
  838. *ludpp = ludp;
  839. return LDAP_URL_SUCCESS;
  840. }
  841. /* scan forward for '?' that may marks end of dn */
  842. q = strchr( p, '?' );
  843. if( q != NULL ) {
  844. /* terminate dn part */
  845. *q++ = '\0';
  846. }
  847. if( *p != '\0' ) {
  848. /* parse dn part */
  849. ldap_pvt_hex_unescape( p );
  850. ludp->lud_dn = LDAP_STRDUP( p );
  851. } else if ( !( flags & LDAP_PVT_URL_PARSE_NOEMPTY_DN ) ) {
  852. ludp->lud_dn = LDAP_STRDUP( "" );
  853. } else {
  854. check_dn = 0;
  855. }
  856. if( check_dn && ludp->lud_dn == NULL ) {
  857. LDAP_FREE( url );
  858. ldap_free_urldesc( ludp );
  859. return LDAP_URL_ERR_MEM;
  860. }
  861. if( q == NULL ) {
  862. /* no more */
  863. LDAP_FREE( url );
  864. *ludpp = ludp;
  865. return LDAP_URL_SUCCESS;
  866. }
  867. /* scan forward for '?' that may marks end of attributes */
  868. p = q;
  869. q = strchr( p, '?' );
  870. if( q != NULL ) {
  871. /* terminate attributes part */
  872. *q++ = '\0';
  873. }
  874. if( *p != '\0' ) {
  875. /* parse attributes */
  876. ldap_pvt_hex_unescape( p );
  877. ludp->lud_attrs = ldap_str2charray( p, "," );
  878. if( ludp->lud_attrs == NULL ) {
  879. LDAP_FREE( url );
  880. ldap_free_urldesc( ludp );
  881. return LDAP_URL_ERR_BADATTRS;
  882. }
  883. }
  884. if ( q == NULL ) {
  885. /* no more */
  886. LDAP_FREE( url );
  887. *ludpp = ludp;
  888. return LDAP_URL_SUCCESS;
  889. }
  890. /* scan forward for '?' that may marks end of scope */
  891. p = q;
  892. q = strchr( p, '?' );
  893. if( q != NULL ) {
  894. /* terminate the scope part */
  895. *q++ = '\0';
  896. }
  897. if( *p != '\0' ) {
  898. /* parse the scope */
  899. ldap_pvt_hex_unescape( p );
  900. ludp->lud_scope = ldap_pvt_str2scope( p );
  901. if( ludp->lud_scope == -1 ) {
  902. LDAP_FREE( url );
  903. ldap_free_urldesc( ludp );
  904. return LDAP_URL_ERR_BADSCOPE;
  905. }
  906. }
  907. if ( q == NULL ) {
  908. /* no more */
  909. LDAP_FREE( url );
  910. *ludpp = ludp;
  911. return LDAP_URL_SUCCESS;
  912. }
  913. /* scan forward for '?' that may marks end of filter */
  914. p = q;
  915. q = strchr( p, '?' );
  916. if( q != NULL ) {
  917. /* terminate the filter part */
  918. *q++ = '\0';
  919. }
  920. if( *p != '\0' ) {
  921. /* parse the filter */
  922. ldap_pvt_hex_unescape( p );
  923. if( ! *p ) {
  924. /* missing filter */
  925. LDAP_FREE( url );
  926. ldap_free_urldesc( ludp );
  927. return LDAP_URL_ERR_BADFILTER;
  928. }
  929. ludp->lud_filter = LDAP_STRDUP( p );
  930. if( ludp->lud_filter == NULL ) {
  931. LDAP_FREE( url );
  932. ldap_free_urldesc( ludp );
  933. return LDAP_URL_ERR_MEM;
  934. }
  935. }
  936. if ( q == NULL ) {
  937. /* no more */
  938. LDAP_FREE( url );
  939. *ludpp = ludp;
  940. return LDAP_URL_SUCCESS;
  941. }
  942. /* scan forward for '?' that may marks end of extensions */
  943. p = q;
  944. q = strchr( p, '?' );
  945. if( q != NULL ) {
  946. /* extra '?' */
  947. LDAP_FREE( url );
  948. ldap_free_urldesc( ludp );
  949. return LDAP_URL_ERR_BADURL;
  950. }
  951. /* parse the extensions */
  952. ludp->lud_exts = ldap_str2charray( p, "," );
  953. if( ludp->lud_exts == NULL ) {
  954. LDAP_FREE( url );
  955. ldap_free_urldesc( ludp );
  956. return LDAP_URL_ERR_BADEXTS;
  957. }
  958. for( i=0; ludp->lud_exts[i] != NULL; i++ ) {
  959. ldap_pvt_hex_unescape( ludp->lud_exts[i] );
  960. if( *ludp->lud_exts[i] == '!' ) {
  961. /* count the number of critical extensions */
  962. ludp->lud_crit_exts++;
  963. }
  964. }
  965. if( i == 0 ) {
  966. /* must have 1 or more */
  967. LDAP_FREE( url );
  968. ldap_free_urldesc( ludp );
  969. return LDAP_URL_ERR_BADEXTS;
  970. }
  971. /* no more */
  972. *ludpp = ludp;
  973. LDAP_FREE( url );
  974. return LDAP_URL_SUCCESS;
  975. }
  976. int
  977. ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp )
  978. {
  979. return ldap_url_parse_ext( url_in, ludpp, LDAP_PVT_URL_PARSE_HISTORIC );
  980. }
  981. LDAPURLDesc *
  982. ldap_url_dup ( LDAPURLDesc *ludp )
  983. {
  984. LDAPURLDesc *dest;
  985. if ( ludp == NULL ) {
  986. return NULL;
  987. }
  988. dest = LDAP_MALLOC( sizeof(LDAPURLDesc) );
  989. if (dest == NULL)
  990. return NULL;
  991. *dest = *ludp;
  992. dest->lud_scheme = NULL;
  993. dest->lud_host = NULL;
  994. dest->lud_dn = NULL;
  995. dest->lud_filter = NULL;
  996. dest->lud_attrs = NULL;
  997. dest->lud_exts = NULL;
  998. dest->lud_next = NULL;
  999. if ( ludp->lud_scheme != NULL ) {
  1000. dest->lud_scheme = LDAP_STRDUP( ludp->lud_scheme );
  1001. if (dest->lud_scheme == NULL) {
  1002. ldap_free_urldesc(dest);
  1003. return NULL;
  1004. }
  1005. }
  1006. if ( ludp->lud_host != NULL ) {
  1007. dest->lud_host = LDAP_STRDUP( ludp->lud_host );
  1008. if (dest->lud_host == NULL) {
  1009. ldap_free_urldesc(dest);
  1010. return NULL;
  1011. }
  1012. }
  1013. if ( ludp->lud_dn != NULL ) {
  1014. dest->lud_dn = LDAP_STRDUP( ludp->lud_dn );
  1015. if (dest->lud_dn == NULL) {
  1016. ldap_free_urldesc(dest);
  1017. return NULL;
  1018. }
  1019. }
  1020. if ( ludp->lud_filter != NULL ) {
  1021. dest->lud_filter = LDAP_STRDUP( ludp->lud_filter );
  1022. if (dest->lud_filter == NULL) {
  1023. ldap_free_urldesc(dest);
  1024. return NULL;
  1025. }
  1026. }
  1027. if ( ludp->lud_attrs != NULL ) {
  1028. dest->lud_attrs = ldap_charray_dup( ludp->lud_attrs );
  1029. if (dest->lud_attrs == NULL) {
  1030. ldap_free_urldesc(dest);
  1031. return NULL;
  1032. }
  1033. }
  1034. if ( ludp->lud_exts != NULL ) {
  1035. dest->lud_exts = ldap_charray_dup( ludp->lud_exts );
  1036. if (dest->lud_exts == NULL) {
  1037. ldap_free_urldesc(dest);
  1038. return NULL;
  1039. }
  1040. }
  1041. return dest;
  1042. }
  1043. LDAPURLDesc *
  1044. ldap_url_duplist (LDAPURLDesc *ludlist)
  1045. {
  1046. LDAPURLDesc *dest, *tail, *ludp, *newludp;
  1047. dest = NULL;
  1048. tail = NULL;
  1049. for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) {
  1050. newludp = ldap_url_dup(ludp);
  1051. if (newludp == NULL) {
  1052. ldap_free_urllist(dest);
  1053. return NULL;
  1054. }
  1055. if (tail == NULL)
  1056. dest = newludp;
  1057. else
  1058. tail->lud_next = newludp;
  1059. tail = newludp;
  1060. }
  1061. return dest;
  1062. }
  1063. static int
  1064. ldap_url_parselist_int (LDAPURLDesc **ludlist, const char *url, const char *sep, unsigned flags )
  1065. {
  1066. int i, rc;
  1067. LDAPURLDesc *ludp;
  1068. char **urls;
  1069. assert( ludlist != NULL );
  1070. assert( url != NULL );
  1071. *ludlist = NULL;
  1072. if ( sep == NULL ) {
  1073. sep = ", ";
  1074. }
  1075. urls = ldap_str2charray( url, sep );
  1076. if (urls == NULL)
  1077. return LDAP_URL_ERR_MEM;
  1078. /* count the URLs... */
  1079. for (i = 0; urls[i] != NULL; i++) ;
  1080. /* ...and put them in the "stack" backward */
  1081. while (--i >= 0) {
  1082. rc = ldap_url_parse_ext( urls[i], &ludp, flags );
  1083. if ( rc != 0 ) {
  1084. ldap_charray_free( urls );
  1085. ldap_free_urllist( *ludlist );
  1086. *ludlist = NULL;
  1087. return rc;
  1088. }
  1089. ludp->lud_next = *ludlist;
  1090. *ludlist = ludp;
  1091. }
  1092. ldap_charray_free( urls );
  1093. return LDAP_URL_SUCCESS;
  1094. }
  1095. int
  1096. ldap_url_parselist (LDAPURLDesc **ludlist, const char *url )
  1097. {
  1098. return ldap_url_parselist_int( ludlist, url, ", ", LDAP_PVT_URL_PARSE_HISTORIC );
  1099. }
  1100. int
  1101. ldap_url_parselist_ext (LDAPURLDesc **ludlist, const char *url, const char *sep, unsigned flags )
  1102. {
  1103. return ldap_url_parselist_int( ludlist, url, sep, flags );
  1104. }
  1105. int
  1106. ldap_url_parsehosts(
  1107. LDAPURLDesc **ludlist,
  1108. const char *hosts,
  1109. int port )
  1110. {
  1111. int i;
  1112. LDAPURLDesc *ludp;
  1113. char **specs, *p;
  1114. assert( ludlist != NULL );
  1115. assert( hosts != NULL );
  1116. *ludlist = NULL;
  1117. specs = ldap_str2charray(hosts, ", ");
  1118. if (specs == NULL)
  1119. return LDAP_NO_MEMORY;
  1120. /* count the URLs... */
  1121. for (i = 0; specs[i] != NULL; i++) /* EMPTY */;
  1122. /* ...and put them in the "stack" backward */
  1123. while (--i >= 0) {
  1124. ludp = LDAP_CALLOC( 1, sizeof(LDAPURLDesc) );
  1125. if (ludp == NULL) {
  1126. ldap_charray_free(specs);
  1127. ldap_free_urllist(*ludlist);
  1128. *ludlist = NULL;
  1129. return LDAP_NO_MEMORY;
  1130. }
  1131. ludp->lud_port = port;
  1132. ludp->lud_host = specs[i];
  1133. p = strchr(ludp->lud_host, ':');
  1134. if (p != NULL) {
  1135. /* more than one :, IPv6 address */
  1136. if ( strchr(p+1, ':') != NULL ) {
  1137. /* allow [address] and [address]:port */
  1138. if ( *ludp->lud_host == '[' ) {
  1139. p = strchr( ludp->lud_host+1, ']' );
  1140. if ( p == NULL ) {
  1141. LDAP_FREE(ludp);
  1142. ldap_charray_free(specs);
  1143. return LDAP_PARAM_ERROR;
  1144. }
  1145. /* Truncate trailing ']' and shift hostname down 1 char */
  1146. *p = '\0';
  1147. AC_MEMCPY( ludp->lud_host, ludp->lud_host+1, p - ludp->lud_host );
  1148. p++;
  1149. if ( *p != ':' ) {
  1150. if ( *p != '\0' ) {
  1151. LDAP_FREE(ludp);
  1152. ldap_charray_free(specs);
  1153. return LDAP_PARAM_ERROR;
  1154. }
  1155. p = NULL;
  1156. }
  1157. } else {
  1158. p = NULL;
  1159. }
  1160. }
  1161. if (p != NULL) {
  1162. char *next;
  1163. *p++ = 0;
  1164. ldap_pvt_hex_unescape(p);
  1165. ludp->lud_port = strtol( p, &next, 10 );
  1166. if ( next == p || next[0] != '\0' ) {
  1167. LDAP_FREE(ludp);
  1168. ldap_charray_free(specs);
  1169. return LDAP_PARAM_ERROR;
  1170. }
  1171. }
  1172. }
  1173. ludp->lud_scheme = LDAP_STRDUP("ldap");
  1174. if ( ludp->lud_scheme == NULL ) {
  1175. LDAP_FREE(ludp);
  1176. ldap_charray_free(specs);
  1177. return LDAP_NO_MEMORY;
  1178. }
  1179. specs[i] = NULL;
  1180. ldap_pvt_hex_unescape(ludp->lud_host);
  1181. ludp->lud_next = *ludlist;
  1182. *ludlist = ludp;
  1183. }
  1184. /* this should be an array of NULLs now */
  1185. ldap_charray_free(specs);
  1186. return LDAP_SUCCESS;
  1187. }
  1188. char *
  1189. ldap_url_list2hosts (LDAPURLDesc *ludlist)
  1190. {
  1191. LDAPURLDesc *ludp;
  1192. int size;
  1193. char *s, *p, buf[32]; /* big enough to hold a long decimal # (overkill) */
  1194. if (ludlist == NULL)
  1195. return NULL;
  1196. /* figure out how big the string is */
  1197. size = 1; /* nul-term */
  1198. for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) {
  1199. if ( ludp->lud_host == NULL ) continue;
  1200. size += strlen(ludp->lud_host) + 1; /* host and space */
  1201. if (strchr(ludp->lud_host, ':')) /* will add [ ] below */
  1202. size += 2;
  1203. if (ludp->lud_port != 0)
  1204. size += sprintf(buf, ":%d", ludp->lud_port);
  1205. }
  1206. s = LDAP_MALLOC(size);
  1207. if (s == NULL)
  1208. return NULL;
  1209. p = s;
  1210. for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) {
  1211. if ( ludp->lud_host == NULL ) continue;
  1212. if (strchr(ludp->lud_host, ':')) {
  1213. p += sprintf(p, "[%s]", ludp->lud_host);
  1214. } else {
  1215. strcpy(p, ludp->lud_host);
  1216. p += strlen(ludp->lud_host);
  1217. }
  1218. if (ludp->lud_port != 0)
  1219. p += sprintf(p, ":%d", ludp->lud_port);
  1220. *p++ = ' ';
  1221. }
  1222. if (p != s)
  1223. p--; /* nuke that extra space */
  1224. *p = '\0';
  1225. return s;
  1226. }
  1227. char *
  1228. ldap_url_list2urls(
  1229. LDAPURLDesc *ludlist )
  1230. {
  1231. LDAPURLDesc *ludp;
  1232. int size, sofar;
  1233. char *s;
  1234. if ( ludlist == NULL ) {
  1235. return NULL;
  1236. }
  1237. /* figure out how big the string is */
  1238. for ( size = 0, ludp = ludlist; ludp != NULL; ludp = ludp->lud_next ) {
  1239. int len = desc2str_len( ludp );
  1240. if ( len < 0 ) {
  1241. return NULL;
  1242. }
  1243. size += len + 1;
  1244. }
  1245. s = LDAP_MALLOC( size );
  1246. if ( s == NULL ) {
  1247. return NULL;
  1248. }
  1249. for ( sofar = 0, ludp = ludlist; ludp != NULL; ludp = ludp->lud_next ) {
  1250. int len;
  1251. len = desc2str( ludp, &s[sofar], size );
  1252. if ( len < 0 ) {
  1253. LDAP_FREE( s );
  1254. return NULL;
  1255. }
  1256. sofar += len;
  1257. size -= len;
  1258. s[sofar++] = ' ';
  1259. size--;
  1260. assert( size >= 0 );
  1261. }
  1262. s[sofar - 1] = '\0';
  1263. return s;
  1264. }
  1265. void
  1266. ldap_free_urllist( LDAPURLDesc *ludlist )
  1267. {
  1268. LDAPURLDesc *ludp, *next;
  1269. for (ludp = ludlist; ludp != NULL; ludp = next) {
  1270. next = ludp->lud_next;
  1271. ldap_free_urldesc(ludp);
  1272. }
  1273. }
  1274. void
  1275. ldap_free_urldesc( LDAPURLDesc *ludp )
  1276. {
  1277. if ( ludp == NULL ) {
  1278. return;
  1279. }
  1280. if ( ludp->lud_scheme != NULL ) {
  1281. LDAP_FREE( ludp->lud_scheme );
  1282. }
  1283. if ( ludp->lud_host != NULL ) {
  1284. LDAP_FREE( ludp->lud_host );
  1285. }
  1286. if ( ludp->lud_dn != NULL ) {
  1287. LDAP_FREE( ludp->lud_dn );
  1288. }
  1289. if ( ludp->lud_filter != NULL ) {
  1290. LDAP_FREE( ludp->lud_filter);
  1291. }
  1292. if ( ludp->lud_attrs != NULL ) {
  1293. LDAP_VFREE( ludp->lud_attrs );
  1294. }
  1295. if ( ludp->lud_exts != NULL ) {
  1296. LDAP_VFREE( ludp->lud_exts );
  1297. }
  1298. LDAP_FREE( ludp );
  1299. }
  1300. static int
  1301. ldap_int_is_hexpair( char *s )
  1302. {
  1303. int i;
  1304. for ( i = 0; i < 2; i++ ) {
  1305. if ( s[i] >= '0' && s[i] <= '9' ) {
  1306. continue;
  1307. }
  1308. if ( s[i] >= 'A' && s[i] <= 'F' ) {
  1309. continue;
  1310. }
  1311. if ( s[i] >= 'a' && s[i] <= 'f' ) {
  1312. continue;
  1313. }
  1314. return 0;
  1315. }
  1316. return 1;
  1317. }
  1318. static int
  1319. ldap_int_unhex( int c )
  1320. {
  1321. return( c >= '0' && c <= '9' ? c - '0'
  1322. : c >= 'A' && c <= 'F' ? c - 'A' + 10
  1323. : c - 'a' + 10 );
  1324. }
  1325. void
  1326. ldap_pvt_hex_unescape( char *s )
  1327. {
  1328. /*
  1329. * Remove URL hex escapes from s... done in place. The basic concept for
  1330. * this routine is borrowed from the WWW library HTUnEscape() routine.
  1331. */
  1332. char *p,
  1333. *save_s = s;
  1334. for ( p = s; *s != '\0'; ++s ) {
  1335. if ( *s == '%' ) {
  1336. /*
  1337. * FIXME: what if '%' is followed
  1338. * by non-hexpair chars?
  1339. */
  1340. if ( !ldap_int_is_hexpair( s + 1 ) ) {
  1341. p = save_s;
  1342. break;
  1343. }
  1344. if ( *++s == '\0' ) {
  1345. break;
  1346. }
  1347. *p = ldap_int_unhex( *s ) << 4;
  1348. if ( *++s == '\0' ) {
  1349. break;
  1350. }
  1351. *p++ += ldap_int_unhex( *s );
  1352. } else {
  1353. *p++ = *s;
  1354. }
  1355. }
  1356. *p = '\0';
  1357. }