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