Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/ldap/liblber/io.c
4394 views
1
/* io.c - ber general i/o 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) 1990 Regents of the University of Michigan.
17
* All rights reserved.
18
*
19
* Redistribution and use in source and binary forms are permitted
20
* provided that this notice is preserved and that due credit is given
21
* to the University of Michigan at Ann Arbor. The name of the University
22
* may not be used to endorse or promote products derived from this
23
* software without specific prior written permission. This software
24
* is provided ``as is'' without express or implied warranty.
25
*/
26
/* ACKNOWLEDGEMENTS:
27
* This work was originally developed by the University of Michigan
28
* (as part of U-MICH LDAP).
29
*/
30
31
#include "portable.h"
32
33
#include <stdio.h>
34
35
#include <ac/stdlib.h>
36
37
#include <ac/ctype.h>
38
#include <ac/errno.h>
39
#include <ac/socket.h>
40
#include <ac/string.h>
41
#include <ac/unistd.h>
42
43
#ifdef HAVE_IO_H
44
#include <io.h>
45
#endif
46
47
#include "lber-int.h"
48
#include "ldap_log.h"
49
50
ber_slen_t
51
ber_skip_data(
52
BerElement *ber,
53
ber_len_t len )
54
{
55
ber_len_t actuallen, nleft;
56
57
assert( ber != NULL );
58
assert( LBER_VALID( ber ) );
59
60
nleft = ber_pvt_ber_remaining( ber );
61
actuallen = nleft < len ? nleft : len;
62
ber->ber_ptr += actuallen;
63
ber->ber_tag = *(unsigned char *)ber->ber_ptr;
64
65
return( (ber_slen_t) actuallen );
66
}
67
68
/*
69
* Read from the ber buffer. The caller must maintain ber->ber_tag.
70
* Do not use to read whole tags. See ber_get_tag() and ber_skip_data().
71
*/
72
ber_slen_t
73
ber_read(
74
BerElement *ber,
75
char *buf,
76
ber_len_t len )
77
{
78
ber_len_t actuallen, nleft;
79
80
assert( ber != NULL );
81
assert( buf != NULL );
82
assert( LBER_VALID( ber ) );
83
84
nleft = ber_pvt_ber_remaining( ber );
85
actuallen = nleft < len ? nleft : len;
86
87
AC_MEMCPY( buf, ber->ber_ptr, actuallen );
88
89
ber->ber_ptr += actuallen;
90
91
return( (ber_slen_t) actuallen );
92
}
93
94
/*
95
* Write to the ber buffer.
96
* Note that ber_start_seqorset/ber_put_seqorset() bypass ber_write().
97
*/
98
ber_slen_t
99
ber_write(
100
BerElement *ber,
101
LDAP_CONST char *buf,
102
ber_len_t len,
103
int zero ) /* nonzero is unsupported from OpenLDAP 2.4.18 */
104
{
105
char **p;
106
107
assert( ber != NULL );
108
assert( buf != NULL );
109
assert( LBER_VALID( ber ) );
110
111
if ( zero != 0 ) {
112
ber_log_printf( LDAP_DEBUG_ANY, ber->ber_debug, "%s",
113
"ber_write: nonzero 4th argument not supported\n" );
114
return( -1 );
115
}
116
117
p = ber->ber_sos_ptr == NULL ? &ber->ber_ptr : &ber->ber_sos_ptr;
118
if ( len > (ber_len_t) (ber->ber_end - *p) ) {
119
if ( ber_realloc( ber, len ) != 0 ) return( -1 );
120
}
121
AC_MEMCPY( *p, buf, len );
122
*p += len;
123
124
return( (ber_slen_t) len );
125
}
126
127
/* Resize the ber buffer */
128
int
129
ber_realloc( BerElement *ber, ber_len_t len )
130
{
131
ber_len_t total, offset, sos_offset, rw_offset;
132
char *buf;
133
134
assert( ber != NULL );
135
assert( LBER_VALID( ber ) );
136
137
/* leave room for ber_flatten() to \0-terminate ber_buf */
138
if ( ++len == 0 ) {
139
return( -1 );
140
}
141
142
total = ber_pvt_ber_total( ber );
143
144
#define LBER_EXBUFSIZ 4060 /* a few words less than 2^N for binary buddy */
145
#if defined( LBER_EXBUFSIZ ) && LBER_EXBUFSIZ > 0
146
# ifndef notdef
147
/* don't realloc by small amounts */
148
total += len < LBER_EXBUFSIZ ? LBER_EXBUFSIZ : len;
149
# else
150
{ /* not sure what value this adds. reduce fragmentation? */
151
ber_len_t have = (total + (LBER_EXBUFSIZE - 1)) / LBER_EXBUFSIZ;
152
ber_len_t need = (len + (LBER_EXBUFSIZ - 1)) / LBER_EXBUFSIZ;
153
total = ( have + need ) * LBER_EXBUFSIZ;
154
}
155
# endif
156
#else
157
total += len; /* realloc just what's needed */
158
#endif
159
160
if ( total < len || total > (ber_len_t)-1 / 2 /* max ber_slen_t */ ) {
161
return( -1 );
162
}
163
164
buf = ber->ber_buf;
165
offset = ber->ber_ptr - buf;
166
sos_offset = ber->ber_sos_ptr ? ber->ber_sos_ptr - buf : 0;
167
/* if ber_sos_ptr != NULL, it is > ber_buf so that sos_offset > 0 */
168
rw_offset = ber->ber_rwptr ? ber->ber_rwptr - buf : 0;
169
170
buf = (char *) ber_memrealloc_x( buf, total, ber->ber_memctx );
171
if ( buf == NULL ) {
172
return( -1 );
173
}
174
175
ber->ber_buf = buf;
176
ber->ber_end = buf + total;
177
ber->ber_ptr = buf + offset;
178
if ( sos_offset )
179
ber->ber_sos_ptr = buf + sos_offset;
180
if ( ber->ber_rwptr )
181
ber->ber_rwptr = buf + rw_offset;
182
183
return( 0 );
184
}
185
186
void
187
ber_free_buf( BerElement *ber )
188
{
189
assert( LBER_VALID( ber ) );
190
191
if ( ber->ber_buf) ber_memfree_x( ber->ber_buf, ber->ber_memctx );
192
193
ber->ber_buf = NULL;
194
ber->ber_sos_ptr = NULL;
195
ber->ber_valid = LBER_UNINITIALIZED;
196
}
197
198
void
199
ber_free( BerElement *ber, int freebuf )
200
{
201
if( ber == NULL ) {
202
LDAP_MEMORY_DEBUG_ASSERT( ber != NULL );
203
return;
204
}
205
206
if( freebuf ) ber_free_buf( ber );
207
208
ber_memfree_x( (char *) ber, ber->ber_memctx );
209
}
210
211
int
212
ber_flush( Sockbuf *sb, BerElement *ber, int freeit )
213
{
214
return ber_flush2( sb, ber,
215
freeit ? LBER_FLUSH_FREE_ON_SUCCESS
216
: LBER_FLUSH_FREE_NEVER );
217
}
218
219
int
220
ber_flush2( Sockbuf *sb, BerElement *ber, int freeit )
221
{
222
ber_len_t towrite;
223
ber_slen_t rc;
224
225
assert( sb != NULL );
226
assert( ber != NULL );
227
assert( SOCKBUF_VALID( sb ) );
228
assert( LBER_VALID( ber ) );
229
230
if ( ber->ber_rwptr == NULL ) {
231
ber->ber_rwptr = ber->ber_buf;
232
}
233
towrite = ber->ber_ptr - ber->ber_rwptr;
234
235
if ( sb->sb_debug ) {
236
ber_log_printf( LDAP_DEBUG_TRACE, sb->sb_debug,
237
"ber_flush2: %ld bytes to sd %ld%s\n",
238
towrite, (long) sb->sb_fd,
239
ber->ber_rwptr != ber->ber_buf ? " (re-flush)" : "" );
240
ber_log_bprint( LDAP_DEBUG_BER, sb->sb_debug,
241
ber->ber_rwptr, towrite );
242
}
243
244
while ( towrite > 0 ) {
245
#ifdef LBER_TRICKLE
246
sleep(1);
247
rc = ber_int_sb_write( sb, ber->ber_rwptr, 1 );
248
#else
249
rc = ber_int_sb_write( sb, ber->ber_rwptr, towrite );
250
#endif
251
if ( rc <= 0 ) {
252
if ( freeit & LBER_FLUSH_FREE_ON_ERROR ) ber_free( ber, 1 );
253
return -1;
254
}
255
towrite -= rc;
256
ber->ber_rwptr += rc;
257
}
258
259
if ( freeit & LBER_FLUSH_FREE_ON_SUCCESS ) ber_free( ber, 1 );
260
261
return 0;
262
}
263
264
BerElement *
265
ber_alloc_t( int options )
266
{
267
BerElement *ber;
268
269
ber = (BerElement *) LBER_CALLOC( 1, sizeof(BerElement) );
270
271
if ( ber == NULL ) {
272
return NULL;
273
}
274
275
ber->ber_valid = LBER_VALID_BERELEMENT;
276
ber->ber_tag = LBER_DEFAULT;
277
ber->ber_options = options;
278
ber->ber_debug = ber_int_debug;
279
280
assert( LBER_VALID( ber ) );
281
return ber;
282
}
283
284
BerElement *
285
ber_alloc( void ) /* deprecated */
286
{
287
return ber_alloc_t( 0 );
288
}
289
290
BerElement *
291
der_alloc( void ) /* deprecated */
292
{
293
return ber_alloc_t( LBER_USE_DER );
294
}
295
296
BerElement *
297
ber_dup( BerElement *ber )
298
{
299
BerElement *new;
300
301
assert( ber != NULL );
302
assert( LBER_VALID( ber ) );
303
304
if ( (new = ber_alloc_t( ber->ber_options )) == NULL ) {
305
return NULL;
306
}
307
308
*new = *ber;
309
310
assert( LBER_VALID( new ) );
311
return( new );
312
}
313
314
315
void
316
ber_init2( BerElement *ber, struct berval *bv, int options )
317
{
318
assert( ber != NULL );
319
320
(void) memset( (char *)ber, '\0', sizeof( BerElement ));
321
ber->ber_valid = LBER_VALID_BERELEMENT;
322
ber->ber_tag = LBER_DEFAULT;
323
ber->ber_options = (char) options;
324
ber->ber_debug = ber_int_debug;
325
326
if ( bv != NULL ) {
327
ber->ber_buf = bv->bv_val;
328
ber->ber_ptr = ber->ber_buf;
329
ber->ber_end = ber->ber_buf + bv->bv_len;
330
}
331
332
assert( LBER_VALID( ber ) );
333
}
334
335
/* OLD U-Mich ber_init() */
336
void
337
ber_init_w_nullc( BerElement *ber, int options )
338
{
339
ber_init2( ber, NULL, options );
340
}
341
342
/* New C-API ber_init() */
343
/* This function constructs a BerElement containing a copy
344
** of the data in the bv argument.
345
*/
346
BerElement *
347
ber_init( struct berval *bv )
348
{
349
BerElement *ber;
350
351
assert( bv != NULL );
352
353
if ( bv == NULL ) {
354
return NULL;
355
}
356
357
ber = ber_alloc_t( 0 );
358
359
if( ber == NULL ) {
360
/* allocation failed */
361
return NULL;
362
}
363
364
/* copy the data */
365
if ( ((ber_len_t) ber_write ( ber, bv->bv_val, bv->bv_len, 0 ))
366
!= bv->bv_len )
367
{
368
/* write failed, so free and return NULL */
369
ber_free( ber, 1 );
370
return NULL;
371
}
372
373
ber_reset( ber, 1 ); /* reset the pointer to the start of the buffer */
374
return ber;
375
}
376
377
/* New C-API ber_flatten routine */
378
/* This routine allocates a struct berval whose contents are a BER
379
** encoding taken from the ber argument. The bvPtr pointer points to
380
** the returned berval.
381
**
382
** ber_flatten2 is the same, but uses a struct berval passed by
383
** the caller. If alloc is 0 the returned bv uses the ber buf directly.
384
*/
385
int ber_flatten2(
386
BerElement *ber,
387
struct berval *bv,
388
int alloc )
389
{
390
assert( bv != NULL );
391
392
if ( bv == NULL ) {
393
return -1;
394
}
395
396
if ( ber == NULL ) {
397
/* ber is null, create an empty berval */
398
bv->bv_val = NULL;
399
bv->bv_len = 0;
400
401
} else if ( ber->ber_sos_ptr != NULL ) {
402
/* unmatched "{" and "}" */
403
return -1;
404
405
} else {
406
/* copy the berval */
407
ber_len_t len = ber_pvt_ber_write( ber );
408
409
if ( alloc ) {
410
bv->bv_val = (char *) ber_memalloc_x( len + 1, ber->ber_memctx );
411
if ( bv->bv_val == NULL ) {
412
return -1;
413
}
414
AC_MEMCPY( bv->bv_val, ber->ber_buf, len );
415
bv->bv_val[len] = '\0';
416
} else if ( ber->ber_buf != NULL ) {
417
bv->bv_val = ber->ber_buf;
418
bv->bv_val[len] = '\0';
419
} else {
420
bv->bv_val = "";
421
}
422
bv->bv_len = len;
423
}
424
return 0;
425
}
426
427
int ber_flatten(
428
BerElement *ber,
429
struct berval **bvPtr)
430
{
431
struct berval *bv;
432
int rc;
433
434
assert( bvPtr != NULL );
435
436
if(bvPtr == NULL) {
437
return -1;
438
}
439
440
bv = ber_memalloc_x( sizeof(struct berval), ber->ber_memctx );
441
if ( bv == NULL ) {
442
return -1;
443
}
444
rc = ber_flatten2(ber, bv, 1);
445
if (rc == -1) {
446
ber_memfree_x(bv, ber->ber_memctx);
447
} else {
448
*bvPtr = bv;
449
}
450
return rc;
451
}
452
453
void
454
ber_reset( BerElement *ber, int was_writing )
455
{
456
assert( ber != NULL );
457
assert( LBER_VALID( ber ) );
458
459
if ( was_writing ) {
460
ber->ber_end = ber->ber_ptr;
461
ber->ber_ptr = ber->ber_buf;
462
463
} else {
464
ber->ber_ptr = ber->ber_end;
465
}
466
467
ber->ber_rwptr = NULL;
468
}
469
470
/*
471
* A rewrite of ber_get_next that can safely be called multiple times
472
* for the same packet. It will simply continue where it stopped until
473
* a full packet is read.
474
*/
475
476
#define LENSIZE 4
477
478
ber_tag_t
479
ber_get_next(
480
Sockbuf *sb,
481
ber_len_t *len,
482
BerElement *ber )
483
{
484
assert( sb != NULL );
485
assert( len != NULL );
486
assert( ber != NULL );
487
assert( SOCKBUF_VALID( sb ) );
488
assert( LBER_VALID( ber ) );
489
490
if ( ber->ber_debug & LDAP_DEBUG_TRACE ) {
491
ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug,
492
"ber_get_next\n" );
493
}
494
495
/*
496
* Any ber element looks like this: tag length contents.
497
* Assuming everything's ok, we return the tag byte (we
498
* can assume a single byte), return the length in len,
499
* and the rest of the undecoded element in buf.
500
*
501
* Assumptions:
502
* 1) small tags (less than 128)
503
* 2) definite lengths
504
* 3) primitive encodings used whenever possible
505
*
506
* The code also handles multi-byte tags. The first few bytes
507
* of the message are read to check for multi-byte tags and
508
* lengths. These bytes are temporarily stored in the ber_tag,
509
* ber_len, and ber_usertag fields of the berelement until
510
* tag/len parsing is complete. After this parsing, any leftover
511
* bytes and the rest of the message are copied into the ber_buf.
512
*
513
* We expect tag and len to be at most 32 bits wide.
514
*/
515
516
if (ber->ber_rwptr == NULL) {
517
assert( ber->ber_buf == NULL );
518
ber->ber_rwptr = (char *) &ber->ber_len-1;
519
ber->ber_ptr = ber->ber_rwptr;
520
ber->ber_tag = 0;
521
}
522
523
while (ber->ber_rwptr > (char *)&ber->ber_tag && ber->ber_rwptr <
524
(char *)&ber->ber_len + LENSIZE*2) {
525
ber_slen_t sblen;
526
char buf[sizeof(ber->ber_len)-1];
527
ber_len_t tlen = 0;
528
529
/* The tag & len can be at most 9 bytes; we try to read up to 8 here */
530
sock_errset(0);
531
sblen=((char *)&ber->ber_len + LENSIZE*2 - 1)-ber->ber_rwptr;
532
/* Trying to read the last len byte of a 9 byte tag+len */
533
if (sblen<1)
534
sblen = 1;
535
sblen=ber_int_sb_read( sb, ber->ber_rwptr, sblen );
536
if (sblen<=0) return LBER_DEFAULT;
537
ber->ber_rwptr += sblen;
538
539
/* We got at least one byte, try to parse the tag. */
540
if (ber->ber_ptr == (char *)&ber->ber_len-1) {
541
ber_tag_t tag;
542
unsigned char *p = (unsigned char *)ber->ber_ptr;
543
tag = *p++;
544
if ((tag & LBER_BIG_TAG_MASK) == LBER_BIG_TAG_MASK) {
545
ber_len_t i;
546
for (i=1; (char *)p<ber->ber_rwptr; i++) {
547
tag <<= 8;
548
tag |= *p++;
549
if (!(tag & LBER_MORE_TAG_MASK))
550
break;
551
/* Is the tag too big? */
552
if (i == sizeof(ber_tag_t)-1) {
553
sock_errset(ERANGE);
554
return LBER_DEFAULT;
555
}
556
}
557
/* Did we run out of bytes? */
558
if ((char *)p == ber->ber_rwptr) {
559
sock_errset(EWOULDBLOCK);
560
return LBER_DEFAULT;
561
}
562
}
563
ber->ber_tag = tag;
564
ber->ber_ptr = (char *)p;
565
}
566
567
if ( ber->ber_ptr == ber->ber_rwptr ) {
568
sock_errset(EWOULDBLOCK);
569
return LBER_DEFAULT;
570
}
571
572
/* Now look for the length */
573
if (*ber->ber_ptr & 0x80) { /* multi-byte */
574
int i;
575
unsigned char *p = (unsigned char *)ber->ber_ptr;
576
int llen = *p++ & 0x7f;
577
if (llen > LENSIZE) {
578
sock_errset(ERANGE);
579
return LBER_DEFAULT;
580
}
581
/* Not enough bytes? */
582
if (ber->ber_rwptr - (char *)p < llen) {
583
sock_errset(EWOULDBLOCK);
584
return LBER_DEFAULT;
585
}
586
for (i=0; i<llen; i++) {
587
tlen <<=8;
588
tlen |= *p++;
589
}
590
ber->ber_ptr = (char *)p;
591
} else {
592
tlen = *(unsigned char *)ber->ber_ptr++;
593
}
594
595
/* Are there leftover data bytes inside ber->ber_len? */
596
if (ber->ber_ptr < (char *)&ber->ber_usertag) {
597
if (ber->ber_rwptr < (char *)&ber->ber_usertag) {
598
sblen = ber->ber_rwptr - ber->ber_ptr;
599
} else {
600
sblen = (char *)&ber->ber_usertag - ber->ber_ptr;
601
}
602
AC_MEMCPY(buf, ber->ber_ptr, sblen);
603
ber->ber_ptr += sblen;
604
} else {
605
sblen = 0;
606
}
607
ber->ber_len = tlen;
608
609
/* now fill the buffer. */
610
611
/* make sure length is reasonable */
612
if ( ber->ber_len == 0 ) {
613
sock_errset(ERANGE);
614
return LBER_DEFAULT;
615
}
616
617
if ( sb->sb_max_incoming && ber->ber_len > sb->sb_max_incoming ) {
618
ber_log_printf( LDAP_DEBUG_CONNS, ber->ber_debug,
619
"ber_get_next: sockbuf_max_incoming exceeded "
620
"(%ld > %ld)\n", ber->ber_len, sb->sb_max_incoming );
621
sock_errset(ERANGE);
622
return LBER_DEFAULT;
623
}
624
625
if (ber->ber_buf==NULL) {
626
ber_len_t l = ber->ber_rwptr - ber->ber_ptr;
627
/* ber->ber_ptr is always <= ber->ber->ber_rwptr.
628
* make sure ber->ber_len agrees with what we've
629
* already read.
630
*/
631
if ( ber->ber_len < sblen + l ) {
632
sock_errset(ERANGE);
633
return LBER_DEFAULT;
634
}
635
ber->ber_buf = (char *) ber_memalloc_x( ber->ber_len + 1, ber->ber_memctx );
636
if (ber->ber_buf==NULL) {
637
return LBER_DEFAULT;
638
}
639
ber->ber_end = ber->ber_buf + ber->ber_len;
640
if (sblen) {
641
AC_MEMCPY(ber->ber_buf, buf, sblen);
642
}
643
if (l > 0) {
644
AC_MEMCPY(ber->ber_buf + sblen, ber->ber_ptr, l);
645
sblen += l;
646
}
647
*ber->ber_end = '\0';
648
ber->ber_ptr = ber->ber_buf;
649
ber->ber_usertag = 0;
650
if ((ber_len_t)sblen == ber->ber_len) {
651
goto done;
652
}
653
ber->ber_rwptr = ber->ber_buf + sblen;
654
}
655
}
656
657
if ((ber->ber_rwptr>=ber->ber_buf) && (ber->ber_rwptr<ber->ber_end)) {
658
ber_slen_t res;
659
ber_slen_t to_go;
660
661
to_go = ber->ber_end - ber->ber_rwptr;
662
/* unsigned/signed overflow */
663
if (to_go<0) return LBER_DEFAULT;
664
665
sock_errset(0);
666
res = ber_int_sb_read( sb, ber->ber_rwptr, to_go );
667
if (res<=0) return LBER_DEFAULT;
668
ber->ber_rwptr+=res;
669
670
if (res<to_go) {
671
sock_errset(EWOULDBLOCK);
672
return LBER_DEFAULT;
673
}
674
done:
675
ber->ber_rwptr = NULL;
676
*len = ber->ber_len;
677
if ( ber->ber_debug ) {
678
ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug,
679
"ber_get_next: tag 0x%lx len %ld contents:\n",
680
ber->ber_tag, ber->ber_len );
681
ber_log_dump( LDAP_DEBUG_BER, ber->ber_debug, ber, 1 );
682
}
683
return (ber->ber_tag);
684
}
685
686
/* invalid input */
687
return LBER_DEFAULT;
688
}
689
690
char *
691
ber_start( BerElement* ber )
692
{
693
return ber->ber_buf;
694
}
695
696
int
697
ber_len( BerElement* ber )
698
{
699
return ( ber->ber_end - ber->ber_buf );
700
}
701
702
int
703
ber_ptrlen( BerElement* ber )
704
{
705
return ( ber->ber_ptr - ber->ber_buf );
706
}
707
708
void
709
ber_rewind ( BerElement * ber )
710
{
711
ber->ber_rwptr = NULL;
712
ber->ber_sos_ptr = NULL;
713
ber->ber_end = ber->ber_ptr;
714
ber->ber_ptr = ber->ber_buf;
715
#if 0 /* TODO: Should we add this? */
716
ber->ber_tag = LBER_DEFAULT;
717
ber->ber_usertag = 0;
718
#endif
719
}
720
721
int
722
ber_remaining( BerElement * ber )
723
{
724
return ber_pvt_ber_remaining( ber );
725
}
726
727