PageRenderTime 30ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/usr/src/lib/libldap5/sources/ldap/ber/encode.c

https://bitbucket.org/a3217055/illumos-joyent
C | 688 lines | 454 code | 117 blank | 117 comment | 138 complexity | 99008849632a0de11d4dc6ba6a5c249c MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, GPL-2.0, GPL-3.0, 0BSD, BSD-2-Clause, BSD-3-Clause-No-Nuclear-License-2014, MPL-2.0-no-copyleft-exception, AGPL-1.0, LGPL-2.1, LGPL-2.0
  1. /*
  2. * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
  3. * Use is subject to license terms.
  4. */
  5. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  6. *
  7. * The contents of this file are subject to the Netscape Public License
  8. * Version 1.0 (the "NPL"); you may not use this file except in
  9. * compliance with the NPL. You may obtain a copy of the NPL at
  10. * http://www.mozilla.org/NPL/
  11. *
  12. * Software distributed under the NPL is distributed on an "AS IS" basis,
  13. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  14. * for the specific language governing rights and limitations under the
  15. * NPL.
  16. *
  17. * The Initial Developer of this code under the NPL is Netscape
  18. * Communications Corporation. Portions created by Netscape are
  19. * Copyright (C) 1998 Netscape Communications Corporation. All Rights
  20. * Reserved.
  21. */
  22. /*
  23. * Copyright (c) 1990 Regents of the University of Michigan.
  24. * All rights reserved.
  25. *
  26. * Redistribution and use in source and binary forms are permitted
  27. * provided that this notice is preserved and that due credit is given
  28. * to the University of Michigan at Ann Arbor. The name of the University
  29. * may not be used to endorse or promote products derived from this
  30. * software without specific prior written permission. This software
  31. * is provided ``as is'' without express or implied warranty.
  32. */
  33. /* encode.c - ber output encoding routines */
  34. #include "lber-int.h"
  35. /* the following constants are used in ber_calc_lenlen */
  36. #define LENMASK1 0xFF
  37. #define LENMASK2 0xFFFF
  38. #define LENMASK3 0xFFFFFF
  39. #define LENMASK4 0xFFFFFFFF
  40. #define _MASK 0x80
  41. static int
  42. ber_calc_taglen( ber_tag_t tag )
  43. {
  44. int i;
  45. ber_int_t mask;
  46. /* find the first non-all-zero byte in the tag */
  47. for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) {
  48. mask = (LENMASK3 << (i * 8));
  49. /* not all zero */
  50. if ( tag & mask )
  51. break;
  52. }
  53. return( i + 1 );
  54. }
  55. static int
  56. ber_put_tag( BerElement *ber, ber_tag_t tag, int nosos )
  57. {
  58. int taglen;
  59. ber_tag_t ntag;
  60. taglen = ber_calc_taglen( tag );
  61. ntag = LBER_HTONL( tag );
  62. return( ber_write( ber, ((char *) &ntag) + sizeof(ber_int_t) - taglen,
  63. taglen, nosos ) );
  64. }
  65. static int
  66. ber_calc_lenlen( ber_len_t len )
  67. {
  68. /*
  69. * short len if it's less than 128 - one byte giving the len,
  70. * with bit 8 0.
  71. */
  72. if ( len <= 0x7F )
  73. return( 1 );
  74. /*
  75. * long len otherwise - one byte with bit 8 set, giving the
  76. * length of the length, followed by the length itself.
  77. */
  78. if ( len <= LENMASK1 )
  79. return( 2 );
  80. if ( len <= LENMASK2 )
  81. return( 3 );
  82. if ( len <= LENMASK3 )
  83. return( 4 );
  84. return( 5 );
  85. }
  86. static int
  87. ber_put_len( BerElement *ber, ber_len_t len, int nosos )
  88. {
  89. int i;
  90. char lenlen;
  91. ber_int_t mask;
  92. ber_len_t netlen;
  93. /*
  94. * short len if it's less than 128 - one byte giving the len,
  95. * with bit 8 0.
  96. */
  97. if ( len <= 127 ) {
  98. netlen = LBER_HTONL( len );
  99. return( ber_write( ber, (char *) &netlen + sizeof(ber_int_t) - 1,
  100. 1, nosos ) );
  101. }
  102. /*
  103. * long len otherwise - one byte with bit 8 set, giving the
  104. * length of the length, followed by the length itself.
  105. */
  106. /* find the first non-all-zero byte */
  107. for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) {
  108. mask = (LENMASK1 << (i * 8));
  109. /* not all zero */
  110. if ( len & mask )
  111. break;
  112. }
  113. lenlen = ++i;
  114. if ( lenlen > 4 )
  115. return( -1 );
  116. lenlen |= 0x80;
  117. /* write the length of the length */
  118. if ( ber_write( ber, &lenlen, 1, nosos ) != 1 )
  119. return( -1 );
  120. /* write the length itself */
  121. netlen = LBER_HTONL( len );
  122. if ( ber_write( ber, (char *) &netlen + (sizeof(ber_int_t) - i), i, nosos )
  123. != i )
  124. return( -1 );
  125. return( i + 1 );
  126. }
  127. static int
  128. ber_put_int_or_enum( BerElement *ber, ber_int_t num, ber_tag_t tag )
  129. {
  130. int i, sign, taglen;
  131. int len, lenlen;
  132. ber_int_t netnum, mask;
  133. sign = (num < 0);
  134. /*
  135. * high bit is set - look for first non-all-one byte
  136. * high bit is clear - look for first non-all-zero byte
  137. */
  138. for ( i = sizeof(ber_int_t) - 1; i > 0; i-- ) {
  139. mask = (LENMASK1 << (i * 8));
  140. if ( sign ) {
  141. /* not all ones */
  142. if ( (num & mask) != mask )
  143. break;
  144. } else {
  145. /* not all zero */
  146. if ( num & mask )
  147. break;
  148. }
  149. }
  150. /*
  151. * we now have the "leading byte". if the high bit on this
  152. * byte matches the sign bit, we need to "back up" a byte.
  153. */
  154. mask = (num & (_MASK << (i * 8)));
  155. if ( (mask && !sign) || (sign && !mask) )
  156. i++;
  157. len = i + 1;
  158. if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
  159. return( -1 );
  160. if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 )
  161. return( -1 );
  162. i++;
  163. netnum = LBER_HTONL( num );
  164. if ( ber_write( ber, (char *) &netnum + (sizeof(ber_int_t) - i), i, 0 )
  165. == i)
  166. /* length of tag + length + contents */
  167. return( taglen + lenlen + i );
  168. return( -1 );
  169. }
  170. int
  171. LDAP_CALL
  172. ber_put_enum( BerElement *ber, ber_int_t num, ber_tag_t tag )
  173. {
  174. if ( tag == LBER_DEFAULT )
  175. tag = LBER_ENUMERATED;
  176. return( ber_put_int_or_enum( ber, num, tag ) );
  177. }
  178. int
  179. LDAP_CALL
  180. ber_put_int( BerElement *ber, ber_int_t num, ber_tag_t tag )
  181. {
  182. if ( tag == LBER_DEFAULT )
  183. tag = LBER_INTEGER;
  184. return( ber_put_int_or_enum( ber, num, tag ) );
  185. }
  186. int
  187. LDAP_CALL
  188. ber_put_ostring( BerElement *ber, char *str, ber_len_t len,
  189. ber_tag_t tag )
  190. {
  191. int taglen, lenlen, rc;
  192. #ifdef STR_TRANSLATION
  193. int free_str;
  194. #endif /* STR_TRANSLATION */
  195. if ( tag == LBER_DEFAULT )
  196. tag = LBER_OCTETSTRING;
  197. if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
  198. return( -1 );
  199. #ifdef STR_TRANSLATION
  200. if ( len > 0 && ( ber->ber_options & LBER_OPT_TRANSLATE_STRINGS ) != 0
  201. && ber->ber_encode_translate_proc != NULL ) {
  202. if ( (*(ber->ber_encode_translate_proc))( &str, &len, 0 )
  203. != 0 ) {
  204. return( -1 );
  205. }
  206. free_str = 1;
  207. } else {
  208. free_str = 0;
  209. }
  210. #endif /* STR_TRANSLATION */
  211. /*
  212. * Note: below is a spot where we limit ber_write
  213. * to signed long (instead of unsigned long)
  214. */
  215. if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 ||
  216. ber_write( ber, str, len, 0 ) != (ber_int_t) len ) {
  217. rc = -1;
  218. } else {
  219. /* return length of tag + length + contents */
  220. rc = taglen + lenlen + len;
  221. }
  222. #ifdef STR_TRANSLATION
  223. if ( free_str ) {
  224. NSLBERI_FREE( str );
  225. }
  226. #endif /* STR_TRANSLATION */
  227. return( rc );
  228. }
  229. int
  230. LDAP_CALL
  231. ber_put_string( BerElement *ber, char *str, ber_tag_t tag )
  232. {
  233. return( ber_put_ostring( ber, str, (ber_len_t) strlen( str ), tag ));
  234. }
  235. int
  236. LDAP_CALL
  237. ber_put_bitstring( BerElement *ber, char *str,
  238. ber_len_t blen /* in bits */, ber_tag_t tag )
  239. {
  240. int taglen, lenlen, len;
  241. unsigned char unusedbits;
  242. if ( tag == LBER_DEFAULT )
  243. tag = LBER_BITSTRING;
  244. if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
  245. return( -1 );
  246. len = ( blen + 7 ) / 8;
  247. unusedbits = (unsigned char) (len * 8 - blen);
  248. if ( (lenlen = ber_put_len( ber, len + 1, 0 )) == -1 )
  249. return( -1 );
  250. if ( ber_write( ber, (char *)&unusedbits, 1, 0 ) != 1 )
  251. return( -1 );
  252. if ( ber_write( ber, str, len, 0 ) != len )
  253. return( -1 );
  254. /* return length of tag + length + unused bit count + contents */
  255. return( taglen + 1 + lenlen + len );
  256. }
  257. int
  258. LDAP_CALL
  259. ber_put_null( BerElement *ber, ber_tag_t tag )
  260. {
  261. int taglen;
  262. if ( tag == LBER_DEFAULT )
  263. tag = LBER_NULL;
  264. if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
  265. return( -1 );
  266. if ( ber_put_len( ber, 0, 0 ) != 1 )
  267. return( -1 );
  268. return( taglen + 1 );
  269. }
  270. int
  271. LDAP_CALL
  272. ber_put_boolean( BerElement *ber, int boolval, ber_tag_t tag )
  273. {
  274. int taglen;
  275. unsigned char trueval = 0xff;
  276. unsigned char falseval = 0x00;
  277. if ( tag == LBER_DEFAULT )
  278. tag = LBER_BOOLEAN;
  279. if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
  280. return( -1 );
  281. if ( ber_put_len( ber, 1, 0 ) != 1 )
  282. return( -1 );
  283. if ( ber_write( ber, (char *)(boolval ? &trueval : &falseval), 1, 0 )
  284. != 1 )
  285. return( -1 );
  286. return( taglen + 2 );
  287. }
  288. #define FOUR_BYTE_LEN 5
  289. /* the idea here is roughly this: we maintain a stack of these Seqorset
  290. * structures. This is pushed when we see the beginning of a new set or
  291. * sequence. It is popped when we see the end of a set or sequence.
  292. * Since we don't want to malloc and free these structures all the time,
  293. * we pre-allocate a small set of them within the ber element structure.
  294. * thus we need to spot when we've overflowed this stack and fall back to
  295. * malloc'ing instead.
  296. */
  297. static int
  298. ber_start_seqorset( BerElement *ber, ber_tag_t tag )
  299. {
  300. Seqorset *new_sos;
  301. /* can we fit into the local stack ? */
  302. if (ber->ber_sos_stack_posn < SOS_STACK_SIZE) {
  303. /* yes */
  304. new_sos = &ber->ber_sos_stack[ber->ber_sos_stack_posn];
  305. } else {
  306. /* no */
  307. if ( (new_sos = (Seqorset *)NSLBERI_MALLOC( sizeof(Seqorset)))
  308. == NULLSEQORSET ) {
  309. return( -1 );
  310. }
  311. }
  312. ber->ber_sos_stack_posn++;
  313. if ( ber->ber_sos == NULLSEQORSET )
  314. new_sos->sos_first = ber->ber_ptr;
  315. else
  316. new_sos->sos_first = ber->ber_sos->sos_ptr;
  317. /* Set aside room for a 4 byte length field */
  318. new_sos->sos_ptr = new_sos->sos_first + ber_calc_taglen( tag ) + FOUR_BYTE_LEN;
  319. new_sos->sos_tag = tag;
  320. new_sos->sos_next = ber->ber_sos;
  321. new_sos->sos_clen = 0;
  322. ber->ber_sos = new_sos;
  323. if (ber->ber_sos->sos_ptr > ber->ber_end) {
  324. nslberi_ber_realloc(ber, ber->ber_sos->sos_ptr - ber->ber_end);
  325. }
  326. return( 0 );
  327. }
  328. int
  329. LDAP_CALL
  330. ber_start_seq( BerElement *ber, ber_tag_t tag )
  331. {
  332. if ( tag == LBER_DEFAULT )
  333. tag = LBER_SEQUENCE;
  334. return( ber_start_seqorset( ber, tag ) );
  335. }
  336. int
  337. LDAP_CALL
  338. ber_start_set( BerElement *ber, ber_tag_t tag )
  339. {
  340. if ( tag == LBER_DEFAULT )
  341. tag = LBER_SET;
  342. return( ber_start_seqorset( ber, tag ) );
  343. }
  344. static int
  345. ber_put_seqorset( BerElement *ber )
  346. {
  347. ber_len_t len, netlen;
  348. int taglen, lenlen;
  349. unsigned char ltag = 0x80 + FOUR_BYTE_LEN - 1;
  350. Seqorset *next;
  351. Seqorset **sos = &ber->ber_sos;
  352. /*
  353. * If this is the toplevel sequence or set, we need to actually
  354. * write the stuff out. Otherwise, it's already been put in
  355. * the appropriate buffer and will be written when the toplevel
  356. * one is written. In this case all we need to do is update the
  357. * length and tag.
  358. */
  359. len = (*sos)->sos_clen;
  360. netlen = LBER_HTONL( len );
  361. if ( sizeof(ber_int_t) > 4 && len > LENMASK4 )
  362. return( -1 );
  363. if ( ber->ber_options & LBER_OPT_USE_DER ) {
  364. lenlen = ber_calc_lenlen( len );
  365. } else {
  366. lenlen = FOUR_BYTE_LEN;
  367. }
  368. if ( (next = (*sos)->sos_next) == NULLSEQORSET ) {
  369. /* write the tag */
  370. if ( (taglen = ber_put_tag( ber, (*sos)->sos_tag, 1 )) == -1 )
  371. return( -1 );
  372. if ( ber->ber_options & LBER_OPT_USE_DER ) {
  373. /* Write the length in the minimum # of octets */
  374. if ( ber_put_len( ber, len, 1 ) == -1 )
  375. return( -1 );
  376. if (lenlen != FOUR_BYTE_LEN) {
  377. /*
  378. * We set aside FOUR_BYTE_LEN bytes for
  379. * the length field. Move the data if
  380. * we don't actually need that much
  381. */
  382. SAFEMEMCPY( (*sos)->sos_first + taglen +
  383. lenlen, (*sos)->sos_first + taglen +
  384. FOUR_BYTE_LEN, len );
  385. }
  386. } else {
  387. /* Fill FOUR_BYTE_LEN bytes for length field */
  388. /* one byte of length length */
  389. if ( ber_write( ber, (char *)&ltag, 1, 1 ) != 1 )
  390. return( -1 );
  391. /* the length itself */
  392. if ( ber_write( ber, (char *) &netlen + sizeof(ber_int_t)
  393. - (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1 )
  394. != FOUR_BYTE_LEN - 1 )
  395. return( -1 );
  396. }
  397. /* The ber_ptr is at the set/seq start - move it to the end */
  398. ber->ber_ptr += len;
  399. } else {
  400. ber_tag_t ntag;
  401. /* the tag */
  402. taglen = ber_calc_taglen( (*sos)->sos_tag );
  403. ntag = LBER_HTONL( (*sos)->sos_tag );
  404. SAFEMEMCPY( (*sos)->sos_first, (char *) &ntag +
  405. sizeof(ber_int_t) - taglen, taglen );
  406. if ( ber->ber_options & LBER_OPT_USE_DER ) {
  407. ltag = (lenlen == 1) ? (unsigned char)len :
  408. (unsigned char) (0x80 + (lenlen - 1));
  409. }
  410. /* one byte of length length */
  411. SAFEMEMCPY( (*sos)->sos_first + 1, &ltag, 1 );
  412. if ( ber->ber_options & LBER_OPT_USE_DER ) {
  413. if (lenlen > 1) {
  414. /* Write the length itself */
  415. SAFEMEMCPY( (*sos)->sos_first + 2,
  416. (char *)&netlen + sizeof(ber_uint_t) -
  417. (lenlen - 1),
  418. lenlen - 1 );
  419. }
  420. if (lenlen != FOUR_BYTE_LEN) {
  421. /*
  422. * We set aside FOUR_BYTE_LEN bytes for
  423. * the length field. Move the data if
  424. * we don't actually need that much
  425. */
  426. SAFEMEMCPY( (*sos)->sos_first + taglen +
  427. lenlen, (*sos)->sos_first + taglen +
  428. FOUR_BYTE_LEN, len );
  429. }
  430. } else {
  431. /* the length itself */
  432. SAFEMEMCPY( (*sos)->sos_first + taglen + 1,
  433. (char *) &netlen + sizeof(ber_int_t) -
  434. (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1 );
  435. }
  436. next->sos_clen += (taglen + lenlen + len);
  437. next->sos_ptr += (taglen + lenlen + len);
  438. }
  439. /* we're done with this seqorset, so free it up */
  440. /* was this one from the local stack ? */
  441. if (ber->ber_sos_stack_posn <= SOS_STACK_SIZE) {
  442. /* yes */
  443. } else {
  444. /* no */
  445. NSLBERI_FREE( (char *) (*sos) );
  446. }
  447. ber->ber_sos_stack_posn--;
  448. *sos = next;
  449. return( taglen + lenlen + len );
  450. }
  451. int
  452. LDAP_CALL
  453. ber_put_seq( BerElement *ber )
  454. {
  455. return( ber_put_seqorset( ber ) );
  456. }
  457. int
  458. LDAP_CALL
  459. ber_put_set( BerElement *ber )
  460. {
  461. return( ber_put_seqorset( ber ) );
  462. }
  463. /* VARARGS */
  464. int
  465. LDAP_C
  466. ber_printf( BerElement *ber, const char *fmt, ... )
  467. {
  468. va_list ap;
  469. char *s, **ss;
  470. struct berval *bval, **bv;
  471. int rc, i;
  472. ber_len_t len;
  473. va_start( ap, fmt );
  474. #ifdef LDAP_DEBUG
  475. if ( lber_debug & 64 ) {
  476. char msg[80];
  477. sprintf( msg, "ber_printf fmt (%s)\n", fmt );
  478. ber_err_print( msg );
  479. }
  480. #endif
  481. for ( rc = 0; *fmt && rc != -1; fmt++ ) {
  482. switch ( *fmt ) {
  483. case 'b': /* boolean */
  484. i = va_arg( ap, int );
  485. rc = ber_put_boolean( ber, i, ber->ber_tag );
  486. break;
  487. case 'i': /* int */
  488. i = va_arg( ap, int );
  489. rc = ber_put_int( ber, (ber_int_t)i, ber->ber_tag );
  490. break;
  491. case 'e': /* enumeration */
  492. i = va_arg( ap, int );
  493. rc = ber_put_enum( ber, (ber_int_t)i, ber->ber_tag );
  494. break;
  495. case 'n': /* null */
  496. rc = ber_put_null( ber, ber->ber_tag );
  497. break;
  498. case 'o': /* octet string (non-null terminated) */
  499. s = va_arg( ap, char * );
  500. len = va_arg( ap, int );
  501. rc = ber_put_ostring( ber, s, len, ber->ber_tag );
  502. break;
  503. case 'O': /* berval octet string */
  504. if( ( bval = va_arg( ap, struct berval * ) ) == NULL )
  505. break;
  506. if( bval->bv_len == 0 ) {
  507. rc = ber_put_ostring( ber, "", 0, ber->ber_tag );
  508. } else {
  509. rc = ber_put_ostring( ber, bval->bv_val, bval->bv_len,
  510. ber->ber_tag );
  511. }
  512. break;
  513. case 's': /* string */
  514. s = va_arg( ap, char * );
  515. rc = ber_put_string( ber, s, ber->ber_tag );
  516. break;
  517. case 'B': /* bit string */
  518. s = va_arg( ap, char * );
  519. len = va_arg( ap, int ); /* in bits */
  520. rc = ber_put_bitstring( ber, s, len, ber->ber_tag );
  521. break;
  522. case 't': /* tag for the next element */
  523. ber->ber_tag = va_arg( ap, ber_tag_t );
  524. ber->ber_usertag = 1;
  525. break;
  526. case 'v': /* vector of strings */
  527. if ( (ss = va_arg( ap, char ** )) == NULL )
  528. break;
  529. for ( i = 0; ss[i] != NULL; i++ ) {
  530. if ( (rc = ber_put_string( ber, ss[i],
  531. ber->ber_tag )) == -1 )
  532. break;
  533. }
  534. break;
  535. case 'V': /* sequences of strings + lengths */
  536. if ( (bv = va_arg( ap, struct berval ** )) == NULL )
  537. break;
  538. for ( i = 0; bv[i] != NULL; i++ ) {
  539. if ( (rc = ber_put_ostring( ber, bv[i]->bv_val,
  540. bv[i]->bv_len, ber->ber_tag )) == -1 )
  541. break;
  542. }
  543. break;
  544. case '{': /* begin sequence */
  545. rc = ber_start_seq( ber, ber->ber_tag );
  546. break;
  547. case '}': /* end sequence */
  548. rc = ber_put_seqorset( ber );
  549. break;
  550. case '[': /* begin set */
  551. rc = ber_start_set( ber, ber->ber_tag );
  552. break;
  553. case ']': /* end set */
  554. rc = ber_put_seqorset( ber );
  555. break;
  556. default: {
  557. char msg[80];
  558. sprintf( msg, "unknown fmt %c\n", *fmt );
  559. ber_err_print( msg );
  560. rc = -1;
  561. break;
  562. }
  563. }
  564. if ( ber->ber_usertag == 0 )
  565. ber->ber_tag = LBER_DEFAULT;
  566. else
  567. ber->ber_usertag = 0;
  568. }
  569. va_end( ap );
  570. return( rc );
  571. }