Bug Summary

File:src/lib/libcrypto/asn1/asn_mime.c
Warning:line 681, column 10
Although the value stored to 'len' is used in the enclosing expression, the value is never actually read from 'len'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name asn_mime.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/lib/libcrypto/obj -resource-dir /usr/local/llvm16/lib/clang/16 -D LIBRESSL_INTERNAL -D HAVE_FUNOPEN -I /usr/src/lib/libcrypto -I /usr/src/lib/libcrypto/arch/amd64 -I /usr/src/lib/libcrypto/asn1 -I /usr/src/lib/libcrypto/bio -I /usr/src/lib/libcrypto/bn -I /usr/src/lib/libcrypto/bn/arch/amd64 -I /usr/src/lib/libcrypto/bytestring -I /usr/src/lib/libcrypto/curve25519 -I /usr/src/lib/libcrypto/dh -I /usr/src/lib/libcrypto/dsa -I /usr/src/lib/libcrypto/ec -I /usr/src/lib/libcrypto/ecdsa -I /usr/src/lib/libcrypto/evp -I /usr/src/lib/libcrypto/hidden -I /usr/src/lib/libcrypto/hmac -I /usr/src/lib/libcrypto/kdf -I /usr/src/lib/libcrypto/modes -I /usr/src/lib/libcrypto/ocsp -I /usr/src/lib/libcrypto/pkcs12 -I /usr/src/lib/libcrypto/rsa -I /usr/src/lib/libcrypto/sha -I /usr/src/lib/libcrypto/ts -I /usr/src/lib/libcrypto/x509 -I /usr/src/lib/libcrypto/obj -D AES_ASM -D BSAES_ASM -D VPAES_ASM -D OPENSSL_IA32_SSE2 -D RSA_ASM -D OPENSSL_BN_ASM_MONT -D OPENSSL_BN_ASM_MONT5 -D MD5_ASM -D GHASH_ASM -D RC4_MD5_ASM -D SHA1_ASM -D SHA256_ASM -D SHA512_ASM -D WHIRLPOOL_ASM -D OPENSSL_CPUID_OBJ -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/lib/libcrypto/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/lib/libcrypto/asn1/asn_mime.c
1/* $OpenBSD: asn_mime.c,v 1.32 2023/07/05 21:23:36 beck Exp $ */
2/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3 * project.
4 */
5/* ====================================================================
6 * Copyright (c) 1999-2008 The OpenSSL Project. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. All advertising materials mentioning features or use of this
21 * software must display the following acknowledgment:
22 * "This product includes software developed by the OpenSSL Project
23 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24 *
25 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26 * endorse or promote products derived from this software without
27 * prior written permission. For written permission, please contact
28 * licensing@OpenSSL.org.
29 *
30 * 5. Products derived from this software may not be called "OpenSSL"
31 * nor may "OpenSSL" appear in their names without prior written
32 * permission of the OpenSSL Project.
33 *
34 * 6. Redistributions of any form whatsoever must retain the following
35 * acknowledgment:
36 * "This product includes software developed by the OpenSSL Project
37 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38 *
39 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50 * OF THE POSSIBILITY OF SUCH DAMAGE.
51 * ====================================================================
52 *
53 */
54
55#include <ctype.h>
56#include <stdio.h>
57#include <stdlib.h>
58#include <string.h>
59
60#include <openssl/asn1.h>
61#include <openssl/asn1t.h>
62#include <openssl/err.h>
63#include <openssl/x509.h>
64
65#include "asn1_local.h"
66#include "evp_local.h"
67
68/* Generalised MIME like utilities for streaming ASN1. Although many
69 * have a PKCS7/CMS like flavour others are more general purpose.
70 */
71
72/* MIME format structures
73 * Note that all are translated to lower case apart from
74 * parameter values. Quotes are stripped off
75 */
76
77typedef struct {
78 char *param_name; /* Param name e.g. "micalg" */
79 char *param_value; /* Param value e.g. "sha1" */
80} MIME_PARAM;
81
82DECLARE_STACK_OF(MIME_PARAM)struct stack_st_MIME_PARAM { _STACK stack; };
83
84typedef struct {
85 char *name; /* Name of line e.g. "content-type" */
86 char *value; /* Value of line e.g. "text/plain" */
87 STACK_OF(MIME_PARAM)struct stack_st_MIME_PARAM *params; /* Zero or more parameters */
88} MIME_HEADER;
89
90DECLARE_STACK_OF(MIME_HEADER)struct stack_st_MIME_HEADER { _STACK stack; };
91
92static int asn1_output_data(BIO *out, BIO *data, ASN1_VALUE *val, int flags,
93 const ASN1_ITEM *it);
94static char * strip_ends(char *name);
95static char * strip_start(char *name);
96static char * strip_end(char *name);
97static MIME_HEADER *mime_hdr_new(char *name, char *value);
98static int mime_hdr_addparam(MIME_HEADER *mhdr, char *name, char *value);
99static STACK_OF(MIME_HEADER)struct stack_st_MIME_HEADER *mime_parse_hdr(BIO *bio);
100static int mime_hdr_cmp(const MIME_HEADER * const *a,
101 const MIME_HEADER * const *b);
102static int mime_param_cmp(const MIME_PARAM * const *a,
103 const MIME_PARAM * const *b);
104static void mime_param_free(MIME_PARAM *param);
105static int mime_bound_check(char *line, int linelen, char *bound, int blen);
106static int multi_split(BIO *bio, char *bound, STACK_OF(BIO)struct stack_st_BIO **ret);
107static int strip_eol(char *linebuf, int *plen);
108static MIME_HEADER *mime_hdr_find(STACK_OF(MIME_HEADER)struct stack_st_MIME_HEADER *hdrs, char *name);
109static MIME_PARAM *mime_param_find(MIME_HEADER *hdr, char *name);
110static void mime_hdr_free(MIME_HEADER *hdr);
111
112#define MAX_SMLEN1024 1024
113#define mime_debug(x) /* x */
114
115/* Output an ASN1 structure in BER format streaming if necessary */
116
117int
118i2d_ASN1_bio_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags,
119 const ASN1_ITEM *it)
120{
121 /* If streaming create stream BIO and copy all content through it */
122 if (flags & SMIME_STREAM0x1000) {
123 BIO *bio, *tbio;
124 bio = BIO_new_NDEF(out, val, it);
125 if (!bio) {
126 ASN1error(ERR_R_MALLOC_FAILURE)ERR_put_error(13,(0xfff),((1|64)),"/usr/src/lib/libcrypto/asn1/asn_mime.c"
,126)
;
127 return 0;
128 }
129 SMIME_crlf_copy(in, bio, flags);
130 (void)BIO_flush(bio)(int)BIO_ctrl(bio,11,0,((void *)0));
131 /* Free up successive BIOs until we hit the old output BIO */
132 do {
133 tbio = BIO_pop(bio);
134 BIO_free(bio);
135 bio = tbio;
136 } while (bio != out);
137 }
138 /* else just write out ASN1 structure which will have all content
139 * stored internally
140 */
141 else
142 ASN1_item_i2d_bio(it, out, val);
143 return 1;
144}
145
146/* Base 64 read and write of ASN1 structure */
147
148static int
149B64_write_ASN1(BIO *out, ASN1_VALUE *val, BIO *in, int flags,
150 const ASN1_ITEM *it)
151{
152 BIO *b64;
153 int r;
154
155 b64 = BIO_new(BIO_f_base64());
156 if (!b64) {
157 ASN1error(ERR_R_MALLOC_FAILURE)ERR_put_error(13,(0xfff),((1|64)),"/usr/src/lib/libcrypto/asn1/asn_mime.c"
,157)
;
158 return 0;
159 }
160 /* prepend the b64 BIO so all data is base64 encoded.
161 */
162 out = BIO_push(b64, out);
163 r = i2d_ASN1_bio_stream(out, val, in, flags, it);
164 (void)BIO_flush(out)(int)BIO_ctrl(out,11,0,((void *)0));
165 BIO_pop(out);
166 BIO_free(b64);
167 return r;
168}
169
170/* Streaming ASN1 PEM write */
171
172int
173PEM_write_bio_ASN1_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags,
174 const char *hdr, const ASN1_ITEM *it)
175{
176 int r;
177
178 BIO_printf(out, "-----BEGIN %s-----\n", hdr);
179 r = B64_write_ASN1(out, val, in, flags, it);
180 BIO_printf(out, "-----END %s-----\n", hdr);
181 return r;
182}
183
184static ASN1_VALUE *
185b64_read_asn1(BIO *bio, const ASN1_ITEM *it)
186{
187 BIO *b64;
188 ASN1_VALUE *val;
189 if (!(b64 = BIO_new(BIO_f_base64()))) {
190 ASN1error(ERR_R_MALLOC_FAILURE)ERR_put_error(13,(0xfff),((1|64)),"/usr/src/lib/libcrypto/asn1/asn_mime.c"
,190)
;
191 return 0;
192 }
193 bio = BIO_push(b64, bio);
194 val = ASN1_item_d2i_bio(it, bio, NULL((void *)0));
195 if (!val)
196 ASN1error(ASN1_R_DECODE_ERROR)ERR_put_error(13,(0xfff),(110),"/usr/src/lib/libcrypto/asn1/asn_mime.c"
,196)
;
197 (void)BIO_flush(bio)(int)BIO_ctrl(bio,11,0,((void *)0));
198 bio = BIO_pop(bio);
199 BIO_free(b64);
200 return val;
201}
202
203/* Generate the MIME "micalg" parameter from RFC3851, RFC4490 */
204
205static int
206asn1_write_micalg(BIO *out, STACK_OF(X509_ALGOR)struct stack_st_X509_ALGOR *mdalgs)
207{
208 const EVP_MD *md;
209 int i, have_unknown = 0, write_comma, ret = 0, md_nid;
210
211 have_unknown = 0;
212 write_comma = 0;
213 for (i = 0; i < sk_X509_ALGOR_num(mdalgs)sk_num(((_STACK*) (1 ? (mdalgs) : (struct stack_st_X509_ALGOR
*)0)))
; i++) {
214 if (write_comma)
215 BIO_write(out, ",", 1);
216 write_comma = 1;
217 md_nid = OBJ_obj2nid(sk_X509_ALGOR_value(mdalgs, i)((X509_ALGOR *)sk_value(((_STACK*) (1 ? (mdalgs) : (struct stack_st_X509_ALGOR
*)0)), (i)))
->algorithm);
218 md = EVP_get_digestbynid(md_nid)EVP_get_digestbyname(OBJ_nid2sn(md_nid));
219 if (md && md->md_ctrl) {
220 int rv;
221 char *micstr;
222 rv = md->md_ctrl(NULL((void *)0), EVP_MD_CTRL_MICALG0x2, 0, &micstr);
223 if (rv > 0) {
224 BIO_puts(out, micstr);
225 free(micstr);
226 continue;
227 }
228 if (rv != -2)
229 goto err;
230 }
231 switch (md_nid) {
232 case NID_sha164:
233 BIO_puts(out, "sha1");
234 break;
235
236 case NID_md54:
237 BIO_puts(out, "md5");
238 break;
239
240 case NID_sha256672:
241 BIO_puts(out, "sha-256");
242 break;
243
244 case NID_sha384673:
245 BIO_puts(out, "sha-384");
246 break;
247
248 case NID_sha512674:
249 BIO_puts(out, "sha-512");
250 break;
251
252 case NID_id_GostR3411_94809:
253 BIO_puts(out, "gostr3411-94");
254 goto err;
255 break;
256
257 default:
258 if (have_unknown)
259 write_comma = 0;
260 else {
261 BIO_puts(out, "unknown");
262 have_unknown = 1;
263 }
264 break;
265
266 }
267 }
268
269 ret = 1;
270
271 err:
272 return ret;
273}
274
275/* SMIME sender */
276
277int
278SMIME_write_ASN1(BIO *bio, ASN1_VALUE *val, BIO *data, int flags,
279 int ctype_nid, int econt_nid, STACK_OF(X509_ALGOR)struct stack_st_X509_ALGOR *mdalgs,
280 const ASN1_ITEM *it)
281{
282 char bound[33], c;
283 int i;
284 const char *mime_prefix, *mime_eol, *cname = "smime.p7m";
285 const char *msg_type = NULL((void *)0);
286
287 if (flags & SMIME_OLDMIME0x400)
288 mime_prefix = "application/x-pkcs7-";
289 else
290 mime_prefix = "application/pkcs7-";
291
292 if (flags & SMIME_CRLFEOL0x800)
293 mime_eol = "\r\n";
294 else
295 mime_eol = "\n";
296 if ((flags & SMIME_DETACHED0x40) && data) {
297 /* We want multipart/signed */
298 /* Generate a random boundary */
299 arc4random_buf(bound, 32);
300 for (i = 0; i < 32; i++) {
301 c = bound[i] & 0xf;
302 if (c < 10)
303 c += '0';
304 else
305 c += 'A' - 10;
306 bound[i] = c;
307 }
308 bound[32] = 0;
309 BIO_printf(bio, "MIME-Version: 1.0%s", mime_eol);
310 BIO_printf(bio, "Content-Type: multipart/signed;");
311 BIO_printf(bio, " protocol=\"%ssignature\";", mime_prefix);
312 BIO_puts(bio, " micalg=\"");
313 asn1_write_micalg(bio, mdalgs);
314 BIO_printf(bio, "\"; boundary=\"----%s\"%s%s",
315 bound, mime_eol, mime_eol);
316 BIO_printf(bio, "This is an S/MIME signed message%s%s",
317 mime_eol, mime_eol);
318 /* Now write out the first part */
319 BIO_printf(bio, "------%s%s", bound, mime_eol);
320 if (!asn1_output_data(bio, data, val, flags, it))
321 return 0;
322 BIO_printf(bio, "%s------%s%s", mime_eol, bound, mime_eol);
323
324 /* Headers for signature */
325
326 BIO_printf(bio, "Content-Type: %ssignature;", mime_prefix);
327 BIO_printf(bio, " name=\"smime.p7s\"%s", mime_eol);
328 BIO_printf(bio, "Content-Transfer-Encoding: base64%s",
329 mime_eol);
330 BIO_printf(bio, "Content-Disposition: attachment;");
331 BIO_printf(bio, " filename=\"smime.p7s\"%s%s",
332 mime_eol, mime_eol);
333 B64_write_ASN1(bio, val, NULL((void *)0), 0, it);
334 BIO_printf(bio, "%s------%s--%s%s", mime_eol, bound,
335 mime_eol, mime_eol);
336 return 1;
337 }
338
339 /* Determine smime-type header */
340
341 if (ctype_nid == NID_pkcs7_enveloped23)
342 msg_type = "enveloped-data";
343 else if (ctype_nid == NID_pkcs7_signed22) {
344 if (econt_nid == NID_id_smime_ct_receipt204)
345 msg_type = "signed-receipt";
346 else if (sk_X509_ALGOR_num(mdalgs)sk_num(((_STACK*) (1 ? (mdalgs) : (struct stack_st_X509_ALGOR
*)0)))
>= 0)
347 msg_type = "signed-data";
348 else
349 msg_type = "certs-only";
350 } else if (ctype_nid == NID_id_smime_ct_compressedData786) {
351 msg_type = "compressed-data";
352 cname = "smime.p7z";
353 }
354 /* MIME headers */
355 BIO_printf(bio, "MIME-Version: 1.0%s", mime_eol);
356 BIO_printf(bio, "Content-Disposition: attachment;");
357 BIO_printf(bio, " filename=\"%s\"%s", cname, mime_eol);
358 BIO_printf(bio, "Content-Type: %smime;", mime_prefix);
359 if (msg_type)
360 BIO_printf(bio, " smime-type=%s;", msg_type);
361 BIO_printf(bio, " name=\"%s\"%s", cname, mime_eol);
362 BIO_printf(bio, "Content-Transfer-Encoding: base64%s%s",
363 mime_eol, mime_eol);
364 if (!B64_write_ASN1(bio, val, data, flags, it))
365 return 0;
366 BIO_printf(bio, "%s", mime_eol);
367 return 1;
368}
369
370/* Handle output of ASN1 data */
371
372
373static int
374asn1_output_data(BIO *out, BIO *data, ASN1_VALUE *val, int flags,
375 const ASN1_ITEM *it)
376{
377 BIO *tmpbio;
378 const ASN1_AUX *aux = it->funcs;
379 ASN1_STREAM_ARG sarg;
380 int rv = 1;
381
382 /* If data is not deteched or resigning then the output BIO is
383 * already set up to finalise when it is written through.
384 */
385 if (!(flags & SMIME_DETACHED0x40) || (flags & PKCS7_REUSE_DIGEST0x8000)) {
386 SMIME_crlf_copy(data, out, flags);
387 return 1;
388 }
389
390 if (!aux || !aux->asn1_cb) {
391 ASN1error(ASN1_R_STREAMING_NOT_SUPPORTED)ERR_put_error(13,(0xfff),(202),"/usr/src/lib/libcrypto/asn1/asn_mime.c"
,391)
;
392 return 0;
393 }
394
395 sarg.out = out;
396 sarg.ndef_bio = NULL((void *)0);
397 sarg.boundary = NULL((void *)0);
398
399 /* Let ASN1 code prepend any needed BIOs */
400
401 if (aux->asn1_cb(ASN1_OP_DETACHED_PRE12, &val, it, &sarg) <= 0)
402 return 0;
403
404 /* Copy data across, passing through filter BIOs for processing */
405 SMIME_crlf_copy(data, sarg.ndef_bio, flags);
406
407 /* Finalize structure */
408 if (aux->asn1_cb(ASN1_OP_DETACHED_POST13, &val, it, &sarg) <= 0)
409 rv = 0;
410
411 /* Now remove any digests prepended to the BIO */
412
413 while (sarg.ndef_bio != out) {
414 tmpbio = BIO_pop(sarg.ndef_bio);
415 BIO_free(sarg.ndef_bio);
416 sarg.ndef_bio = tmpbio;
417 }
418
419 return rv;
420}
421
422/* SMIME reader: handle multipart/signed and opaque signing.
423 * in multipart case the content is placed in a memory BIO
424 * pointed to by "bcont". In opaque this is set to NULL
425 */
426
427ASN1_VALUE *
428SMIME_read_ASN1(BIO *bio, BIO **bcont, const ASN1_ITEM *it)
429{
430 BIO *asnin;
431 STACK_OF(MIME_HEADER)struct stack_st_MIME_HEADER *headers = NULL((void *)0);
432 STACK_OF(BIO)struct stack_st_BIO *parts = NULL((void *)0);
433 MIME_HEADER *hdr;
434 MIME_PARAM *prm;
435 ASN1_VALUE *val;
436 int ret;
437
438 if (bcont)
439 *bcont = NULL((void *)0);
440
441 if (!(headers = mime_parse_hdr(bio))) {
442 ASN1error(ASN1_R_MIME_PARSE_ERROR)ERR_put_error(13,(0xfff),(207),"/usr/src/lib/libcrypto/asn1/asn_mime.c"
,442)
;
443 return NULL((void *)0);
444 }
445
446 if (!(hdr = mime_hdr_find(headers, "content-type")) || !hdr->value) {
447 sk_MIME_HEADER_pop_free(headers, mime_hdr_free)sk_pop_free(((_STACK*) (1 ? (headers) : (struct stack_st_MIME_HEADER
*)0)), ((void (*)(void *)) ((1 ? (mime_hdr_free) : (void (*)(
MIME_HEADER *))0))))
;
448 ASN1error(ASN1_R_NO_CONTENT_TYPE)ERR_put_error(13,(0xfff),(209),"/usr/src/lib/libcrypto/asn1/asn_mime.c"
,448)
;
449 return NULL((void *)0);
450 }
451
452 /* Handle multipart/signed */
453
454 if (!strcmp(hdr->value, "multipart/signed")) {
455 /* Split into two parts */
456 prm = mime_param_find(hdr, "boundary");
457 if (!prm || !prm->param_value) {
458 sk_MIME_HEADER_pop_free(headers, mime_hdr_free)sk_pop_free(((_STACK*) (1 ? (headers) : (struct stack_st_MIME_HEADER
*)0)), ((void (*)(void *)) ((1 ? (mime_hdr_free) : (void (*)(
MIME_HEADER *))0))))
;
459 ASN1error(ASN1_R_NO_MULTIPART_BOUNDARY)ERR_put_error(13,(0xfff),(211),"/usr/src/lib/libcrypto/asn1/asn_mime.c"
,459)
;
460 return NULL((void *)0);
461 }
462 ret = multi_split(bio, prm->param_value, &parts);
463 sk_MIME_HEADER_pop_free(headers, mime_hdr_free)sk_pop_free(((_STACK*) (1 ? (headers) : (struct stack_st_MIME_HEADER
*)0)), ((void (*)(void *)) ((1 ? (mime_hdr_free) : (void (*)(
MIME_HEADER *))0))))
;
464 if (!ret || (sk_BIO_num(parts)sk_num(((_STACK*) (1 ? (parts) : (struct stack_st_BIO*)0))) != 2) ) {
465 ASN1error(ASN1_R_NO_MULTIPART_BODY_FAILURE)ERR_put_error(13,(0xfff),(210),"/usr/src/lib/libcrypto/asn1/asn_mime.c"
,465)
;
466 sk_BIO_pop_free(parts, BIO_vfree)sk_pop_free(((_STACK*) (1 ? (parts) : (struct stack_st_BIO*)0
)), ((void (*)(void *)) ((1 ? (BIO_vfree) : (void (*)(BIO *))
0))))
;
467 return NULL((void *)0);
468 }
469
470 /* Parse the signature piece */
471 asnin = sk_BIO_value(parts, 1)((BIO *)sk_value(((_STACK*) (1 ? (parts) : (struct stack_st_BIO
*)0)), (1)))
;
472
473 if (!(headers = mime_parse_hdr(asnin))) {
474 ASN1error(ASN1_R_MIME_SIG_PARSE_ERROR)ERR_put_error(13,(0xfff),(208),"/usr/src/lib/libcrypto/asn1/asn_mime.c"
,474)
;
475 sk_BIO_pop_free(parts, BIO_vfree)sk_pop_free(((_STACK*) (1 ? (parts) : (struct stack_st_BIO*)0
)), ((void (*)(void *)) ((1 ? (BIO_vfree) : (void (*)(BIO *))
0))))
;
476 return NULL((void *)0);
477 }
478
479 /* Get content type */
480
481 if (!(hdr = mime_hdr_find(headers, "content-type")) ||
482 !hdr->value) {
483 sk_MIME_HEADER_pop_free(headers, mime_hdr_free)sk_pop_free(((_STACK*) (1 ? (headers) : (struct stack_st_MIME_HEADER
*)0)), ((void (*)(void *)) ((1 ? (mime_hdr_free) : (void (*)(
MIME_HEADER *))0))))
;
484 sk_BIO_pop_free(parts, BIO_vfree)sk_pop_free(((_STACK*) (1 ? (parts) : (struct stack_st_BIO*)0
)), ((void (*)(void *)) ((1 ? (BIO_vfree) : (void (*)(BIO *))
0))))
;
485 ASN1error(ASN1_R_NO_SIG_CONTENT_TYPE)ERR_put_error(13,(0xfff),(212),"/usr/src/lib/libcrypto/asn1/asn_mime.c"
,485)
;
486 return NULL((void *)0);
487 }
488
489 if (strcmp(hdr->value, "application/x-pkcs7-signature") &&
490 strcmp(hdr->value, "application/pkcs7-signature")) {
491 ASN1error(ASN1_R_SIG_INVALID_MIME_TYPE)ERR_put_error(13,(0xfff),(213),"/usr/src/lib/libcrypto/asn1/asn_mime.c"
,491)
;
492 ERR_asprintf_error_data("type: %s", hdr->value);
493 sk_MIME_HEADER_pop_free(headers, mime_hdr_free)sk_pop_free(((_STACK*) (1 ? (headers) : (struct stack_st_MIME_HEADER
*)0)), ((void (*)(void *)) ((1 ? (mime_hdr_free) : (void (*)(
MIME_HEADER *))0))))
;
494 sk_BIO_pop_free(parts, BIO_vfree)sk_pop_free(((_STACK*) (1 ? (parts) : (struct stack_st_BIO*)0
)), ((void (*)(void *)) ((1 ? (BIO_vfree) : (void (*)(BIO *))
0))))
;
495 return NULL((void *)0);
496 }
497 sk_MIME_HEADER_pop_free(headers, mime_hdr_free)sk_pop_free(((_STACK*) (1 ? (headers) : (struct stack_st_MIME_HEADER
*)0)), ((void (*)(void *)) ((1 ? (mime_hdr_free) : (void (*)(
MIME_HEADER *))0))))
;
498 /* Read in ASN1 */
499 if (!(val = b64_read_asn1(asnin, it))) {
500 ASN1error(ASN1_R_ASN1_SIG_PARSE_ERROR)ERR_put_error(13,(0xfff),(204),"/usr/src/lib/libcrypto/asn1/asn_mime.c"
,500)
;
501 sk_BIO_pop_free(parts, BIO_vfree)sk_pop_free(((_STACK*) (1 ? (parts) : (struct stack_st_BIO*)0
)), ((void (*)(void *)) ((1 ? (BIO_vfree) : (void (*)(BIO *))
0))))
;
502 return NULL((void *)0);
503 }
504
505 if (bcont) {
506 *bcont = sk_BIO_value(parts, 0)((BIO *)sk_value(((_STACK*) (1 ? (parts) : (struct stack_st_BIO
*)0)), (0)))
;
507 BIO_free(asnin);
508 sk_BIO_free(parts)sk_free(((_STACK*) (1 ? (parts) : (struct stack_st_BIO*)0)));
509 } else sk_BIO_pop_free(parts, BIO_vfree)sk_pop_free(((_STACK*) (1 ? (parts) : (struct stack_st_BIO*)0
)), ((void (*)(void *)) ((1 ? (BIO_vfree) : (void (*)(BIO *))
0))))
;
510 return val;
511 }
512
513 /* OK, if not multipart/signed try opaque signature */
514
515 if (strcmp (hdr->value, "application/x-pkcs7-mime") &&
516 strcmp (hdr->value, "application/pkcs7-mime")) {
517 ASN1error(ASN1_R_INVALID_MIME_TYPE)ERR_put_error(13,(0xfff),(205),"/usr/src/lib/libcrypto/asn1/asn_mime.c"
,517)
;
518 ERR_asprintf_error_data("type: %s", hdr->value);
519 sk_MIME_HEADER_pop_free(headers, mime_hdr_free)sk_pop_free(((_STACK*) (1 ? (headers) : (struct stack_st_MIME_HEADER
*)0)), ((void (*)(void *)) ((1 ? (mime_hdr_free) : (void (*)(
MIME_HEADER *))0))))
;
520 return NULL((void *)0);
521 }
522
523 sk_MIME_HEADER_pop_free(headers, mime_hdr_free)sk_pop_free(((_STACK*) (1 ? (headers) : (struct stack_st_MIME_HEADER
*)0)), ((void (*)(void *)) ((1 ? (mime_hdr_free) : (void (*)(
MIME_HEADER *))0))))
;
524
525 if (!(val = b64_read_asn1(bio, it))) {
526 ASN1error(ASN1_R_ASN1_PARSE_ERROR)ERR_put_error(13,(0xfff),(203),"/usr/src/lib/libcrypto/asn1/asn_mime.c"
,526)
;
527 return NULL((void *)0);
528 }
529 return val;
530}
531
532/* Copy text from one BIO to another making the output CRLF at EOL */
533int
534SMIME_crlf_copy(BIO *in, BIO *out, int flags)
535{
536 BIO *bf;
537 char eol;
538 int len;
539 char linebuf[MAX_SMLEN1024];
540
541 /* Buffer output so we don't write one line at a time. This is
542 * useful when streaming as we don't end up with one OCTET STRING
543 * per line.
544 */
545 bf = BIO_new(BIO_f_buffer());
546 if (!bf)
547 return 0;
548 out = BIO_push(bf, out);
549 if (flags & SMIME_BINARY0x80) {
550 while ((len = BIO_read(in, linebuf, MAX_SMLEN1024)) > 0)
551 BIO_write(out, linebuf, len);
552 } else {
553 if (flags & SMIME_TEXT0x1)
554 BIO_printf(out, "Content-Type: text/plain\r\n\r\n");
555 while ((len = BIO_gets(in, linebuf, MAX_SMLEN1024)) > 0) {
556 eol = strip_eol(linebuf, &len);
557 if (len)
558 BIO_write(out, linebuf, len);
559 if (eol)
560 BIO_write(out, "\r\n", 2);
561 }
562 }
563 (void)BIO_flush(out)(int)BIO_ctrl(out,11,0,((void *)0));
564 BIO_pop(out);
565 BIO_free(bf);
566 return 1;
567}
568LCRYPTO_ALIAS(SMIME_crlf_copy)asm("");
569
570/* Strip off headers if they are text/plain */
571int
572SMIME_text(BIO *in, BIO *out)
573{
574 char iobuf[4096];
575 int len;
576 STACK_OF(MIME_HEADER)struct stack_st_MIME_HEADER *headers;
577 MIME_HEADER *hdr;
578
579 if (!(headers = mime_parse_hdr(in))) {
580 ASN1error(ASN1_R_MIME_PARSE_ERROR)ERR_put_error(13,(0xfff),(207),"/usr/src/lib/libcrypto/asn1/asn_mime.c"
,580)
;
581 return 0;
582 }
583 if (!(hdr = mime_hdr_find(headers, "content-type")) || !hdr->value) {
584 ASN1error(ASN1_R_MIME_NO_CONTENT_TYPE)ERR_put_error(13,(0xfff),(206),"/usr/src/lib/libcrypto/asn1/asn_mime.c"
,584)
;
585 sk_MIME_HEADER_pop_free(headers, mime_hdr_free)sk_pop_free(((_STACK*) (1 ? (headers) : (struct stack_st_MIME_HEADER
*)0)), ((void (*)(void *)) ((1 ? (mime_hdr_free) : (void (*)(
MIME_HEADER *))0))))
;
586 return 0;
587 }
588 if (strcmp (hdr->value, "text/plain")) {
589 ASN1error(ASN1_R_INVALID_MIME_TYPE)ERR_put_error(13,(0xfff),(205),"/usr/src/lib/libcrypto/asn1/asn_mime.c"
,589)
;
590 ERR_asprintf_error_data("type: %s", hdr->value);
591 sk_MIME_HEADER_pop_free(headers, mime_hdr_free)sk_pop_free(((_STACK*) (1 ? (headers) : (struct stack_st_MIME_HEADER
*)0)), ((void (*)(void *)) ((1 ? (mime_hdr_free) : (void (*)(
MIME_HEADER *))0))))
;
592 return 0;
593 }
594 sk_MIME_HEADER_pop_free(headers, mime_hdr_free)sk_pop_free(((_STACK*) (1 ? (headers) : (struct stack_st_MIME_HEADER
*)0)), ((void (*)(void *)) ((1 ? (mime_hdr_free) : (void (*)(
MIME_HEADER *))0))))
;
595 while ((len = BIO_read(in, iobuf, sizeof(iobuf))) > 0)
596 BIO_write(out, iobuf, len);
597 if (len < 0)
598 return 0;
599 return 1;
600}
601LCRYPTO_ALIAS(SMIME_text)asm("");
602
603/*
604 * Split a multipart/XXX message body into component parts: result is
605 * canonical parts in a STACK of bios
606 */
607static int
608multi_split(BIO *bio, char *bound, STACK_OF(BIO)struct stack_st_BIO **ret)
609{
610 char linebuf[MAX_SMLEN1024];
611 int len, blen;
612 int eol = 0, next_eol = 0;
613 BIO *bpart = NULL((void *)0);
614 STACK_OF(BIO)struct stack_st_BIO *parts;
615 char state, part, first;
616
617 blen = strlen(bound);
618 part = 0;
619 state = 0;
620 first = 1;
621 parts = sk_BIO_new_null()((struct stack_st_BIO *)sk_new_null());
622 *ret = parts;
623 if (parts == NULL((void *)0))
624 return 0;
625 while ((len = BIO_gets(bio, linebuf, MAX_SMLEN1024)) > 0) {
626 state = mime_bound_check(linebuf, len, bound, blen);
627 if (state == 1) {
628 first = 1;
629 part++;
630 } else if (state == 2) {
631 if (sk_BIO_push(parts, bpart)sk_push(((_STACK*) (1 ? (parts) : (struct stack_st_BIO*)0)), (
(void*) (1 ? (bpart) : (BIO*)0)))
== 0)
632 return 0;
633 return 1;
634 } else if (part) {
635 /* Strip CR+LF from linebuf */
636 next_eol = strip_eol(linebuf, &len);
637 if (first) {
638 first = 0;
639 if (bpart != NULL((void *)0)) {
640 if (sk_BIO_push(parts, bpart)sk_push(((_STACK*) (1 ? (parts) : (struct stack_st_BIO*)0)), (
(void*) (1 ? (bpart) : (BIO*)0)))
== 0)
641 return 0;
642 }
643 bpart = BIO_new(BIO_s_mem());
644 if (bpart == NULL((void *)0))
645 return 0;
646 BIO_set_mem_eof_return(bpart, 0)BIO_ctrl(bpart,130,0,((void *)0));
647 } else if (eol)
648 BIO_write(bpart, "\r\n", 2);
649 eol = next_eol;
650 if (len)
651 BIO_write(bpart, linebuf, len);
652 }
653 }
654 BIO_free(bpart);
655 return 0;
656}
657
658/* This is the big one: parse MIME header lines up to message body */
659
660#define MIME_INVALID0 0
661#define MIME_START1 1
662#define MIME_TYPE2 2
663#define MIME_NAME3 3
664#define MIME_VALUE4 4
665#define MIME_QUOTE5 5
666#define MIME_COMMENT6 6
667
668static STACK_OF(MIME_HEADER)struct stack_st_MIME_HEADER *
669mime_parse_hdr(BIO *bio)
670{
671 char *p, *q, c;
672 char *ntmp;
673 char linebuf[MAX_SMLEN1024];
674 MIME_HEADER *mhdr = NULL((void *)0);
675 STACK_OF(MIME_HEADER)struct stack_st_MIME_HEADER *headers;
676 int len, state, save_state = 0;
677
678 headers = sk_MIME_HEADER_new(mime_hdr_cmp)((struct stack_st_MIME_HEADER *)sk_new(((int (*)(const void *
, const void *)) ((1 ? (mime_hdr_cmp) : (int (*)(const MIME_HEADER
* const *, const MIME_HEADER * const *))0)))))
;
679 if (!headers)
680 return NULL((void *)0);
681 while ((len = BIO_gets(bio, linebuf, MAX_SMLEN1024)) > 0) {
Although the value stored to 'len' is used in the enclosing expression, the value is never actually read from 'len'
682 /* If whitespace at line start then continuation line */
683 if (mhdr && isspace((unsigned char)linebuf[0]))
684 state = MIME_NAME3;
685 else
686 state = MIME_START1;
687 ntmp = NULL((void *)0);
688
689 /* Go through all characters */
690 for (p = linebuf, q = linebuf;
691 (c = *p) && (c != '\r') && (c != '\n'); p++) {
692
693 /* State machine to handle MIME headers
694 * if this looks horrible that's because it *is*
695 */
696
697 switch (state) {
698 case MIME_START1:
699 if (c == ':') {
700 state = MIME_TYPE2;
701 *p = 0;
702 ntmp = strip_ends(q);
703 q = p + 1;
704 }
705 break;
706
707 case MIME_TYPE2:
708 if (c == ';') {
709 mime_debug("Found End Value\n");
710 *p = 0;
711 mhdr = mime_hdr_new(ntmp,
712 strip_ends(q));
713 if (mhdr == NULL((void *)0))
714 goto merr;
715 if (sk_MIME_HEADER_push(headers,sk_push(((_STACK*) (1 ? (headers) : (struct stack_st_MIME_HEADER
*)0)), ((void*) (1 ? (mhdr) : (MIME_HEADER*)0)))
716 mhdr)sk_push(((_STACK*) (1 ? (headers) : (struct stack_st_MIME_HEADER
*)0)), ((void*) (1 ? (mhdr) : (MIME_HEADER*)0)))
== 0)
717 goto merr;
718 ntmp = NULL((void *)0);
719 q = p + 1;
720 state = MIME_NAME3;
721 } else if (c == '(') {
722 save_state = state;
723 state = MIME_COMMENT6;
724 }
725 break;
726
727 case MIME_COMMENT6:
728 if (c == ')') {
729 state = save_state;
730 }
731 break;
732
733 case MIME_NAME3:
734 if (c == '=') {
735 state = MIME_VALUE4;
736 *p = 0;
737 ntmp = strip_ends(q);
738 q = p + 1;
739 }
740 break;
741
742 case MIME_VALUE4:
743 if (c == ';') {
744 state = MIME_NAME3;
745 *p = 0;
746 mime_hdr_addparam(mhdr, ntmp,
747 strip_ends(q));
748 ntmp = NULL((void *)0);
749 q = p + 1;
750 } else if (c == '"') {
751 mime_debug("Found Quote\n");
752 state = MIME_QUOTE5;
753 } else if (c == '(') {
754 save_state = state;
755 state = MIME_COMMENT6;
756 }
757 break;
758
759 case MIME_QUOTE5:
760 if (c == '"') {
761 mime_debug("Found Match Quote\n");
762 state = MIME_VALUE4;
763 }
764 break;
765 }
766 }
767
768 if (state == MIME_TYPE2) {
769 mhdr = mime_hdr_new(ntmp, strip_ends(q));
770 if (mhdr == NULL((void *)0))
771 goto merr;
772 if (sk_MIME_HEADER_push(headers, mhdr)sk_push(((_STACK*) (1 ? (headers) : (struct stack_st_MIME_HEADER
*)0)), ((void*) (1 ? (mhdr) : (MIME_HEADER*)0)))
== 0)
773 goto merr;
774 } else if (state == MIME_VALUE4)
775 mime_hdr_addparam(mhdr, ntmp, strip_ends(q));
776
777 if (p == linebuf)
778 break; /* Blank line means end of headers */
779 }
780
781 return headers;
782
783 merr:
784 if (mhdr != NULL((void *)0))
785 mime_hdr_free(mhdr);
786 sk_MIME_HEADER_pop_free(headers, mime_hdr_free)sk_pop_free(((_STACK*) (1 ? (headers) : (struct stack_st_MIME_HEADER
*)0)), ((void (*)(void *)) ((1 ? (mime_hdr_free) : (void (*)(
MIME_HEADER *))0))))
;
787 return NULL((void *)0);
788}
789
790static char *
791strip_ends(char *name)
792{
793 return strip_end(strip_start(name));
794}
795
796/* Strip a parameter of whitespace from start of param */
797static char *
798strip_start(char *name)
799{
800 char *p, c;
801
802 /* Look for first non white space or quote */
803 for (p = name; (c = *p); p++) {
804 if (c == '"') {
805 /* Next char is start of string if non null */
806 if (p[1])
807 return p + 1;
808 /* Else null string */
809 return NULL((void *)0);
810 }
811 if (!isspace((unsigned char)c))
812 return p;
813 }
814 return NULL((void *)0);
815}
816
817/* As above but strip from end of string : maybe should handle brackets? */
818static char *
819strip_end(char *name)
820{
821 char *p, c;
822
823 if (!name)
824 return NULL((void *)0);
825
826 /* Look for first non white space or quote */
827 for (p = name + strlen(name) - 1; p >= name; p--) {
828 c = *p;
829 if (c == '"') {
830 if (p - 1 == name)
831 return NULL((void *)0);
832 *p = 0;
833 return name;
834 }
835 if (isspace((unsigned char)c))
836 *p = 0;
837 else
838 return name;
839 }
840 return NULL((void *)0);
841}
842
843static MIME_HEADER *
844mime_hdr_new(char *name, char *value)
845{
846 MIME_HEADER *mhdr;
847 char *tmpname = NULL((void *)0), *tmpval = NULL((void *)0), *p;
848
849 if (name) {
850 if (!(tmpname = strdup(name)))
851 goto err;
852 for (p = tmpname; *p; p++)
853 *p = tolower((unsigned char)*p);
854 }
855 if (value) {
856 if (!(tmpval = strdup(value)))
857 goto err;
858 for (p = tmpval; *p; p++)
859 *p = tolower((unsigned char)*p);
860 }
861 mhdr = malloc(sizeof(MIME_HEADER));
862 if (!mhdr)
863 goto err;
864 mhdr->name = tmpname;
865 mhdr->value = tmpval;
866 if (!(mhdr->params = sk_MIME_PARAM_new(mime_param_cmp)((struct stack_st_MIME_PARAM *)sk_new(((int (*)(const void *,
const void *)) ((1 ? (mime_param_cmp) : (int (*)(const MIME_PARAM
* const *, const MIME_PARAM * const *))0)))))
)) {
867 free(mhdr);
868 goto err;
869 }
870 return mhdr;
871 err:
872 free(tmpname);
873 free(tmpval);
874 return NULL((void *)0);
875}
876
877static int
878mime_hdr_addparam(MIME_HEADER *mhdr, char *name, char *value)
879{
880 char *tmpname = NULL((void *)0), *tmpval = NULL((void *)0), *p;
881 MIME_PARAM *mparam;
882
883 if (name) {
884 tmpname = strdup(name);
885 if (!tmpname)
886 goto err;
887 for (p = tmpname; *p; p++)
888 *p = tolower((unsigned char)*p);
889 }
890 if (value) {
891 tmpval = strdup(value);
892 if (!tmpval)
893 goto err;
894 }
895 /* Parameter values are case sensitive so leave as is */
896 mparam = malloc(sizeof(MIME_PARAM));
897 if (!mparam)
898 goto err;
899 mparam->param_name = tmpname;
900 mparam->param_value = tmpval;
901 if (sk_MIME_PARAM_push(mhdr->params, mparam)sk_push(((_STACK*) (1 ? (mhdr->params) : (struct stack_st_MIME_PARAM
*)0)), ((void*) (1 ? (mparam) : (MIME_PARAM*)0)))
== 0) {
902 free(mparam);
903 goto err;
904 }
905 return 1;
906 err:
907 free(tmpname);
908 free(tmpval);
909 return 0;
910}
911
912static int
913mime_hdr_cmp(const MIME_HEADER * const *a, const MIME_HEADER * const *b)
914{
915 if (!(*a)->name || !(*b)->name)
916 return !!(*a)->name - !!(*b)->name;
917 return (strcmp((*a)->name, (*b)->name));
918}
919
920static int
921mime_param_cmp(const MIME_PARAM * const *a, const MIME_PARAM * const *b)
922{
923 if (!(*a)->param_name || !(*b)->param_name)
924 return !!(*a)->param_name - !!(*b)->param_name;
925 return (strcmp((*a)->param_name, (*b)->param_name));
926}
927
928/* Find a header with a given name (if possible) */
929
930static MIME_HEADER *
931mime_hdr_find(STACK_OF(MIME_HEADER)struct stack_st_MIME_HEADER *hdrs, char *name)
932{
933 MIME_HEADER htmp;
934 int idx;
935 htmp.name = name;
936 idx = sk_MIME_HEADER_find(hdrs, &htmp)sk_find(((_STACK*) (1 ? (hdrs) : (struct stack_st_MIME_HEADER
*)0)), ((void*) (1 ? (&htmp) : (MIME_HEADER*)0)))
;
937 if (idx < 0)
938 return NULL((void *)0);
939 return sk_MIME_HEADER_value(hdrs, idx)((MIME_HEADER *)sk_value(((_STACK*) (1 ? (hdrs) : (struct stack_st_MIME_HEADER
*)0)), (idx)))
;
940}
941
942static MIME_PARAM *
943mime_param_find(MIME_HEADER *hdr, char *name)
944{
945 MIME_PARAM param;
946 int idx;
947 param.param_name = name;
948 idx = sk_MIME_PARAM_find(hdr->params, &param)sk_find(((_STACK*) (1 ? (hdr->params) : (struct stack_st_MIME_PARAM
*)0)), ((void*) (1 ? (&param) : (MIME_PARAM*)0)))
;
949 if (idx < 0)
950 return NULL((void *)0);
951 return sk_MIME_PARAM_value(hdr->params, idx)((MIME_PARAM *)sk_value(((_STACK*) (1 ? (hdr->params) : (struct
stack_st_MIME_PARAM*)0)), (idx)))
;
952}
953
954static void
955mime_hdr_free(MIME_HEADER *hdr)
956{
957 free(hdr->name);
958 free(hdr->value);
959 if (hdr->params)
960 sk_MIME_PARAM_pop_free(hdr->params, mime_param_free)sk_pop_free(((_STACK*) (1 ? (hdr->params) : (struct stack_st_MIME_PARAM
*)0)), ((void (*)(void *)) ((1 ? (mime_param_free) : (void (*
)(MIME_PARAM *))0))))
;
961 free(hdr);
962}
963
964static void
965mime_param_free(MIME_PARAM *param)
966{
967 free(param->param_name);
968 free(param->param_value);
969 free(param);
970}
971
972/* Check for a multipart boundary. Returns:
973 * 0 : no boundary
974 * 1 : part boundary
975 * 2 : final boundary
976 */
977static int
978mime_bound_check(char *line, int linelen, char *bound, int blen)
979{
980 if (linelen == -1)
981 linelen = strlen(line);
982 if (blen == -1)
983 blen = strlen(bound);
984 /* Quickly eliminate if line length too short */
985 if (blen + 2 > linelen)
986 return 0;
987 /* Check for part boundary */
988 if (!strncmp(line, "--", 2) && !strncmp(line + 2, bound, blen)) {
989 if (!strncmp(line + blen + 2, "--", 2))
990 return 2;
991 else
992 return 1;
993 }
994 return 0;
995}
996
997static int
998strip_eol(char *linebuf, int *plen)
999{
1000 int len = *plen;
1001 char *p, c;
1002 int is_eol = 0;
1003
1004 for (p = linebuf + len - 1; len > 0; len--, p--) {
1005 c = *p;
1006 if (c == '\n')
1007 is_eol = 1;
1008 else if (c != '\r')
1009 break;
1010 }
1011 *plen = len;
1012 return is_eol;
1013}