sasl.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867
  1. /* $OpenLDAP$ */
  2. /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  3. *
  4. * Copyright 1998-2022 The OpenLDAP Foundation.
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted only as authorized by the OpenLDAP
  9. * Public License.
  10. *
  11. * A copy of this license is available in the file LICENSE in the
  12. * top-level directory of the distribution or, alternatively, at
  13. * <http://www.OpenLDAP.org/license.html>.
  14. */
  15. /*
  16. * BindRequest ::= SEQUENCE {
  17. * version INTEGER,
  18. * name DistinguishedName, -- who
  19. * authentication CHOICE {
  20. * simple [0] OCTET STRING -- passwd
  21. * krbv42ldap [1] OCTET STRING -- OBSOLETE
  22. * krbv42dsa [2] OCTET STRING -- OBSOLETE
  23. * sasl [3] SaslCredentials -- LDAPv3
  24. * }
  25. * }
  26. *
  27. * BindResponse ::= SEQUENCE {
  28. * COMPONENTS OF LDAPResult,
  29. * serverSaslCreds OCTET STRING OPTIONAL -- LDAPv3
  30. * }
  31. *
  32. */
  33. #include "portable.h"
  34. #include <stdio.h>
  35. #include <ac/socket.h>
  36. #include <ac/stdlib.h>
  37. #include <ac/string.h>
  38. #include <ac/time.h>
  39. #include <ac/errno.h>
  40. #include "ldap-int.h"
  41. BerElement *
  42. ldap_build_bind_req(
  43. LDAP *ld,
  44. LDAP_CONST char *dn,
  45. LDAP_CONST char *mechanism,
  46. struct berval *cred,
  47. LDAPControl **sctrls,
  48. LDAPControl **cctrls,
  49. ber_int_t *msgidp )
  50. {
  51. BerElement *ber;
  52. int rc;
  53. if( mechanism == LDAP_SASL_SIMPLE ) {
  54. if( dn == NULL && cred != NULL && cred->bv_len ) {
  55. /* use default binddn */
  56. dn = ld->ld_defbinddn;
  57. }
  58. } else if( ld->ld_version < LDAP_VERSION3 ) {
  59. ld->ld_errno = LDAP_NOT_SUPPORTED;
  60. return( NULL );
  61. }
  62. if ( dn == NULL ) {
  63. dn = "";
  64. }
  65. /* create a message to send */
  66. if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
  67. return( NULL );
  68. }
  69. LDAP_NEXT_MSGID( ld, *msgidp );
  70. if( mechanism == LDAP_SASL_SIMPLE ) {
  71. /* simple bind */
  72. rc = ber_printf( ber, "{it{istON}" /*}*/,
  73. *msgidp, LDAP_REQ_BIND,
  74. ld->ld_version, dn, LDAP_AUTH_SIMPLE,
  75. cred );
  76. } else if ( cred == NULL || cred->bv_val == NULL ) {
  77. /* SASL bind w/o credentials */
  78. rc = ber_printf( ber, "{it{ist{sN}N}" /*}*/,
  79. *msgidp, LDAP_REQ_BIND,
  80. ld->ld_version, dn, LDAP_AUTH_SASL,
  81. mechanism );
  82. } else {
  83. /* SASL bind w/ credentials */
  84. rc = ber_printf( ber, "{it{ist{sON}N}" /*}*/,
  85. *msgidp, LDAP_REQ_BIND,
  86. ld->ld_version, dn, LDAP_AUTH_SASL,
  87. mechanism, cred );
  88. }
  89. if( rc == -1 ) {
  90. ld->ld_errno = LDAP_ENCODING_ERROR;
  91. ber_free( ber, 1 );
  92. return( NULL );
  93. }
  94. /* Put Server Controls */
  95. if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
  96. ber_free( ber, 1 );
  97. return( NULL );
  98. }
  99. if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
  100. ld->ld_errno = LDAP_ENCODING_ERROR;
  101. ber_free( ber, 1 );
  102. return( NULL );
  103. }
  104. return( ber );
  105. }
  106. /*
  107. * ldap_sasl_bind - bind to the ldap server (and X.500).
  108. * The dn (usually NULL), mechanism, and credentials are provided.
  109. * The message id of the request initiated is provided upon successful
  110. * (LDAP_SUCCESS) return.
  111. *
  112. * Example:
  113. * ldap_sasl_bind( ld, NULL, "mechanism",
  114. * cred, NULL, NULL, &msgid )
  115. */
  116. int
  117. ldap_sasl_bind(
  118. LDAP *ld,
  119. LDAP_CONST char *dn,
  120. LDAP_CONST char *mechanism,
  121. struct berval *cred,
  122. LDAPControl **sctrls,
  123. LDAPControl **cctrls,
  124. int *msgidp )
  125. {
  126. BerElement *ber;
  127. int rc;
  128. ber_int_t id;
  129. Debug0( LDAP_DEBUG_TRACE, "ldap_sasl_bind\n" );
  130. assert( ld != NULL );
  131. assert( LDAP_VALID( ld ) );
  132. assert( msgidp != NULL );
  133. /* check client controls */
  134. rc = ldap_int_client_controls( ld, cctrls );
  135. if( rc != LDAP_SUCCESS ) return rc;
  136. ber = ldap_build_bind_req( ld, dn, mechanism, cred, sctrls, cctrls, &id );
  137. if( !ber )
  138. return ld->ld_errno;
  139. /* send the message */
  140. *msgidp = ldap_send_initial_request( ld, LDAP_REQ_BIND, dn, ber, id );
  141. if(*msgidp < 0)
  142. return ld->ld_errno;
  143. return LDAP_SUCCESS;
  144. }
  145. int
  146. ldap_sasl_bind_s(
  147. LDAP *ld,
  148. LDAP_CONST char *dn,
  149. LDAP_CONST char *mechanism,
  150. struct berval *cred,
  151. LDAPControl **sctrls,
  152. LDAPControl **cctrls,
  153. struct berval **servercredp )
  154. {
  155. int rc, msgid;
  156. LDAPMessage *result;
  157. struct berval *scredp = NULL;
  158. Debug0( LDAP_DEBUG_TRACE, "ldap_sasl_bind_s\n" );
  159. /* do a quick !LDAPv3 check... ldap_sasl_bind will do the rest. */
  160. if( servercredp != NULL ) {
  161. if (ld->ld_version < LDAP_VERSION3) {
  162. ld->ld_errno = LDAP_NOT_SUPPORTED;
  163. return ld->ld_errno;
  164. }
  165. *servercredp = NULL;
  166. }
  167. rc = ldap_sasl_bind( ld, dn, mechanism, cred, sctrls, cctrls, &msgid );
  168. if ( rc != LDAP_SUCCESS ) {
  169. return( rc );
  170. }
  171. #ifdef LDAP_CONNECTIONLESS
  172. if (LDAP_IS_UDP(ld)) {
  173. return( rc );
  174. }
  175. #endif
  176. if ( ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1 || !result ) {
  177. return( ld->ld_errno ); /* ldap_result sets ld_errno */
  178. }
  179. /* parse the results */
  180. scredp = NULL;
  181. if( servercredp != NULL ) {
  182. rc = ldap_parse_sasl_bind_result( ld, result, &scredp, 0 );
  183. }
  184. if ( rc != LDAP_SUCCESS ) {
  185. ldap_msgfree( result );
  186. return( rc );
  187. }
  188. rc = ldap_result2error( ld, result, 1 );
  189. if ( rc == LDAP_SUCCESS || rc == LDAP_SASL_BIND_IN_PROGRESS ) {
  190. if( servercredp != NULL ) {
  191. *servercredp = scredp;
  192. scredp = NULL;
  193. }
  194. }
  195. if ( scredp != NULL ) {
  196. ber_bvfree(scredp);
  197. }
  198. return rc;
  199. }
  200. /*
  201. * Parse BindResponse:
  202. *
  203. * BindResponse ::= [APPLICATION 1] SEQUENCE {
  204. * COMPONENTS OF LDAPResult,
  205. * serverSaslCreds [7] OCTET STRING OPTIONAL }
  206. *
  207. * LDAPResult ::= SEQUENCE {
  208. * resultCode ENUMERATED,
  209. * matchedDN LDAPDN,
  210. * errorMessage LDAPString,
  211. * referral [3] Referral OPTIONAL }
  212. */
  213. int
  214. ldap_parse_sasl_bind_result(
  215. LDAP *ld,
  216. LDAPMessage *res,
  217. struct berval **servercredp,
  218. int freeit )
  219. {
  220. ber_int_t errcode;
  221. struct berval* scred;
  222. ber_tag_t tag;
  223. BerElement *ber;
  224. Debug0( LDAP_DEBUG_TRACE, "ldap_parse_sasl_bind_result\n" );
  225. assert( ld != NULL );
  226. assert( LDAP_VALID( ld ) );
  227. assert( res != NULL );
  228. if( servercredp != NULL ) {
  229. if( ld->ld_version < LDAP_VERSION2 ) {
  230. return LDAP_NOT_SUPPORTED;
  231. }
  232. *servercredp = NULL;
  233. }
  234. if( res->lm_msgtype != LDAP_RES_BIND ) {
  235. ld->ld_errno = LDAP_PARAM_ERROR;
  236. return ld->ld_errno;
  237. }
  238. scred = NULL;
  239. if ( ld->ld_error ) {
  240. LDAP_FREE( ld->ld_error );
  241. ld->ld_error = NULL;
  242. }
  243. if ( ld->ld_matched ) {
  244. LDAP_FREE( ld->ld_matched );
  245. ld->ld_matched = NULL;
  246. }
  247. /* parse results */
  248. ber = ber_dup( res->lm_ber );
  249. if( ber == NULL ) {
  250. ld->ld_errno = LDAP_NO_MEMORY;
  251. return ld->ld_errno;
  252. }
  253. if ( ld->ld_version < LDAP_VERSION2 ) {
  254. tag = ber_scanf( ber, "{iA}",
  255. &errcode, &ld->ld_error );
  256. if( tag == LBER_ERROR ) {
  257. ber_free( ber, 0 );
  258. ld->ld_errno = LDAP_DECODING_ERROR;
  259. return ld->ld_errno;
  260. }
  261. } else {
  262. ber_len_t len;
  263. tag = ber_scanf( ber, "{eAA" /*}*/,
  264. &errcode, &ld->ld_matched, &ld->ld_error );
  265. if( tag == LBER_ERROR ) {
  266. ber_free( ber, 0 );
  267. ld->ld_errno = LDAP_DECODING_ERROR;
  268. return ld->ld_errno;
  269. }
  270. tag = ber_peek_tag(ber, &len);
  271. if( tag == LDAP_TAG_REFERRAL ) {
  272. /* skip 'em */
  273. if( ber_scanf( ber, "x" ) == LBER_ERROR ) {
  274. ber_free( ber, 0 );
  275. ld->ld_errno = LDAP_DECODING_ERROR;
  276. return ld->ld_errno;
  277. }
  278. tag = ber_peek_tag(ber, &len);
  279. }
  280. if( tag == LDAP_TAG_SASL_RES_CREDS ) {
  281. if( ber_scanf( ber, "O", &scred ) == LBER_ERROR ) {
  282. ber_free( ber, 0 );
  283. ld->ld_errno = LDAP_DECODING_ERROR;
  284. return ld->ld_errno;
  285. }
  286. }
  287. }
  288. ber_free( ber, 0 );
  289. if ( servercredp != NULL ) {
  290. *servercredp = scred;
  291. } else if ( scred != NULL ) {
  292. ber_bvfree( scred );
  293. }
  294. ld->ld_errno = errcode;
  295. if ( freeit ) {
  296. ldap_msgfree( res );
  297. }
  298. return( LDAP_SUCCESS );
  299. }
  300. int
  301. ldap_pvt_sasl_getmechs ( LDAP *ld, char **pmechlist )
  302. {
  303. /* we need to query the server for supported mechs anyway */
  304. LDAPMessage *res, *e;
  305. char *attrs[] = { "supportedSASLMechanisms", NULL };
  306. char **values, *mechlist;
  307. int rc;
  308. Debug0( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_getmech\n" );
  309. rc = ldap_search_s( ld, "", LDAP_SCOPE_BASE,
  310. NULL, attrs, 0, &res );
  311. if ( rc != LDAP_SUCCESS ) {
  312. return ld->ld_errno;
  313. }
  314. e = ldap_first_entry( ld, res );
  315. if ( e == NULL ) {
  316. ldap_msgfree( res );
  317. if ( ld->ld_errno == LDAP_SUCCESS ) {
  318. ld->ld_errno = LDAP_NO_SUCH_OBJECT;
  319. }
  320. return ld->ld_errno;
  321. }
  322. values = ldap_get_values( ld, e, "supportedSASLMechanisms" );
  323. if ( values == NULL ) {
  324. ldap_msgfree( res );
  325. ld->ld_errno = LDAP_NO_SUCH_ATTRIBUTE;
  326. return ld->ld_errno;
  327. }
  328. mechlist = ldap_charray2str( values, " " );
  329. if ( mechlist == NULL ) {
  330. LDAP_VFREE( values );
  331. ldap_msgfree( res );
  332. ld->ld_errno = LDAP_NO_MEMORY;
  333. return ld->ld_errno;
  334. }
  335. LDAP_VFREE( values );
  336. ldap_msgfree( res );
  337. *pmechlist = mechlist;
  338. return LDAP_SUCCESS;
  339. }
  340. /*
  341. * ldap_sasl_interactive_bind - interactive SASL authentication
  342. *
  343. * This routine uses interactive callbacks.
  344. *
  345. * LDAP_SUCCESS is returned upon success, the ldap error code
  346. * otherwise. LDAP_SASL_BIND_IN_PROGRESS is returned if further
  347. * calls are needed.
  348. */
  349. int
  350. ldap_sasl_interactive_bind(
  351. LDAP *ld,
  352. LDAP_CONST char *dn, /* usually NULL */
  353. LDAP_CONST char *mechs,
  354. LDAPControl **serverControls,
  355. LDAPControl **clientControls,
  356. unsigned flags,
  357. LDAP_SASL_INTERACT_PROC *interact,
  358. void *defaults,
  359. LDAPMessage *result,
  360. const char **rmech,
  361. int *msgid )
  362. {
  363. char *smechs = NULL;
  364. int rc;
  365. #ifdef LDAP_CONNECTIONLESS
  366. if( LDAP_IS_UDP(ld) ) {
  367. /* Just force it to simple bind, silly to make the user
  368. * ask all the time. No, we don't ever actually bind, but I'll
  369. * let the final bind handler take care of saving the cdn.
  370. */
  371. rc = ldap_simple_bind( ld, dn, NULL );
  372. rc = rc < 0 ? rc : 0;
  373. goto done;
  374. } else
  375. #endif
  376. /* First time */
  377. if ( !result ) {
  378. #ifdef HAVE_CYRUS_SASL
  379. if( mechs == NULL || *mechs == '\0' ) {
  380. mechs = ld->ld_options.ldo_def_sasl_mech;
  381. }
  382. #endif
  383. if( mechs == NULL || *mechs == '\0' ) {
  384. /* FIXME: this needs to be asynchronous too;
  385. * perhaps NULL should be disallowed for async usage?
  386. */
  387. rc = ldap_pvt_sasl_getmechs( ld, &smechs );
  388. if( rc != LDAP_SUCCESS ) {
  389. goto done;
  390. }
  391. Debug1( LDAP_DEBUG_TRACE,
  392. "ldap_sasl_interactive_bind: server supports: %s\n",
  393. smechs );
  394. mechs = smechs;
  395. } else {
  396. Debug1( LDAP_DEBUG_TRACE,
  397. "ldap_sasl_interactive_bind: user selected: %s\n",
  398. mechs );
  399. }
  400. }
  401. rc = ldap_int_sasl_bind( ld, dn, mechs,
  402. serverControls, clientControls,
  403. flags, interact, defaults, result, rmech, msgid );
  404. done:
  405. if ( smechs ) LDAP_FREE( smechs );
  406. return rc;
  407. }
  408. /*
  409. * ldap_sasl_interactive_bind_s - interactive SASL authentication
  410. *
  411. * This routine uses interactive callbacks.
  412. *
  413. * LDAP_SUCCESS is returned upon success, the ldap error code
  414. * otherwise.
  415. */
  416. int
  417. ldap_sasl_interactive_bind_s(
  418. LDAP *ld,
  419. LDAP_CONST char *dn, /* usually NULL */
  420. LDAP_CONST char *mechs,
  421. LDAPControl **serverControls,
  422. LDAPControl **clientControls,
  423. unsigned flags,
  424. LDAP_SASL_INTERACT_PROC *interact,
  425. void *defaults )
  426. {
  427. const char *rmech = NULL;
  428. LDAPMessage *result = NULL;
  429. int rc, msgid;
  430. do {
  431. rc = ldap_sasl_interactive_bind( ld, dn, mechs,
  432. serverControls, clientControls,
  433. flags, interact, defaults, result, &rmech, &msgid );
  434. ldap_msgfree( result );
  435. if ( rc != LDAP_SASL_BIND_IN_PROGRESS )
  436. break;
  437. #ifdef LDAP_CONNECTIONLESS
  438. if (LDAP_IS_UDP(ld)) {
  439. break;
  440. }
  441. #endif
  442. if ( ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &result ) == -1 || !result ) {
  443. return( ld->ld_errno ); /* ldap_result sets ld_errno */
  444. }
  445. } while ( rc == LDAP_SASL_BIND_IN_PROGRESS );
  446. return rc;
  447. }
  448. #ifdef HAVE_CYRUS_SASL
  449. #ifdef HAVE_SASL_SASL_H
  450. #include <sasl/sasl.h>
  451. #else
  452. #include <sasl.h>
  453. #endif
  454. #endif /* HAVE_CYRUS_SASL */
  455. static int
  456. sb_sasl_generic_remove( Sockbuf_IO_Desc *sbiod );
  457. static int
  458. sb_sasl_generic_setup( Sockbuf_IO_Desc *sbiod, void *arg )
  459. {
  460. struct sb_sasl_generic_data *p;
  461. struct sb_sasl_generic_install *i;
  462. assert( sbiod != NULL );
  463. i = (struct sb_sasl_generic_install *)arg;
  464. p = LBER_MALLOC( sizeof( *p ) );
  465. if ( p == NULL )
  466. return -1;
  467. p->ops = i->ops;
  468. p->ops_private = i->ops_private;
  469. p->sbiod = sbiod;
  470. p->flags = 0;
  471. ber_pvt_sb_buf_init( &p->sec_buf_in );
  472. ber_pvt_sb_buf_init( &p->buf_in );
  473. ber_pvt_sb_buf_init( &p->buf_out );
  474. sbiod->sbiod_pvt = p;
  475. p->ops->init( p, &p->min_send, &p->max_send, &p->max_recv );
  476. if ( ber_pvt_sb_grow_buffer( &p->sec_buf_in, p->min_send ) < 0 ) {
  477. sb_sasl_generic_remove( sbiod );
  478. sock_errset(ENOMEM);
  479. return -1;
  480. }
  481. return 0;
  482. }
  483. static int
  484. sb_sasl_generic_remove( Sockbuf_IO_Desc *sbiod )
  485. {
  486. struct sb_sasl_generic_data *p;
  487. assert( sbiod != NULL );
  488. p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt;
  489. p->ops->fini(p);
  490. ber_pvt_sb_buf_destroy( &p->sec_buf_in );
  491. ber_pvt_sb_buf_destroy( &p->buf_in );
  492. ber_pvt_sb_buf_destroy( &p->buf_out );
  493. LBER_FREE( p );
  494. sbiod->sbiod_pvt = NULL;
  495. return 0;
  496. }
  497. static ber_len_t
  498. sb_sasl_generic_pkt_length(
  499. struct sb_sasl_generic_data *p,
  500. const unsigned char *buf,
  501. int debuglevel )
  502. {
  503. ber_len_t size;
  504. assert( buf != NULL );
  505. size = buf[0] << 24
  506. | buf[1] << 16
  507. | buf[2] << 8
  508. | buf[3];
  509. if ( size > p->max_recv ) {
  510. /* somebody is trying to mess me up. */
  511. ber_log_printf( LDAP_DEBUG_ANY, debuglevel,
  512. "sb_sasl_generic_pkt_length: "
  513. "received illegal packet length of %lu bytes\n",
  514. (unsigned long)size );
  515. size = 16; /* this should lead to an error. */
  516. }
  517. return size + 4; /* include the size !!! */
  518. }
  519. /* Drop a processed packet from the input buffer */
  520. static void
  521. sb_sasl_generic_drop_packet (
  522. struct sb_sasl_generic_data *p,
  523. int debuglevel )
  524. {
  525. ber_slen_t len;
  526. len = p->sec_buf_in.buf_ptr - p->sec_buf_in.buf_end;
  527. if ( len > 0 )
  528. AC_MEMCPY( p->sec_buf_in.buf_base, p->sec_buf_in.buf_base +
  529. p->sec_buf_in.buf_end, len );
  530. if ( len >= 4 ) {
  531. p->sec_buf_in.buf_end = sb_sasl_generic_pkt_length(p,
  532. (unsigned char *) p->sec_buf_in.buf_base, debuglevel);
  533. }
  534. else {
  535. p->sec_buf_in.buf_end = 0;
  536. }
  537. p->sec_buf_in.buf_ptr = len;
  538. }
  539. static ber_slen_t
  540. sb_sasl_generic_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
  541. {
  542. struct sb_sasl_generic_data *p;
  543. ber_slen_t ret, bufptr;
  544. assert( sbiod != NULL );
  545. assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
  546. p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt;
  547. /* Are there anything left in the buffer? */
  548. ret = ber_pvt_sb_copy_out( &p->buf_in, buf, len );
  549. bufptr = ret;
  550. len -= ret;
  551. if ( len == 0 )
  552. return bufptr;
  553. p->ops->reset_buf( p, &p->buf_in );
  554. /* Read the length of the packet */
  555. while ( p->sec_buf_in.buf_ptr < 4 ) {
  556. ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base +
  557. p->sec_buf_in.buf_ptr,
  558. 4 - p->sec_buf_in.buf_ptr );
  559. #ifdef EINTR
  560. if ( ( ret < 0 ) && ( errno == EINTR ) )
  561. continue;
  562. #endif
  563. if ( ret <= 0 )
  564. return bufptr ? bufptr : ret;
  565. p->sec_buf_in.buf_ptr += ret;
  566. }
  567. /* The new packet always starts at p->sec_buf_in.buf_base */
  568. ret = sb_sasl_generic_pkt_length(p, (unsigned char *) p->sec_buf_in.buf_base,
  569. sbiod->sbiod_sb->sb_debug );
  570. /* Grow the packet buffer if necessary */
  571. if ( ( p->sec_buf_in.buf_size < (ber_len_t) ret ) &&
  572. ber_pvt_sb_grow_buffer( &p->sec_buf_in, ret ) < 0 )
  573. {
  574. sock_errset(ENOMEM);
  575. return -1;
  576. }
  577. p->sec_buf_in.buf_end = ret;
  578. /* Did we read the whole encrypted packet? */
  579. while ( p->sec_buf_in.buf_ptr < p->sec_buf_in.buf_end ) {
  580. /* No, we have got only a part of it */
  581. ret = p->sec_buf_in.buf_end - p->sec_buf_in.buf_ptr;
  582. ret = LBER_SBIOD_READ_NEXT( sbiod, p->sec_buf_in.buf_base +
  583. p->sec_buf_in.buf_ptr, ret );
  584. #ifdef EINTR
  585. if ( ( ret < 0 ) && ( errno == EINTR ) )
  586. continue;
  587. #endif
  588. if ( ret <= 0 )
  589. return bufptr ? bufptr : ret;
  590. p->sec_buf_in.buf_ptr += ret;
  591. }
  592. /* Decode the packet */
  593. ret = p->ops->decode( p, &p->sec_buf_in, &p->buf_in );
  594. /* Drop the packet from the input buffer */
  595. sb_sasl_generic_drop_packet( p, sbiod->sbiod_sb->sb_debug );
  596. if ( ret != 0 ) {
  597. ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
  598. "sb_sasl_generic_read: failed to decode packet\n" );
  599. sock_errset(EIO);
  600. return -1;
  601. }
  602. bufptr += ber_pvt_sb_copy_out( &p->buf_in, (char*) buf + bufptr, len );
  603. return bufptr;
  604. }
  605. static ber_slen_t
  606. sb_sasl_generic_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
  607. {
  608. struct sb_sasl_generic_data *p;
  609. int ret;
  610. ber_len_t len2;
  611. assert( sbiod != NULL );
  612. assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
  613. p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt;
  614. /* Is there anything left in the buffer? */
  615. if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) {
  616. ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
  617. if ( ret < 0 ) return ret;
  618. /* Still have something left?? */
  619. if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) {
  620. sock_errset(EAGAIN);
  621. return -1;
  622. }
  623. }
  624. len2 = p->max_send - 100; /* For safety margin */
  625. len2 = len > len2 ? len2 : len;
  626. /* If we're just retrying a partial write, tell the
  627. * caller it's done. Let them call again if there's
  628. * still more left to write.
  629. */
  630. if ( p->flags & LDAP_PVT_SASL_PARTIAL_WRITE ) {
  631. p->flags ^= LDAP_PVT_SASL_PARTIAL_WRITE;
  632. return len2;
  633. }
  634. /* now encode the next packet. */
  635. p->ops->reset_buf( p, &p->buf_out );
  636. ret = p->ops->encode( p, buf, len2, &p->buf_out );
  637. if ( ret != 0 ) {
  638. ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug,
  639. "sb_sasl_generic_write: failed to encode packet\n" );
  640. sock_errset(EIO);
  641. return -1;
  642. }
  643. ret = ber_pvt_sb_do_write( sbiod, &p->buf_out );
  644. if ( ret < 0 ) {
  645. /* error? */
  646. int err = sock_errno();
  647. /* caller can retry this */
  648. if ( err == EAGAIN || err == EWOULDBLOCK || err == EINTR )
  649. p->flags |= LDAP_PVT_SASL_PARTIAL_WRITE;
  650. return ret;
  651. } else if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) {
  652. /* partial write? pretend nothing got written */
  653. p->flags |= LDAP_PVT_SASL_PARTIAL_WRITE;
  654. sock_errset(EAGAIN);
  655. len2 = -1;
  656. }
  657. /* return number of bytes encoded, not written, to ensure
  658. * no byte is encoded twice (even if only sent once).
  659. */
  660. return len2;
  661. }
  662. static int
  663. sb_sasl_generic_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
  664. {
  665. struct sb_sasl_generic_data *p;
  666. p = (struct sb_sasl_generic_data *)sbiod->sbiod_pvt;
  667. if ( opt == LBER_SB_OPT_DATA_READY ) {
  668. if ( p->buf_in.buf_ptr != p->buf_in.buf_end ) return 1;
  669. }
  670. return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
  671. }
  672. Sockbuf_IO ldap_pvt_sockbuf_io_sasl_generic = {
  673. sb_sasl_generic_setup, /* sbi_setup */
  674. sb_sasl_generic_remove, /* sbi_remove */
  675. sb_sasl_generic_ctrl, /* sbi_ctrl */
  676. sb_sasl_generic_read, /* sbi_read */
  677. sb_sasl_generic_write, /* sbi_write */
  678. NULL /* sbi_close */
  679. };
  680. int ldap_pvt_sasl_generic_install(
  681. Sockbuf *sb,
  682. struct sb_sasl_generic_install *install_arg )
  683. {
  684. Debug0( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_generic_install\n" );
  685. /* don't install the stuff unless security has been negotiated */
  686. if ( !ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO,
  687. &ldap_pvt_sockbuf_io_sasl_generic ) )
  688. {
  689. #ifdef LDAP_DEBUG
  690. ber_sockbuf_add_io( sb, &ber_sockbuf_io_debug,
  691. LBER_SBIOD_LEVEL_APPLICATION, (void *)"sasl_generic_" );
  692. #endif
  693. ber_sockbuf_add_io( sb, &ldap_pvt_sockbuf_io_sasl_generic,
  694. LBER_SBIOD_LEVEL_APPLICATION, install_arg );
  695. }
  696. return LDAP_SUCCESS;
  697. }
  698. void ldap_pvt_sasl_generic_remove( Sockbuf *sb )
  699. {
  700. ber_sockbuf_remove_io( sb, &ldap_pvt_sockbuf_io_sasl_generic,
  701. LBER_SBIOD_LEVEL_APPLICATION );
  702. #ifdef LDAP_DEBUG
  703. ber_sockbuf_remove_io( sb, &ber_sockbuf_io_debug,
  704. LBER_SBIOD_LEVEL_APPLICATION );
  705. #endif
  706. }