Bug Summary

File:src/lib/libcrypto/asn1/asn_mime.c
Warning:line 680, 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.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name asn_mime.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -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 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -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/lib/clang/13.0.0 -D LIBRESSL_INTERNAL -D LIBRESSL_CRYPTO_INTERNAL -D DSO_DLFCN -D HAVE_DLFCN_H -D HAVE_FUNOPEN -D OPENSSL_NO_HW_PADLOCK -I /usr/src/lib/libcrypto -I /usr/src/lib/libcrypto/asn1 -I /usr/src/lib/libcrypto/bio -I /usr/src/lib/libcrypto/bn -I /usr/src/lib/libcrypto/bytestring -I /usr/src/lib/libcrypto/dh -I /usr/src/lib/libcrypto/dsa -I /usr/src/lib/libcrypto/ec -I /usr/src/lib/libcrypto/ecdh -I /usr/src/lib/libcrypto/ecdsa -I /usr/src/lib/libcrypto/evp -I /usr/src/lib/libcrypto/hmac -I /usr/src/lib/libcrypto/modes -I /usr/src/lib/libcrypto/ocsp -I /usr/src/lib/libcrypto/rsa -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 OPENSSL_BN_ASM_GF2m -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 -D PIC -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/lib/libcrypto/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -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/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/lib/libcrypto/asn1/asn_mime.c
1/* $OpenBSD: asn_mime.c,v 1.29 2021/12/25 13:17:48 jsing 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_locl.h"
66#include "evp_locl.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}
568
569/* Strip off headers if they are text/plain */
570int
571SMIME_text(BIO *in, BIO *out)
572{
573 char iobuf[4096];
574 int len;
575 STACK_OF(MIME_HEADER)struct stack_st_MIME_HEADER *headers;
576 MIME_HEADER *hdr;
577
578 if (!(headers = mime_parse_hdr(in))) {
579 ASN1error(ASN1_R_MIME_PARSE_ERROR)ERR_put_error(13,(0xfff),(207),"/usr/src/lib/libcrypto/asn1/asn_mime.c"
,579)
;
580 return 0;
581 }
582 if (!(hdr = mime_hdr_find(headers, "content-type")) || !hdr->value) {
583 ASN1error(ASN1_R_MIME_NO_CONTENT_TYPE)ERR_put_error(13,(0xfff),(206),"/usr/src/lib/libcrypto/asn1/asn_mime.c"
,583)
;
584 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))))
;
585 return 0;
586 }
587 if (strcmp (hdr->value, "text/plain")) {
588 ASN1error(ASN1_R_INVALID_MIME_TYPE)ERR_put_error(13,(0xfff),(205),"/usr/src/lib/libcrypto/asn1/asn_mime.c"
,588)
;
589 ERR_asprintf_error_data("type: %s", hdr->value);
590 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))))
;
591 return 0;
592 }
593 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))))
;
594 while ((len = BIO_read(in, iobuf, sizeof(iobuf))) > 0)
595 BIO_write(out, iobuf, len);
596 if (len < 0)
597 return 0;
598 return 1;
599}
600
601/*
602 * Split a multipart/XXX message body into component parts: result is
603 * canonical parts in a STACK of bios
604 */
605static int
606multi_split(BIO *bio, char *bound, STACK_OF(BIO)struct stack_st_BIO **ret)
607{
608 char linebuf[MAX_SMLEN1024];
609 int len, blen;
610 int eol = 0, next_eol = 0;
611 BIO *bpart = NULL((void*)0);
612 STACK_OF(BIO)struct stack_st_BIO *parts;
613 char state, part, first;
614
615 blen = strlen(bound);
616 part = 0;
617 state = 0;
618 first = 1;
619 parts = sk_BIO_new_null()((struct stack_st_BIO *)sk_new_null());
620 *ret = parts;
621 if (parts == NULL((void*)0))
622 return 0;
623 while ((len = BIO_gets(bio, linebuf, MAX_SMLEN1024)) > 0) {
624 state = mime_bound_check(linebuf, len, bound, blen);
625 if (state == 1) {
626 first = 1;
627 part++;
628 } else if (state == 2) {
629 if (sk_BIO_push(parts, bpart)sk_push(((_STACK*) (1 ? (parts) : (struct stack_st_BIO*)0)), (
(void*) (1 ? (bpart) : (BIO*)0)))
== 0)
630 return 0;
631 return 1;
632 } else if (part) {
633 /* Strip CR+LF from linebuf */
634 next_eol = strip_eol(linebuf, &len);
635 if (first) {
636 first = 0;
637 if (bpart != NULL((void*)0)) {
638 if (sk_BIO_push(parts, bpart)sk_push(((_STACK*) (1 ? (parts) : (struct stack_st_BIO*)0)), (
(void*) (1 ? (bpart) : (BIO*)0)))
== 0)
639 return 0;
640 }
641 bpart = BIO_new(BIO_s_mem());
642 if (bpart == NULL((void*)0))
643 return 0;
644 BIO_set_mem_eof_return(bpart, 0)BIO_ctrl(bpart,130,0,((void*)0));
645 } else if (eol)
646 BIO_write(bpart, "\r\n", 2);
647 eol = next_eol;
648 if (len)
649 BIO_write(bpart, linebuf, len);
650 }
651 }
652 BIO_free(bpart);
653 return 0;
654}
655
656/* This is the big one: parse MIME header lines up to message body */
657
658#define MIME_INVALID0 0
659#define MIME_START1 1
660#define MIME_TYPE2 2
661#define MIME_NAME3 3
662#define MIME_VALUE4 4
663#define MIME_QUOTE5 5
664#define MIME_COMMENT6 6
665
666
667static
668STACK_OF(MIME_HEADER)struct stack_st_MIME_HEADER *mime_parse_hdr(BIO *bio)
669{
670 char *p, *q, c;
671 char *ntmp;
672 char linebuf[MAX_SMLEN1024];
673 MIME_HEADER *mhdr = NULL((void*)0);
674 STACK_OF(MIME_HEADER)struct stack_st_MIME_HEADER *headers;
675 int len, state, save_state = 0;
676
677 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)))))
;
678 if (!headers)
679 return NULL((void*)0);
680 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'
681 /* If whitespace at line start then continuation line */
682 if (mhdr && isspace((unsigned char)linebuf[0]))
683 state = MIME_NAME3;
684 else
685 state = MIME_START1;
686 ntmp = NULL((void*)0);
687
688 /* Go through all characters */
689 for (p = linebuf, q = linebuf;
690 (c = *p) && (c != '\r') && (c != '\n'); p++) {
691
692 /* State machine to handle MIME headers
693 * if this looks horrible that's because it *is*
694 */
695
696 switch (state) {
697 case MIME_START1:
698 if (c == ':') {
699 state = MIME_TYPE2;
700 *p = 0;
701 ntmp = strip_ends(q);
702 q = p + 1;
703 }
704 break;
705
706 case MIME_TYPE2:
707 if (c == ';') {
708 mime_debug("Found End Value\n");
709 *p = 0;
710 mhdr = mime_hdr_new(ntmp,
711 strip_ends(q));
712 if (mhdr == NULL((void*)0))
713 goto merr;
714 if (sk_MIME_HEADER_push(headers,sk_push(((_STACK*) (1 ? (headers) : (struct stack_st_MIME_HEADER
*)0)), ((void*) (1 ? (mhdr) : (MIME_HEADER*)0)))
715 mhdr)sk_push(((_STACK*) (1 ? (headers) : (struct stack_st_MIME_HEADER
*)0)), ((void*) (1 ? (mhdr) : (MIME_HEADER*)0)))
== 0)
716 goto merr;
717 ntmp = NULL((void*)0);
718 q = p + 1;
719 state = MIME_NAME3;
720 } else if (c == '(') {
721 save_state = state;
722 state = MIME_COMMENT6;
723 }
724 break;
725
726 case MIME_COMMENT6:
727 if (c == ')') {
728 state = save_state;
729 }
730 break;
731
732 case MIME_NAME3:
733 if (c == '=') {
734 state = MIME_VALUE4;
735 *p = 0;
736 ntmp = strip_ends(q);
737 q = p + 1;
738 }
739 break;
740
741 case MIME_VALUE4:
742 if (c == ';') {
743 state = MIME_NAME3;
744 *p = 0;
745 mime_hdr_addparam(mhdr, ntmp,
746 strip_ends(q));
747 ntmp = NULL((void*)0);
748 q = p + 1;
749 } else if (c == '"') {
750 mime_debug("Found Quote\n");
751 state = MIME_QUOTE5;
752 } else if (c == '(') {
753 save_state = state;
754 state = MIME_COMMENT6;
755 }
756 break;
757
758 case MIME_QUOTE5:
759 if (c == '"') {
760 mime_debug("Found Match Quote\n");
761 state = MIME_VALUE4;
762 }
763 break;
764 }
765 }
766
767 if (state == MIME_TYPE2) {
768 mhdr = mime_hdr_new(ntmp, strip_ends(q));
769 if (mhdr == NULL((void*)0))
770 goto merr;
771 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)
772 goto merr;
773 } else if (state == MIME_VALUE4)
774 mime_hdr_addparam(mhdr, ntmp, strip_ends(q));
775
776 if (p == linebuf)
777 break; /* Blank line means end of headers */
778 }
779
780 return headers;
781
782 merr:
783 if (mhdr != NULL((void*)0))
784 mime_hdr_free(mhdr);
785 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))))
;
786 return NULL((void*)0);
787}
788
789static char *
790strip_ends(char *name)
791{
792 return strip_end(strip_start(name));
793}
794
795/* Strip a parameter of whitespace from start of param */
796static char *
797strip_start(char *name)
798{
799 char *p, c;
800
801 /* Look for first non white space or quote */
802 for (p = name; (c = *p); p++) {
803 if (c == '"') {
804 /* Next char is start of string if non null */
805 if (p[1])
806 return p + 1;
807 /* Else null string */
808 return NULL((void*)0);
809 }
810 if (!isspace((unsigned char)c))
811 return p;
812 }
813 return NULL((void*)0);
814}
815
816/* As above but strip from end of string : maybe should handle brackets? */
817static char *
818strip_end(char *name)
819{
820 char *p, c;
821
822 if (!name)
823 return NULL((void*)0);
824
825 /* Look for first non white space or quote */
826 for (p = name + strlen(name) - 1; p >= name; p--) {
827 c = *p;
828 if (c == '"') {
829 if (p - 1 == name)
830 return NULL((void*)0);
831 *p = 0;
832 return name;
833 }
834 if (isspace((unsigned char)c))
835 *p = 0;
836 else
837 return name;
838 }
839 return NULL((void*)0);
840}
841
842static MIME_HEADER *
843mime_hdr_new(char *name, char *value)
844{
845 MIME_HEADER *mhdr;
846 char *tmpname = NULL((void*)0), *tmpval = NULL((void*)0), *p;
847
848 if (name) {
849 if (!(tmpname = strdup(name)))
850 goto err;
851 for (p = tmpname; *p; p++)
852 *p = tolower((unsigned char)*p);
853 }
854 if (value) {
855 if (!(tmpval = strdup(value)))
856 goto err;
857 for (p = tmpval; *p; p++)
858 *p = tolower((unsigned char)*p);
859 }
860 mhdr = malloc(sizeof(MIME_HEADER));
861 if (!mhdr)
862 goto err;
863 mhdr->name = tmpname;
864 mhdr->value = tmpval;
865 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)))))
)) {
866 free(mhdr);
867 goto err;
868 }
869 return mhdr;
870 err:
871 free(tmpname);
872 free(tmpval);
873 return NULL((void*)0);
874}
875
876static int
877mime_hdr_addparam(MIME_HEADER *mhdr, char *name, char *value)
878{
879 char *tmpname = NULL((void*)0), *tmpval = NULL((void*)0), *p;
880 MIME_PARAM *mparam;
881
882 if (name) {
883 tmpname = strdup(name);
884 if (!tmpname)
885 goto err;
886 for (p = tmpname; *p; p++)
887 *p = tolower((unsigned char)*p);
888 }
889 if (value) {
890 tmpval = strdup(value);
891 if (!tmpval)
892 goto err;
893 }
894 /* Parameter values are case sensitive so leave as is */
895 mparam = malloc(sizeof(MIME_PARAM));
896 if (!mparam)
897 goto err;
898 mparam->param_name = tmpname;
899 mparam->param_value = tmpval;
900 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) {
901 free(mparam);
902 goto err;
903 }
904 return 1;
905 err:
906 free(tmpname);
907 free(tmpval);
908 return 0;
909}
910
911static int
912mime_hdr_cmp(const MIME_HEADER * const *a, const MIME_HEADER * const *b)
913{
914 if (!(*a)->name || !(*b)->name)
915 return !!(*a)->name - !!(*b)->name;
916 return (strcmp((*a)->name, (*b)->name));
917}
918
919static int
920mime_param_cmp(const MIME_PARAM * const *a, const MIME_PARAM * const *b)
921{
922 if (!(*a)->param_name || !(*b)->param_name)
923 return !!(*a)->param_name - !!(*b)->param_name;
924 return (strcmp((*a)->param_name, (*b)->param_name));
925}
926
927/* Find a header with a given name (if possible) */
928
929static MIME_HEADER *
930mime_hdr_find(STACK_OF(MIME_HEADER)struct stack_st_MIME_HEADER *hdrs, char *name)
931{
932 MIME_HEADER htmp;
933 int idx;
934 htmp.name = name;
935 idx = sk_MIME_HEADER_find(hdrs, &htmp)sk_find(((_STACK*) (1 ? (hdrs) : (struct stack_st_MIME_HEADER
*)0)), ((void*) (1 ? (&htmp) : (MIME_HEADER*)0)))
;
936 if (idx < 0)
937 return NULL((void*)0);
938 return sk_MIME_HEADER_value(hdrs, idx)((MIME_HEADER *)sk_value(((_STACK*) (1 ? (hdrs) : (struct stack_st_MIME_HEADER
*)0)), (idx)))
;
939}
940
941static MIME_PARAM *
942mime_param_find(MIME_HEADER *hdr, char *name)
943{
944 MIME_PARAM param;
945 int idx;
946 param.param_name = name;
947 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)))
;
948 if (idx < 0)
949 return NULL((void*)0);
950 return sk_MIME_PARAM_value(hdr->params, idx)((MIME_PARAM *)sk_value(((_STACK*) (1 ? (hdr->params) : (struct
stack_st_MIME_PARAM*)0)), (idx)))
;
951}
952
953static void
954mime_hdr_free(MIME_HEADER *hdr)
955{
956 free(hdr->name);
957 free(hdr->value);
958 if (hdr->params)
959 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))))
;
960 free(hdr);
961}
962
963static void
964mime_param_free(MIME_PARAM *param)
965{
966 free(param->param_name);
967 free(param->param_value);
968 free(param);
969}
970
971/* Check for a multipart boundary. Returns:
972 * 0 : no boundary
973 * 1 : part boundary
974 * 2 : final boundary
975 */
976static int
977mime_bound_check(char *line, int linelen, char *bound, int blen)
978{
979 if (linelen == -1)
980 linelen = strlen(line);
981 if (blen == -1)
982 blen = strlen(bound);
983 /* Quickly eliminate if line length too short */
984 if (blen + 2 > linelen)
985 return 0;
986 /* Check for part boundary */
987 if (!strncmp(line, "--", 2) && !strncmp(line + 2, bound, blen)) {
988 if (!strncmp(line + blen + 2, "--", 2))
989 return 2;
990 else
991 return 1;
992 }
993 return 0;
994}
995
996static int
997strip_eol(char *linebuf, int *plen)
998{
999 int len = *plen;
1000 char *p, c;
1001 int is_eol = 0;
1002
1003 for (p = linebuf + len - 1; len > 0; len--, p--) {
1004 c = *p;
1005 if (c == '\n')
1006 is_eol = 1;
1007 else if (c != '\r')
1008 break;
1009 }
1010 *plen = len;
1011 return is_eol;
1012}