url.c 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657
  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-2024 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. if ( ! *url ) {
  701. LDAP_FREE( url );
  702. return LDAP_URL_ERR_BADENCLOSURE;
  703. }
  704. p = &url[strlen(url)-1];
  705. if( *p != '>' ) {
  706. LDAP_FREE( url );
  707. return LDAP_URL_ERR_BADENCLOSURE;
  708. }
  709. *p = '\0';
  710. }
  711. /* allocate return struct */
  712. ludp = (LDAPURLDesc *)LDAP_CALLOC( 1, sizeof( LDAPURLDesc ));
  713. if ( ludp == NULL ) {
  714. LDAP_FREE( url );
  715. return LDAP_URL_ERR_MEM;
  716. }
  717. ludp->lud_next = NULL;
  718. ludp->lud_host = NULL;
  719. ludp->lud_port = 0;
  720. ludp->lud_dn = NULL;
  721. ludp->lud_attrs = NULL;
  722. ludp->lud_scope = ( flags & LDAP_PVT_URL_PARSE_NODEF_SCOPE ) ? LDAP_SCOPE_BASE : LDAP_SCOPE_DEFAULT;
  723. ludp->lud_filter = NULL;
  724. ludp->lud_exts = NULL;
  725. ludp->lud_scheme = LDAP_STRDUP( scheme );
  726. if ( ludp->lud_scheme == NULL ) {
  727. LDAP_FREE( url );
  728. ldap_free_urldesc( ludp );
  729. return LDAP_URL_ERR_MEM;
  730. }
  731. /* scan forward for '/' that marks end of hostport and begin. of dn */
  732. p = strchr( url, '/' );
  733. q = NULL;
  734. if( p != NULL ) {
  735. /* terminate hostport; point to start of dn */
  736. *p++ = '\0';
  737. } else {
  738. /* check for Novell kludge, see below */
  739. p = strchr( url, '?' );
  740. if ( p ) {
  741. *p++ = '\0';
  742. q = p;
  743. p = NULL;
  744. }
  745. }
  746. if ( proto != LDAP_PROTO_IPC ) {
  747. /* IPv6 syntax with [ip address]:port */
  748. if ( *url == '[' ) {
  749. r = strchr( url, ']' );
  750. if ( r == NULL ) {
  751. LDAP_FREE( url );
  752. ldap_free_urldesc( ludp );
  753. return LDAP_URL_ERR_BADURL;
  754. }
  755. *r++ = '\0';
  756. q = strchr( r, ':' );
  757. if ( q && q != r ) {
  758. LDAP_FREE( url );
  759. ldap_free_urldesc( ludp );
  760. return LDAP_URL_ERR_BADURL;
  761. }
  762. is_v6 = 1;
  763. } else {
  764. q = strchr( url, ':' );
  765. }
  766. if ( q != NULL ) {
  767. char *next;
  768. *q++ = '\0';
  769. ldap_pvt_hex_unescape( q );
  770. if( *q == '\0' ) {
  771. LDAP_FREE( url );
  772. ldap_free_urldesc( ludp );
  773. return LDAP_URL_ERR_BADURL;
  774. }
  775. ludp->lud_port = strtol( q, &next, 10 );
  776. if ( next == q || next[0] != '\0' ) {
  777. LDAP_FREE( url );
  778. ldap_free_urldesc( ludp );
  779. return LDAP_URL_ERR_BADURL;
  780. }
  781. /* check for Novell kludge */
  782. if ( !p ) {
  783. if ( *next != '\0' ) {
  784. q = &next[1];
  785. } else {
  786. q = NULL;
  787. }
  788. }
  789. }
  790. if ( ( flags & LDAP_PVT_URL_PARSE_DEF_PORT ) && ludp->lud_port == 0 ) {
  791. if ( strcmp( ludp->lud_scheme, "ldaps" ) == 0 ) {
  792. ludp->lud_port = LDAPS_PORT;
  793. } else {
  794. ludp->lud_port = LDAP_PORT;
  795. }
  796. }
  797. }
  798. ldap_pvt_hex_unescape( url );
  799. /* If [ip address]:port syntax, url is [ip and we skip the [ */
  800. ludp->lud_host = LDAP_STRDUP( url + is_v6 );
  801. if( ludp->lud_host == NULL ) {
  802. LDAP_FREE( url );
  803. ldap_free_urldesc( ludp );
  804. return LDAP_URL_ERR_MEM;
  805. }
  806. if ( ( flags & LDAP_PVT_URL_PARSE_NOEMPTY_HOST )
  807. && ludp->lud_host != NULL
  808. && *ludp->lud_host == '\0' )
  809. {
  810. LDAP_FREE( ludp->lud_host );
  811. ludp->lud_host = NULL;
  812. }
  813. /*
  814. * Kludge. ldap://111.222.333.444:389??cn=abc,o=company
  815. *
  816. * On early Novell releases, search references/referrals were returned
  817. * in this format, i.e., the dn was kind of in the scope position,
  818. * but the required slash is missing. The whole thing is illegal syntax,
  819. * but we need to account for it. Fortunately it can't be confused with
  820. * anything real.
  821. */
  822. if( (p == NULL) && (q != NULL) && (*q == '?') ) {
  823. /* ? immediately followed by question */
  824. q++;
  825. if( *q != '\0' ) {
  826. /* parse dn part */
  827. ldap_pvt_hex_unescape( q );
  828. ludp->lud_dn = LDAP_STRDUP( q );
  829. } else if ( !( flags & LDAP_PVT_URL_PARSE_NOEMPTY_DN ) ) {
  830. ludp->lud_dn = LDAP_STRDUP( "" );
  831. } else {
  832. check_dn = 0;
  833. }
  834. if ( check_dn && ludp->lud_dn == NULL ) {
  835. LDAP_FREE( url );
  836. ldap_free_urldesc( ludp );
  837. return LDAP_URL_ERR_MEM;
  838. }
  839. }
  840. if( p == NULL ) {
  841. LDAP_FREE( url );
  842. *ludpp = ludp;
  843. return LDAP_URL_SUCCESS;
  844. }
  845. /* scan forward for '?' that may marks end of dn */
  846. q = strchr( p, '?' );
  847. if( q != NULL ) {
  848. /* terminate dn part */
  849. *q++ = '\0';
  850. }
  851. if( *p != '\0' ) {
  852. /* parse dn part */
  853. ldap_pvt_hex_unescape( p );
  854. ludp->lud_dn = LDAP_STRDUP( p );
  855. } else if ( !( flags & LDAP_PVT_URL_PARSE_NOEMPTY_DN ) ) {
  856. ludp->lud_dn = LDAP_STRDUP( "" );
  857. } else {
  858. check_dn = 0;
  859. }
  860. if( check_dn && ludp->lud_dn == NULL ) {
  861. LDAP_FREE( url );
  862. ldap_free_urldesc( ludp );
  863. return LDAP_URL_ERR_MEM;
  864. }
  865. if( q == NULL ) {
  866. /* no more */
  867. LDAP_FREE( url );
  868. *ludpp = ludp;
  869. return LDAP_URL_SUCCESS;
  870. }
  871. /* scan forward for '?' that may marks end of attributes */
  872. p = q;
  873. q = strchr( p, '?' );
  874. if( q != NULL ) {
  875. /* terminate attributes part */
  876. *q++ = '\0';
  877. }
  878. if( *p != '\0' ) {
  879. /* parse attributes */
  880. ldap_pvt_hex_unescape( p );
  881. ludp->lud_attrs = ldap_str2charray( p, "," );
  882. if( ludp->lud_attrs == NULL ) {
  883. LDAP_FREE( url );
  884. ldap_free_urldesc( ludp );
  885. return LDAP_URL_ERR_BADATTRS;
  886. }
  887. }
  888. if ( q == NULL ) {
  889. /* no more */
  890. LDAP_FREE( url );
  891. *ludpp = ludp;
  892. return LDAP_URL_SUCCESS;
  893. }
  894. /* scan forward for '?' that may marks end of scope */
  895. p = q;
  896. q = strchr( p, '?' );
  897. if( q != NULL ) {
  898. /* terminate the scope part */
  899. *q++ = '\0';
  900. }
  901. if( *p != '\0' ) {
  902. /* parse the scope */
  903. ldap_pvt_hex_unescape( p );
  904. ludp->lud_scope = ldap_pvt_str2scope( p );
  905. if( ludp->lud_scope == -1 ) {
  906. LDAP_FREE( url );
  907. ldap_free_urldesc( ludp );
  908. return LDAP_URL_ERR_BADSCOPE;
  909. }
  910. }
  911. if ( q == NULL ) {
  912. /* no more */
  913. LDAP_FREE( url );
  914. *ludpp = ludp;
  915. return LDAP_URL_SUCCESS;
  916. }
  917. /* scan forward for '?' that may marks end of filter */
  918. p = q;
  919. q = strchr( p, '?' );
  920. if( q != NULL ) {
  921. /* terminate the filter part */
  922. *q++ = '\0';
  923. }
  924. if( *p != '\0' ) {
  925. /* parse the filter */
  926. ldap_pvt_hex_unescape( p );
  927. if( ! *p ) {
  928. /* missing filter */
  929. LDAP_FREE( url );
  930. ldap_free_urldesc( ludp );
  931. return LDAP_URL_ERR_BADFILTER;
  932. }
  933. ludp->lud_filter = LDAP_STRDUP( p );
  934. if( ludp->lud_filter == NULL ) {
  935. LDAP_FREE( url );
  936. ldap_free_urldesc( ludp );
  937. return LDAP_URL_ERR_MEM;
  938. }
  939. }
  940. if ( q == NULL ) {
  941. /* no more */
  942. LDAP_FREE( url );
  943. *ludpp = ludp;
  944. return LDAP_URL_SUCCESS;
  945. }
  946. /* scan forward for '?' that may marks end of extensions */
  947. p = q;
  948. q = strchr( p, '?' );
  949. if( q != NULL ) {
  950. /* extra '?' */
  951. LDAP_FREE( url );
  952. ldap_free_urldesc( ludp );
  953. return LDAP_URL_ERR_BADURL;
  954. }
  955. /* parse the extensions */
  956. ludp->lud_exts = ldap_str2charray( p, "," );
  957. if( ludp->lud_exts == NULL ) {
  958. LDAP_FREE( url );
  959. ldap_free_urldesc( ludp );
  960. return LDAP_URL_ERR_BADEXTS;
  961. }
  962. for( i=0; ludp->lud_exts[i] != NULL; i++ ) {
  963. ldap_pvt_hex_unescape( ludp->lud_exts[i] );
  964. if( *ludp->lud_exts[i] == '!' ) {
  965. /* count the number of critical extensions */
  966. ludp->lud_crit_exts++;
  967. }
  968. }
  969. if( i == 0 ) {
  970. /* must have 1 or more */
  971. LDAP_FREE( url );
  972. ldap_free_urldesc( ludp );
  973. return LDAP_URL_ERR_BADEXTS;
  974. }
  975. /* no more */
  976. *ludpp = ludp;
  977. LDAP_FREE( url );
  978. return LDAP_URL_SUCCESS;
  979. }
  980. int
  981. ldap_url_parse( LDAP_CONST char *url_in, LDAPURLDesc **ludpp )
  982. {
  983. return ldap_url_parse_ext( url_in, ludpp, LDAP_PVT_URL_PARSE_HISTORIC );
  984. }
  985. LDAPURLDesc *
  986. ldap_url_dup ( LDAPURLDesc *ludp )
  987. {
  988. LDAPURLDesc *dest;
  989. if ( ludp == NULL ) {
  990. return NULL;
  991. }
  992. dest = LDAP_MALLOC( sizeof(LDAPURLDesc) );
  993. if (dest == NULL)
  994. return NULL;
  995. *dest = *ludp;
  996. dest->lud_scheme = NULL;
  997. dest->lud_host = NULL;
  998. dest->lud_dn = NULL;
  999. dest->lud_filter = NULL;
  1000. dest->lud_attrs = NULL;
  1001. dest->lud_exts = NULL;
  1002. dest->lud_next = NULL;
  1003. if ( ludp->lud_scheme != NULL ) {
  1004. dest->lud_scheme = LDAP_STRDUP( ludp->lud_scheme );
  1005. if (dest->lud_scheme == NULL) {
  1006. ldap_free_urldesc(dest);
  1007. return NULL;
  1008. }
  1009. }
  1010. if ( ludp->lud_host != NULL ) {
  1011. dest->lud_host = LDAP_STRDUP( ludp->lud_host );
  1012. if (dest->lud_host == NULL) {
  1013. ldap_free_urldesc(dest);
  1014. return NULL;
  1015. }
  1016. }
  1017. if ( ludp->lud_dn != NULL ) {
  1018. dest->lud_dn = LDAP_STRDUP( ludp->lud_dn );
  1019. if (dest->lud_dn == NULL) {
  1020. ldap_free_urldesc(dest);
  1021. return NULL;
  1022. }
  1023. }
  1024. if ( ludp->lud_filter != NULL ) {
  1025. dest->lud_filter = LDAP_STRDUP( ludp->lud_filter );
  1026. if (dest->lud_filter == NULL) {
  1027. ldap_free_urldesc(dest);
  1028. return NULL;
  1029. }
  1030. }
  1031. if ( ludp->lud_attrs != NULL ) {
  1032. dest->lud_attrs = ldap_charray_dup( ludp->lud_attrs );
  1033. if (dest->lud_attrs == NULL) {
  1034. ldap_free_urldesc(dest);
  1035. return NULL;
  1036. }
  1037. }
  1038. if ( ludp->lud_exts != NULL ) {
  1039. dest->lud_exts = ldap_charray_dup( ludp->lud_exts );
  1040. if (dest->lud_exts == NULL) {
  1041. ldap_free_urldesc(dest);
  1042. return NULL;
  1043. }
  1044. }
  1045. return dest;
  1046. }
  1047. LDAPURLDesc *
  1048. ldap_url_duplist (LDAPURLDesc *ludlist)
  1049. {
  1050. LDAPURLDesc *dest, *tail, *ludp, *newludp;
  1051. dest = NULL;
  1052. tail = NULL;
  1053. for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) {
  1054. newludp = ldap_url_dup(ludp);
  1055. if (newludp == NULL) {
  1056. ldap_free_urllist(dest);
  1057. return NULL;
  1058. }
  1059. if (tail == NULL)
  1060. dest = newludp;
  1061. else
  1062. tail->lud_next = newludp;
  1063. tail = newludp;
  1064. }
  1065. return dest;
  1066. }
  1067. static int
  1068. ldap_url_parselist_int (LDAPURLDesc **ludlist, const char *url, const char *sep, unsigned flags )
  1069. {
  1070. int i, rc;
  1071. LDAPURLDesc *ludp;
  1072. char **urls;
  1073. assert( ludlist != NULL );
  1074. assert( url != NULL );
  1075. *ludlist = NULL;
  1076. if ( sep == NULL ) {
  1077. sep = ", ";
  1078. }
  1079. urls = ldap_str2charray( url, sep );
  1080. if (urls == NULL)
  1081. return LDAP_URL_ERR_MEM;
  1082. /* count the URLs... */
  1083. for (i = 0; urls[i] != NULL; i++) ;
  1084. /* ...and put them in the "stack" backward */
  1085. while (--i >= 0) {
  1086. rc = ldap_url_parse_ext( urls[i], &ludp, flags );
  1087. if ( rc != 0 ) {
  1088. ldap_charray_free( urls );
  1089. ldap_free_urllist( *ludlist );
  1090. *ludlist = NULL;
  1091. return rc;
  1092. }
  1093. ludp->lud_next = *ludlist;
  1094. *ludlist = ludp;
  1095. }
  1096. ldap_charray_free( urls );
  1097. return LDAP_URL_SUCCESS;
  1098. }
  1099. int
  1100. ldap_url_parselist (LDAPURLDesc **ludlist, const char *url )
  1101. {
  1102. return ldap_url_parselist_int( ludlist, url, ", ", LDAP_PVT_URL_PARSE_HISTORIC );
  1103. }
  1104. int
  1105. ldap_url_parselist_ext (LDAPURLDesc **ludlist, const char *url, const char *sep, unsigned flags )
  1106. {
  1107. return ldap_url_parselist_int( ludlist, url, sep, flags );
  1108. }
  1109. int
  1110. ldap_url_parsehosts(
  1111. LDAPURLDesc **ludlist,
  1112. const char *hosts,
  1113. int port )
  1114. {
  1115. int i;
  1116. LDAPURLDesc *ludp;
  1117. char **specs, *p;
  1118. assert( ludlist != NULL );
  1119. assert( hosts != NULL );
  1120. *ludlist = NULL;
  1121. specs = ldap_str2charray(hosts, ", ");
  1122. if (specs == NULL)
  1123. return LDAP_NO_MEMORY;
  1124. /* count the URLs... */
  1125. for (i = 0; specs[i] != NULL; i++) /* EMPTY */;
  1126. /* ...and put them in the "stack" backward */
  1127. while (--i >= 0) {
  1128. ludp = LDAP_CALLOC( 1, sizeof(LDAPURLDesc) );
  1129. if (ludp == NULL) {
  1130. ldap_charray_free(specs);
  1131. ldap_free_urllist(*ludlist);
  1132. *ludlist = NULL;
  1133. return LDAP_NO_MEMORY;
  1134. }
  1135. ludp->lud_port = port;
  1136. ludp->lud_host = specs[i];
  1137. p = strchr(ludp->lud_host, ':');
  1138. if (p != NULL) {
  1139. /* more than one :, IPv6 address */
  1140. if ( strchr(p+1, ':') != NULL ) {
  1141. /* allow [address] and [address]:port */
  1142. if ( *ludp->lud_host == '[' ) {
  1143. p = strchr( ludp->lud_host+1, ']' );
  1144. if ( p == NULL ) {
  1145. LDAP_FREE(ludp);
  1146. ldap_charray_free(specs);
  1147. return LDAP_PARAM_ERROR;
  1148. }
  1149. /* Truncate trailing ']' and shift hostname down 1 char */
  1150. *p = '\0';
  1151. AC_MEMCPY( ludp->lud_host, ludp->lud_host+1, p - ludp->lud_host );
  1152. p++;
  1153. if ( *p != ':' ) {
  1154. if ( *p != '\0' ) {
  1155. LDAP_FREE(ludp);
  1156. ldap_charray_free(specs);
  1157. return LDAP_PARAM_ERROR;
  1158. }
  1159. p = NULL;
  1160. }
  1161. } else {
  1162. p = NULL;
  1163. }
  1164. }
  1165. if (p != NULL) {
  1166. char *next;
  1167. *p++ = 0;
  1168. ldap_pvt_hex_unescape(p);
  1169. ludp->lud_port = strtol( p, &next, 10 );
  1170. if ( next == p || next[0] != '\0' ) {
  1171. LDAP_FREE(ludp);
  1172. ldap_charray_free(specs);
  1173. return LDAP_PARAM_ERROR;
  1174. }
  1175. }
  1176. }
  1177. ludp->lud_scheme = LDAP_STRDUP("ldap");
  1178. if ( ludp->lud_scheme == NULL ) {
  1179. LDAP_FREE(ludp);
  1180. ldap_charray_free(specs);
  1181. return LDAP_NO_MEMORY;
  1182. }
  1183. specs[i] = NULL;
  1184. ldap_pvt_hex_unescape(ludp->lud_host);
  1185. ludp->lud_next = *ludlist;
  1186. *ludlist = ludp;
  1187. }
  1188. /* this should be an array of NULLs now */
  1189. ldap_charray_free(specs);
  1190. return LDAP_SUCCESS;
  1191. }
  1192. char *
  1193. ldap_url_list2hosts (LDAPURLDesc *ludlist)
  1194. {
  1195. LDAPURLDesc *ludp;
  1196. int size;
  1197. char *s, *p, buf[32]; /* big enough to hold a long decimal # (overkill) */
  1198. if (ludlist == NULL)
  1199. return NULL;
  1200. /* figure out how big the string is */
  1201. size = 1; /* nul-term */
  1202. for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) {
  1203. if ( ludp->lud_host == NULL ) continue;
  1204. size += strlen(ludp->lud_host) + 1; /* host and space */
  1205. if (strchr(ludp->lud_host, ':')) /* will add [ ] below */
  1206. size += 2;
  1207. if (ludp->lud_port != 0)
  1208. size += sprintf(buf, ":%d", ludp->lud_port);
  1209. }
  1210. s = LDAP_MALLOC(size);
  1211. if (s == NULL)
  1212. return NULL;
  1213. p = s;
  1214. for (ludp = ludlist; ludp != NULL; ludp = ludp->lud_next) {
  1215. if ( ludp->lud_host == NULL ) continue;
  1216. if (strchr(ludp->lud_host, ':')) {
  1217. p += sprintf(p, "[%s]", ludp->lud_host);
  1218. } else {
  1219. strcpy(p, ludp->lud_host);
  1220. p += strlen(ludp->lud_host);
  1221. }
  1222. if (ludp->lud_port != 0)
  1223. p += sprintf(p, ":%d", ludp->lud_port);
  1224. *p++ = ' ';
  1225. }
  1226. if (p != s)
  1227. p--; /* nuke that extra space */
  1228. *p = '\0';
  1229. return s;
  1230. }
  1231. char *
  1232. ldap_url_list2urls(
  1233. LDAPURLDesc *ludlist )
  1234. {
  1235. LDAPURLDesc *ludp;
  1236. int size, sofar;
  1237. char *s;
  1238. if ( ludlist == NULL ) {
  1239. return NULL;
  1240. }
  1241. /* figure out how big the string is */
  1242. for ( size = 0, ludp = ludlist; ludp != NULL; ludp = ludp->lud_next ) {
  1243. int len = desc2str_len( ludp );
  1244. if ( len < 0 ) {
  1245. return NULL;
  1246. }
  1247. size += len + 1;
  1248. }
  1249. s = LDAP_MALLOC( size );
  1250. if ( s == NULL ) {
  1251. return NULL;
  1252. }
  1253. for ( sofar = 0, ludp = ludlist; ludp != NULL; ludp = ludp->lud_next ) {
  1254. int len;
  1255. len = desc2str( ludp, &s[sofar], size );
  1256. if ( len < 0 ) {
  1257. LDAP_FREE( s );
  1258. return NULL;
  1259. }
  1260. sofar += len;
  1261. size -= len;
  1262. s[sofar++] = ' ';
  1263. size--;
  1264. assert( size >= 0 );
  1265. }
  1266. s[sofar - 1] = '\0';
  1267. return s;
  1268. }
  1269. void
  1270. ldap_free_urllist( LDAPURLDesc *ludlist )
  1271. {
  1272. LDAPURLDesc *ludp, *next;
  1273. for (ludp = ludlist; ludp != NULL; ludp = next) {
  1274. next = ludp->lud_next;
  1275. ldap_free_urldesc(ludp);
  1276. }
  1277. }
  1278. void
  1279. ldap_free_urldesc( LDAPURLDesc *ludp )
  1280. {
  1281. if ( ludp == NULL ) {
  1282. return;
  1283. }
  1284. if ( ludp->lud_scheme != NULL ) {
  1285. LDAP_FREE( ludp->lud_scheme );
  1286. }
  1287. if ( ludp->lud_host != NULL ) {
  1288. LDAP_FREE( ludp->lud_host );
  1289. }
  1290. if ( ludp->lud_dn != NULL ) {
  1291. LDAP_FREE( ludp->lud_dn );
  1292. }
  1293. if ( ludp->lud_filter != NULL ) {
  1294. LDAP_FREE( ludp->lud_filter);
  1295. }
  1296. if ( ludp->lud_attrs != NULL ) {
  1297. LDAP_VFREE( ludp->lud_attrs );
  1298. }
  1299. if ( ludp->lud_exts != NULL ) {
  1300. LDAP_VFREE( ludp->lud_exts );
  1301. }
  1302. LDAP_FREE( ludp );
  1303. }
  1304. static int
  1305. ldap_int_is_hexpair( char *s )
  1306. {
  1307. int i;
  1308. for ( i = 0; i < 2; i++ ) {
  1309. if ( s[i] >= '0' && s[i] <= '9' ) {
  1310. continue;
  1311. }
  1312. if ( s[i] >= 'A' && s[i] <= 'F' ) {
  1313. continue;
  1314. }
  1315. if ( s[i] >= 'a' && s[i] <= 'f' ) {
  1316. continue;
  1317. }
  1318. return 0;
  1319. }
  1320. return 1;
  1321. }
  1322. static int
  1323. ldap_int_unhex( int c )
  1324. {
  1325. return( c >= '0' && c <= '9' ? c - '0'
  1326. : c >= 'A' && c <= 'F' ? c - 'A' + 10
  1327. : c - 'a' + 10 );
  1328. }
  1329. void
  1330. ldap_pvt_hex_unescape( char *s )
  1331. {
  1332. /*
  1333. * Remove URL hex escapes from s... done in place. The basic concept for
  1334. * this routine is borrowed from the WWW library HTUnEscape() routine.
  1335. */
  1336. char *p,
  1337. *save_s = s;
  1338. for ( p = s; *s != '\0'; ++s ) {
  1339. if ( *s == '%' ) {
  1340. /*
  1341. * FIXME: what if '%' is followed
  1342. * by non-hexpair chars?
  1343. */
  1344. if ( !ldap_int_is_hexpair( s + 1 ) ) {
  1345. p = save_s;
  1346. break;
  1347. }
  1348. if ( *++s == '\0' ) {
  1349. break;
  1350. }
  1351. *p = ldap_int_unhex( *s ) << 4;
  1352. if ( *++s == '\0' ) {
  1353. break;
  1354. }
  1355. *p++ += ldap_int_unhex( *s );
  1356. } else {
  1357. *p++ = *s;
  1358. }
  1359. }
  1360. *p = '\0';
  1361. }