diff options
Diffstat (limited to 'pith')
-rw-r--r-- | pith/adrbklib.c | 42 | ||||
-rw-r--r-- | pith/adrbklib.h | 2 | ||||
-rw-r--r-- | pith/conf.c | 2 | ||||
-rw-r--r-- | pith/conftype.h | 1 | ||||
-rw-r--r-- | pith/mimedesc.c | 7 | ||||
-rw-r--r-- | pith/pattern.c | 6 | ||||
-rw-r--r-- | pith/pine.hlp | 119 | ||||
-rw-r--r-- | pith/reply.c | 2 | ||||
-rw-r--r-- | pith/send.c | 18 | ||||
-rw-r--r-- | pith/smime.c | 196 | ||||
-rw-r--r-- | pith/smime.h | 11 | ||||
-rw-r--r-- | pith/smkeys.c | 71 |
12 files changed, 276 insertions, 201 deletions
diff --git a/pith/adrbklib.c b/pith/adrbklib.c index 51979bdc..bdd505fb 100644 --- a/pith/adrbklib.c +++ b/pith/adrbklib.c @@ -6026,3 +6026,45 @@ add_forced_entries(AdrBk *abook) } } } + +/* Go through the list of addressbooks and check if any + * of them point to the given stream. + */ +int +any_addressbook_in_remote_stream(MAILSTREAM *stream) +{ + int rv = 0; + int i = 0, num = 0; + char *nickname = NULL; + char *filename = NULL; + char *q = NULL; + + do{ + if(ps_global->VAR_ADDRESSBOOK && + ps_global->VAR_ADDRESSBOOK[num] && + ps_global->VAR_ADDRESSBOOK[num][0]){ + q = ps_global->VAR_ADDRESSBOOK[num++]; + i = num; + } + else if(ps_global->VAR_GLOB_ADDRBOOK && + ps_global->VAR_GLOB_ADDRBOOK[i-num] && + ps_global->VAR_GLOB_ADDRBOOK[i-num][0]){ + q = ps_global->VAR_GLOB_ADDRBOOK[i - num]; + i++; + } else q = NULL; + if(q != NULL){ + get_pair(q, &nickname, &filename, 0, 0); + + if(nickname) fs_give((void **)&nickname); + + if(filename){ + if(*filename == '{' + && same_stream(filename, stream) != NULL) + rv = 1; + fs_give((void **)&filename); + } + } + } while (rv == 0 && q != NULL); + + return rv; +} diff --git a/pith/adrbklib.h b/pith/adrbklib.h index 9fbeb37c..505a8525 100644 --- a/pith/adrbklib.h +++ b/pith/adrbklib.h @@ -852,6 +852,6 @@ void adrbk_maintenance(void); char **parse_addrlist(char *); char *skip_to_next_addr(char *); void add_forced_entries(AdrBk *); - +int any_addressbook_in_remote_stream(MAILSTREAM *); #endif /* PITH_ADRBKLIB_INCLUDED */ diff --git a/pith/conf.c b/pith/conf.c index 4bc9481b..81eed75b 100644 --- a/pith/conf.c +++ b/pith/conf.c @@ -3259,6 +3259,8 @@ feature_list(int index) F_REMEMBER_SMIME_PASSPHRASE, h_config_smime_remember_passphrase, PREF_HIDDEN, 0}, {"smime-sign-by-default", "S/MIME -- Sign by Default", F_SIGN_DEFAULT_ON, h_config_smime_sign_by_default, PREF_HIDDEN, 0}, + {"smime-use-store-only", "S/MIME -- Validate Using Certificate Store Only", + F_USE_CERT_STORE_ONLY, h_config_smime_use_cert_store, PREF_HIDDEN, 1}, #ifdef APPLEKEYCHAIN {"publiccerts-in-keychain", "S/MIME -- Public Certs in MacOS Keychain", F_PUBLICCERTS_IN_KEYCHAIN, h_config_smime_pubcerts_in_keychain, PREF_HIDDEN, 0}, diff --git a/pith/conftype.h b/pith/conftype.h index 16e8de25..8ba7941c 100644 --- a/pith/conftype.h +++ b/pith/conftype.h @@ -544,6 +544,7 @@ typedef enum { F_SIGN_DEFAULT_ON, F_ENCRYPT_DEFAULT_ON, F_REMEMBER_SMIME_PASSPHRASE, + F_USE_CERT_STORE_ONLY, #ifdef APPLEKEYCHAIN F_PUBLICCERTS_IN_KEYCHAIN, #endif diff --git a/pith/mimedesc.c b/pith/mimedesc.c index 5b9db1b4..8a1d7f7d 100644 --- a/pith/mimedesc.c +++ b/pith/mimedesc.c @@ -579,12 +579,15 @@ type_desc(int type, char *subtype, PARAMETER *params, PARAMETER *disp_params, in } if(full && type != TYPEMULTIPART && type != TYPEMESSAGE){ + unsigned char decodebuf[10000]; if((parmval = parameter_val(params, "name")) != NULL){ - snprintf(p, sizeof(type_d)-(p-type_d), " (Name: \"%s\")", parmval); + rfc1522_decode_to_utf8(decodebuf, sizeof(decodebuf), parmval); + snprintf(p, sizeof(type_d)-(p-type_d), " (Name: \"%s\")", decodebuf); fs_give((void **) &parmval); } else if((parmval = parameter_val(disp_params, "filename")) != NULL){ - snprintf(p, sizeof(type_d)-(p-type_d), " (Filename: \"%s\")", parmval); + rfc1522_decode_to_utf8(decodebuf, sizeof(decodebuf), parmval); + snprintf(p, sizeof(type_d)-(p-type_d), " (Filename: \"%s\")", decodebuf); fs_give((void **) &parmval); } } diff --git a/pith/pattern.c b/pith/pattern.c index 3a258e7c..0b2eaf58 100644 --- a/pith/pattern.c +++ b/pith/pattern.c @@ -3,8 +3,8 @@ static char rcsid[] = "$Id: pattern.c 1204 2009-02-02 19:54:23Z hubert@u.washing #endif /* * ======================================================================== - * Copyright 2006-2009 University of Washington * Copyright 2013-2014 Eduardo Chappa + * Copyright 2006-2009 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -4764,7 +4764,9 @@ match_pattern(PATGRP_S *patgrp, MAILSTREAM *stream, SEARCHSET *searchset, } if(in_client_callback && is_imap_stream(stream) - && (patgrp->alltext || patgrp->bodytext)) + && (patgrp->alltext || patgrp->bodytext + || (patgrp->inabook != IAB_EITHER + && any_addressbook_in_remote_stream(stream)))) return(-1); pgm = match_pattern_srchpgm(patgrp, stream, searchset); diff --git a/pith/pine.hlp b/pith/pine.hlp index b296f024..6377dabb 100644 --- a/pith/pine.hlp +++ b/pith/pine.hlp @@ -140,7 +140,7 @@ with help text for the config screen and the composer that didn't have any reasonable place to be called from. Dummy change to get revision in pine.hlp ============= h_revision ================= -Alpine Commit 61 2014-05-02 18:29:37 +Alpine Commit 62 2014-05-17 16:49:55 ============= h_news ================= <HTML> <HEAD> @@ -162,7 +162,7 @@ Version <!--#echo var="ALPINE_VERSION"--> (<!--#echo var="ALPINE_REVISION"-->) <P> Alpine is an "Alternatively Licensed Program for Internet -News and Email" produced until 2008 by the University of Washington. +News and Email" produced until 2009 by the University of Washington. It is intended to be an easy-to-use program for sending, receiving, and filing Internet electronic mail messages and bulletin board (Netnews) messages. Alpine is designed to run on a wide @@ -184,6 +184,11 @@ Additions include: <LI> Upgrade UW-IMAP to Panda IMAP from <A HREF="https://github.com/jonabbey/panda-imap">https://github.com/jonabbey/panda-imap</A>. <LI> S/MIME: Add screen to manage certificates. + <LI> S/MIME: Signatures are validated using the user's certificates instead + of the ones included in the message. Behavior can be disabled by + disabling the option <A href="h_config_smime_use_cert_store"> + <!--#echo var="FEAT_smime-use-storey-only"--></A>, which is enabled + by default. <LI> S/MIME: sign messages using intermediate certificates when needed and possible. <LI> S/MIME: validation of certificates for servers that modify signed @@ -192,7 +197,11 @@ Additions include: encrypted second, so that they can be decoded by other clients. <LI> S/MIME: add the sender certificate to the list of certificates in encrypted messages to make it possible for the sender to decrypt - the message they sent. + the message they sent. + <LI> S/MIME: When transferring certificates to a local container, create + container with default names PublicContainer, PrivateContainer and + CAContainer, as appropriate for these files, unless the user has + provided some other names. <LI> Add support to selective expunge through a subcommand of the select-apply commands. Read more in the <A HREF="h_index_cmd_expunge">help</A> for the expunge command. @@ -235,6 +244,8 @@ Additions include: <LI> Pico: Justification works without need of a predefined quote string. This allows justification of blocks of text that are indented with spaces. + <LI> Decode the name of attachment names, so they can be written as part + of the description of the part. <LI> Check bounds and tie strings off to improve security. Contributed by James Jerkins. <LI> Replace tabs by spaces in From and Subject fields to control for @@ -267,10 +278,21 @@ Bugs that have been addressed include: and Stefan Mueller. <LI> S/MIME: Certificates are lost when using a pinerc file outside of the home directory. - <LI> S/MIME: accessing the S/MIME configuration screen would deinitialize + <LI> S/MIME: Accessing the S/MIME configuration screen would deinitialize SMIME making it not possible to sign or encrypt messages. + <LI> S/MIME: Forwarding a signed message might make the body contain mime + information that is not part of the body, and hence making the body + of the message seem wrong. <LI> Crash when tcp connection to NNTP server was lost after connection had been established, but lost immediately afterwards. + <LI> Crash with message "lock when already locked", when painting + an index was based on scores that needed information from a remote + addressbook in the same server as the folder opened. Reported by + Peter Koellner. + <LI> Alpine cannot handle correctly some characters in the Windows-1256 + character set, which might lead to a crash or a corruption in the + screen. Work was done to contain the bug. A more complete fix will + be done in a future release. Reported by Professor Robert Funnell. <LI> WebAlpine: add _GNU_SOURCE to make pubcookie build. <LI> WebAlpine: fail to build with debug disabled. Fix from Sam Hathaway. <LI> Save command did not warn of existence of a message with a deleted @@ -294,7 +316,7 @@ Bugs that have been addressed include: $alpine_TCLINC instead of $alpine_TCLINC/tcl.h. Reported and fixed by Werner Scheinast. <LI> Move SSL configurations from UW-IMAP to configure script, and - update OpenSSL configuration for Mac OSX. + update OpenSSL configuration for Mac OS X. <LI> Remove -lregex from linker flags when building --with-supplied-regex. </UL> <P> @@ -357,7 +379,7 @@ Additions include: <UL> <LI> Quota report for IMAP folders that support it (press the "@" command in the index screen of such folder). <LI> Search a folder for the content of any header with the ";" command. - <LI> Foreign characters are decoded correctly in IMAP folders. + <LI> Foreign characters are decoded correctly in IMAP folder names. <LI> Question about breaking connection to slow servers includes their name. <LI> Internal x-alpine-help: resource locator for sending links to internal help. <LI> OpenSuse: Alpine find location of OpenSSL certificates. @@ -380,7 +402,7 @@ Bugs that have been addressed include: <LI> Not display of login prompt during initial keystrokes. <LI> justification of long urls breaks them. <LI> Incorrect New Mail message when envelope is not available. - <LI> Inorrect display of PREFDATE, PREFDATETIME and PREFTIME tokens. + <LI> Incorrect display of PREFDATE, PREFDATETIME and PREFTIME tokens. <LI> Crash when resizing the screen after display of LDAP search. <LI> Crash when redrawing screen while opening a remote folder collection. <LI> Infinite loop in scrolltool function during notification of new mail. @@ -713,7 +735,7 @@ version <!--#echo var="C_CLIENT_VERSION"-->. Alpine was developed until 2009 by the Office of Computing & Communications at the University of Washington in Seattle. Since then, the effort of developing Alpine has been continued by -a community of volunteers who make a good software even better! +a community of volunteers who make good software even better! <P> Alpine Copyright 2013-2014 Eduardo Chappa, @@ -1535,7 +1557,7 @@ employer, ... ; or </UL> Due to the large number of Alpine installations worldwide, and because we -receive no funding for it, the Alpine development team <B>cannot provide +receive no funding for it, the University of Washington <B>cannot provide individual support services outside the University of Washington</B>. <P> If you have no local computing support to turn to, the worldwide <b>comp.mail.pine</b> @@ -1599,13 +1621,14 @@ select Setup/Config to see many of the options available to you. Also note that all screens have context-sensitive help text available.<P> <!--chtml if pinemode="phone_home"--> SPECIAL REQUEST: -This software is made available as a public service of the -University of Washington in Seattle. We are no longer actively developing -the software, but it is still helpful to us to have an idea of how many -people are using Alpine. Are you willing to be counted as an Alpine user? Pressing +This software was originally created and maintained as a public +service by the University of Washington until 2009; updates are made +available as a public service of the Alpine community. It is always +helpful to have an idea of how many users are using Alpine. Are you +willing to be counted as an Alpine user? Pressing <A HREF="X-Alpine-Phone-Home:">Return</A> will send an anonymous (meaning, your real email address will not be revealed) -message to the Alpine team at the University of Washington for purposes of tallying. +message to the Alpine developers for purposes of tallying. <P> <!--To Exit this screen and continue your Alpine session press "E".--> <!--chtml else--> @@ -1632,13 +1655,14 @@ The Release Notes may be viewed by pressing <P> <!--chtml if pinemode="phone_home"--> SPECIAL REQUEST: -This software is made available as a public service of the -University of Washington in Seattle. We are no longer actively developing -the software, but it is still helpful to us to have an idea of how many -people are using Alpine. Are you willing to be counted as an Alpine user? Pressing +This software was originally created and maintained as a public +service by the University of Washington until 2009; updates are made +available as a public service of the Alpine community. It is always +helpful to have an idea of how many users are using Alpine. Are you +willing to be counted as an Alpine user? Pressing <A HREF="X-Alpine-Phone-Home:">Return</A> will send an anonymous (meaning, your real email address will not be revealed) -message to the Alpine team at the University of Washington for purposes of tallying. +message to the Alpine developers for purposes of tallying. <P> <!--To Exit this screen and continue your Alpine session press "E".--> <!--chtml else--> @@ -1662,14 +1686,15 @@ documented in the Release Notes, which may be viewed by pressing <P> <!--chtml if pinemode="phone_home"--> SPECIAL REQUEST: -This software is made available as a public service of the -University of Washington in Seattle. We are no longer actively developing -the software, but it is still helpful to us to have an idea of how many -people are using Alpine. Are you willing to be counted as an Alpine user? Pressing +This software was originally created and maintained as a public +service by the University of Washington until 2009; updates are made +available as a public service of the Alpine community. It is always +helpful to have an idea of how many users are using Alpine. Are you +willing to be counted as an Alpine user? Pressing <A HREF="X-Alpine-Phone-Home:">Return</A> will send an anonymous (meaning, your real email address will not be revealed) -message to the Alpine team at the University of Washington for purposes of tallying. - +message to the Alpine developers for purposes of tallying. +<P> <!--To Exit this screen and continue your Alpine session press "E".--> <!--chtml else--> To Exit this screen and continue your Alpine session press "Return". @@ -1766,7 +1791,7 @@ The "NextLink" and "PrevLink" commands <H1>Introduction</H1> Alpine is an "Alternatively Licensed Program for Internet -News and Email" produced until 2008 by the University of Washington. +News and Email" produced until 2009 by the University of Washington. It is intended to be an easy-to-use program for sending, receiving, and filing Internet electronic mail messages and bulletin board (Netnews/Usenet) messages. Alpine supports the following @@ -3945,6 +3970,7 @@ There are also additional details on <li><a href="h_config_smime_encrypt_by_default">S/MIME FEATURE: <!--#echo var="FEAT_smime-encrypt-by-default"--></a> <li><a href="h_config_smime_remember_passphrase">S/MIME FEATURE: <!--#echo var="FEAT_smime-remember-passphrase"--></a> <li><a href="h_config_smime_sign_by_default">S/MIME FEATURE: <!--#echo var="FEAT_smime-sign-by-default"--></a> +<li><a href="h_config_smime_use_cert_store">S/MIME FEATURE: <!--#echo var="FEAT_smime-use-store-only"--></a> <li><a href="h_config_smime_pubcerts_in_keychain">S/MIME FEATURE: <!--#echo var="FEAT_publiccerts-in-keychain"--></a> <li><a href="h_config_smime_cacertcon">S/MIME OPTION: <!--#echo var="VAR_smime-cacert-container"--></a> <li><a href="h_config_smime_cacertdir">S/MIME OPTION: <!--#echo var="VAR_smime-cacert-directory"--></a> @@ -34597,6 +34623,47 @@ certificate). <End of help on this topic> </BODY> </HTML> +========== h_config_smime_use_cert_store ========== +<HTML> +<HEAD> +<TITLE>S/MIME FEATURE: <!--#echo var="FEAT_smime-use-store-only"--></TITLE> +</HEAD> +<BODY> +<H1>S/MIME FEATURE: <!--#echo var="FEAT_smime-use-store-only"--></H1> + +UNIX Alpine only. +<P> +This feature only has an effect if your version of Alpine includes +support for S/MIME. +It affects Alpine's behavior when you validate a message, and should +not be disabled, unless you are performing a test. +<P> +There are two important aspects of validation: validation of the message +(that is, the message was not modified after it was sent) +as well as validation of the identity of the sender. This option has to +do with the latter. +<P> +In order to validate that the message came from the sender in the message +and not an impersonator, Alpine can +either use the certificates that come in the message, or the ones that +you have personally stored. If this feature is enabled (the default) then +Alpine will use certificates that you have already saved in your store +and not those that come in the message to validate the sender of the +message. This behavior helps you prevent against impersonation, because +it is assumed that you trust the certificates that you have saved, and +might not trust those that came with the message that you are validating. +<P> +<UL> +<LI><A HREF="h_mainhelp_smime">General S/MIME help</A> +</UL><P> +<P> + +<UL> +<LI><A HREF="h_finding_help">Finding more information and requesting help</A> +</UL><P> +<End of help on this topic> +</BODY> +</HTML> ========== h_config_smime_pubcerts_in_keychain ========== <HTML> <HEAD> diff --git a/pith/reply.c b/pith/reply.c index d7270a2c..60a7c489 100644 --- a/pith/reply.c +++ b/pith/reply.c @@ -2253,7 +2253,7 @@ forward_body(MAILSTREAM *stream, ENVELOPE *env, struct mail_bodystruct *orig_bod && orig_body->nested.part){ /* only operate on the signed data (not the signature) */ body = forward_body(stream, env, &orig_body->nested.part->body, - msgno, sect_prefix, msgtext, flags); + msgno, section, msgtext, flags); } /*---- Message is multipart ----*/ else if(!(orig_body->subtype && !strucmp(orig_body->subtype, diff --git a/pith/send.c b/pith/send.c index 4620d1aa..191e186d 100644 --- a/pith/send.c +++ b/pith/send.c @@ -4245,6 +4245,7 @@ l_putc(int c) long pine_rfc822_output_body(struct mail_bodystruct *body, soutr_t f, void *s) { + STORE_S *bodyso; PART *part; PARAMETER *param; char *t, *cookie = NIL, *encode_error; @@ -4255,6 +4256,9 @@ pine_rfc822_output_body(struct mail_bodystruct *body, soutr_t f, void *s) dprint((4, "-- pine_rfc822_output_body: %d\n", body ? body->type : 0)); + + bodyso = (STORE_S *) body->contents.text.data; + if(body->type == TYPEMULTIPART) { /* multipart gets special handling */ part = body->nested.part; /* first body part */ /* find cookie */ @@ -4307,8 +4311,8 @@ pine_rfc822_output_body(struct mail_bodystruct *body, soutr_t f, void *s) dprint((4, "-- pine_rfc822_output_body: segment %ld bytes\n", body->size.bytes)); - if(body->contents.text.data) - gf_set_so_readc(&gc, (STORE_S *) body->contents.text.data); + if(bodyso) + gf_set_so_readc(&gc, bodyso); else return(1); @@ -4316,15 +4320,15 @@ pine_rfc822_output_body(struct mail_bodystruct *body, soutr_t f, void *s) * Don't add trailing line if it is ExternalText, which already guarantees * a trailing newline. */ - add_trailing_crlf = !(((STORE_S *) body->contents.text.data)->src == ExternalText); + add_trailing_crlf = !(bodyso->src == ExternalText); - so_seek((STORE_S *) body->contents.text.data, 0L, 0); + so_seek(bodyso, 0L, 0); if(body->type != TYPEMESSAGE){ /* NOT encapsulated message */ char *charset; if(body->type == TYPETEXT - && so_attr((STORE_S *) body->contents.text.data, "edited", NULL) + && so_attr(bodyso, "edited", NULL) && (charset = parameter_val(body->parameter, "charset"))){ if(strucmp(charset, "utf-8") && strucmp(charset, "us-ascii")){ if(!strucmp(charset, "iso-2022-jp")){ @@ -4356,7 +4360,7 @@ pine_rfc822_output_body(struct mail_bodystruct *body, soutr_t f, void *s) */ if(body->type == TYPETEXT && body->encoding != ENCBASE64 - && !so_attr((STORE_S *) body->contents.text.data, "rawbody", NULL)){ + && !so_attr(bodyso, "rawbody", NULL)){ gf_link_filter(gf_local_nvtnl, NULL); } @@ -4380,7 +4384,7 @@ pine_rfc822_output_body(struct mail_bodystruct *body, soutr_t f, void *s) display_message('x'); } - gf_clear_so_readc((STORE_S *) body->contents.text.data); + gf_clear_so_readc(bodyso); if(encode_error || !l_flush_net(TRUE)) return(0); diff --git a/pith/smime.c b/pith/smime.c index ce7b6a70..6c49fdcc 100644 --- a/pith/smime.c +++ b/pith/smime.c @@ -62,7 +62,7 @@ static BIO *bio_from_store(STORE_S *store); static STORE_S *get_part_contents(long msgno, const char *section); static PKCS7 *get_pkcs7_from_part(long msgno, const char *section); static int do_signature_verify(PKCS7 *p7, BIO *in, BIO *out, int silent); -int do_detached_signature_verify(BODY *b, long msgno, char *section); +static int do_detached_signature_verify(BODY *b, long msgno, char *section); static PERSONAL_CERT *find_certificate_matching_pkcs7(PKCS7 *p7); static int do_decoding(BODY *b, long msgno, const char *section); static void free_smime_struct(SMIME_STUFF_S **smime); @@ -90,13 +90,6 @@ static X509_STORE *s_cert_store; static int seeded = 0; static int egdsocket = 0; -typedef enum {P7Type, CharType, SizedText} SpareType; - -typedef struct smime_sparep_t { - SpareType sptype; - void *data; -} SMIME_SPARE_S; - void * create_smime_sparep(SpareType stype, void *s) { @@ -1410,13 +1403,15 @@ copy_dir_to_container(WhichCerts which, char *contents) int ret = 0; BIO *bio_out = NULL, *bio_in = NULL; char srcpath[MAXPATH+1], dstpath[MAXPATH+1], emailaddr[MAXPATH], file[MAXPATH], line[4096]; - char *tempfile = NULL; + char *tempfile = NULL, fpath[MAXPATH+1]; DIR *dirp; struct dirent *d; REMDATA_S *rd = NULL; char *configdir = NULL; char *configpath = NULL; + char *configcontainer = NULL; char *filesuffix = NULL; + char *ret_dir = NULL; dprint((9, "copy_dir_to_container(%s)", which==Public ? "Public" : which==Private ? "Private" : which==CACert ? "CACert" : "?")); smime_init(); @@ -1429,16 +1424,19 @@ copy_dir_to_container(WhichCerts which, char *contents) if(which == Public){ configdir = ps_global->VAR_PUBLICCERT_DIR; configpath = ps_global->smime->publicpath; + configcontainer = cpystr(DF_PUBLIC_CONTAINER); filesuffix = ".crt"; } else if(which == Private){ configdir = ps_global->VAR_PRIVATEKEY_DIR; configpath = ps_global->smime->privatepath; + configcontainer = cpystr(DF_PRIVATE_CONTAINER); filesuffix = ".key"; } else if(which == CACert){ configdir = ps_global->VAR_CACERT_DIR; configpath = ps_global->smime->capath; + configcontainer = cpystr(DF_CA_CONTAINER); filesuffix = ".crt"; } @@ -1534,7 +1532,7 @@ copy_dir_to_container(WhichCerts which, char *contents) * dstpath is either the local Container file or the local cache file * for the remote Container file. */ - tempfile = tempfile_in_same_dir(dstpath, "az", NULL); + tempfile = tempfile_in_same_dir(dstpath, "az", &ret_dir); } /* @@ -1609,12 +1607,24 @@ copy_dir_to_container(WhichCerts which, char *contents) BIO_free(bio_out); if(!ret){ - if(rename_file(tempfile, dstpath) < 0){ + if(ret_dir){ + if(strlen(dstpath) + strlen(configcontainer) - strlen(ret_dir) + 1 < sizeof(dstpath)) + snprintf(fpath, sizeof(fpath), "%s%c%s", + dstpath, tempfile[strlen(ret_dir)], configcontainer); + else + ret = -1; + } + else ret = -1; + + if(!ret){ + if(rename_file(tempfile, fpath) < 0){ q_status_message2(SM_ORDER, 3, 3, - _("Can't rename %s to %s"), tempfile, dstpath); + _("Can't rename %s to %s"), tempfile, fpath); ret = -1; + } else q_status_message1(SM_ORDER, 3, 3, + _("saved container to %s"), fpath); } - + /* if the container is remote, copy it */ if(!ret && IS_REMOTE(configpath)){ int e; @@ -1656,6 +1666,12 @@ copy_dir_to_container(WhichCerts which, char *contents) if(tempfile) fs_give((void **) &tempfile); + if(ret_dir) + fs_give((void **) &ret_dir); + + if(configcontainer) + fs_give((void **) &configcontainer); + return ret; } @@ -1921,36 +1937,6 @@ is_pkcs7_body(BODY *body) } -#ifdef notdef -/* - * Somewhat useful debug utility to dump the contents of a BIO to a file. - * Note that a memory BIO will have its contents eliminated after they - * are read so this will break the next step. - */ -static void -dump_bio_to_file(BIO *in, char *filename) -{ - char iobuf[4096]; - int len; - BIO *out; - - out = BIO_new_file(filename, "w"); - - if(out){ - if(BIO_method_type(in) != BIO_TYPE_MEM) - BIO_reset(in); - - while((len = BIO_read(in, iobuf, sizeof(iobuf))) > 0) - BIO_write(out, iobuf, len); - - BIO_free(out); - } - - BIO_reset(in); -} -#endif - - /* * Recursively stash a pointer to the decrypted data in our * manufactured body. @@ -2255,7 +2241,7 @@ end: /* * Encrypt a message on the way out. Called from call_mailer in send.c - * The body may be reallocated. + * The body may be reallocated. */ int encrypt_outgoing_message(METAENV *header, BODY **bodyP) @@ -2287,9 +2273,9 @@ encrypt_outgoing_message(METAENV *header, BODY **bodyP) for(a=*pf->addr; a; a=a->next){ snprintf(buf, sizeof(buf), "%s@%s", a->mailbox, a->host); - if((cert = get_cert_for(buf, Public)) != NULL) + if((cert = get_cert_for(buf, Public)) != NULL){ sk_X509_push(encerts,cert); - else{ + }else{ q_status_message2(SM_ORDER, 1, 1, _("Unable to find certificate for <%s@%s>"), a->mailbox, a->host); @@ -2491,10 +2477,12 @@ static int do_signature_verify(PKCS7 *p7, BIO *in, BIO *out, int silent) { STACK_OF(X509) *otherCerts = NULL; + CertList *cl; int result; + int flags; const char *data; long err; - + if(!s_cert_store){ if(!silent) q_status_message(SM_ORDER | SM_DING, 2, 2, _("Couldn't verify S/MIME signature: No CA Certs were loaded")); @@ -2504,8 +2492,31 @@ do_signature_verify(PKCS7 *p7, BIO *in, BIO *out, int silent) smime_extract_and_save_cert(p7); - result = PKCS7_verify(p7, otherCerts, s_cert_store, in, out, 0); - + flags = F_ON(F_USE_CERT_STORE_ONLY, ps_global) ? PKCS7_NOINTERN : 0; + + if(ps_global->smime->publiccertlist == NULL){ + renew_cert_data(&ps_global->smime->publiccertlist, Public); + for(cl = ps_global->smime->publiccertlist; cl ; cl = cl->next){ + if(cl->x509_cert == NULL){ + char *s = strrchr(cl->name, '.'); + *s = '\0'; + cl->x509_cert = get_cert_for(cl->name, Public); + *s = '.'; + } + } + } + + if(ps_global->smime->publiccertlist){ + otherCerts = sk_X509_new_null(); + for(cl = ps_global->smime->publiccertlist; cl ; cl = cl->next) + if(cl->x509_cert != NULL) + sk_X509_push(otherCerts, X509_dup(cl->x509_cert)); + } + + result = PKCS7_verify(p7, otherCerts, s_cert_store, in, out, flags); + + sk_X509_pop_free(otherCerts, X509_free); + if(result){ q_status_message(SM_ORDER, 1, 1, _("S/MIME signature verified ok")); } @@ -2550,54 +2561,6 @@ free_smime_body_sparep(void **sparep) } } -/* return the mime header for this body part. Memory freed by caller */ -char * -smime_fetch_mime(BODY *b, MAILSTREAM *stream, long msgno, char * section, - unsigned long *mimelen) -{ - char *rv; - char newSec[100]; - - if(b->type == TYPEMULTIPART) - snprintf(newSec, sizeof(newSec), "%s%s1", section ? section : "", (section && *section) ? "." : ""); - else - strncpy(newSec, section, sizeof(newSec)); - newSec[sizeof(newSec)-1] = '\0'; - rv = mail_fetch_mime(stream, msgno, newSec, mimelen, 0); - return rv ? cpystr(rv) : NULL; -} - - -void -smime_write_body_header(BODY *b, MAILSTREAM *stream, long msgno, char *section, soutr_t f, void *s) -{ - char *rv; - char newSec[100]; - - if(b->nested.part == NULL) - return; - - if(b->nested.part->body.type == TYPEMULTIPART) - snprintf(newSec, sizeof(newSec), "%s%s1", section ? section : "", (section && *section) ? "." : ""); - else - strncpy(newSec, section, sizeof(newSec)); - newSec[sizeof(newSec)-1] = '\0'; - rv = mail_fetch_mime(stream, msgno, newSec, NULL, 0); - if(f && rv != NULL) - (*f)(s, rv); -} - -int -write_signed_body(BODY *b, MAILSTREAM *stream, long msgno, char *section, BIO *in) -{ - - smime_write_body_header(b, stream, msgno, section, rfc822_output_func, in); - - -} - - - /* Big comment, explaining the mess that exists out there, and how we deal with it, and also how we solve the problems that are created this way. @@ -2664,19 +2627,30 @@ write_signed_body(BODY *b, MAILSTREAM *stream, long msgno, char *section, BIO *i processed text. Nevertheless, at this time, this is automatic, and is causing a delay in the processing of the message, but it is validating correctly all messages. + + PART IV + + When the user sends a message as encrypted and signed, this code used to + encrypt first, and then sign the pkcs7 body, but it turns out that some + other clients can not handle these messages. While we could argue that the + other clients need to improve, we will support reading messages in both + ways, and will send messages using this technique; that is, signed first, + encrypted second. It seems that all tested clients support this way, so it + should be safe to do so. */ /* * Given a multipart body of type multipart/signed, attempt to verify it. * Returns non-zero if the body was changed. */ -int +static int do_detached_signature_verify(BODY *b, long msgno, char *section) { PKCS7 *p7 = NULL; BIO *in = NULL; PART *p; int result, modified_the_body = 0; + int flag; /* 1 silent, 0 not silent */ unsigned long mimelen, bodylen; char newSec[100], *mimetext, *bodytext; char *what_we_did; @@ -2693,7 +2667,7 @@ do_detached_signature_verify(BODY *b, long msgno, char *section) if(get_smime_sparep_type(b->sparep) == SizedText){ /* bodytext includes mimetext */ st = (SIZEDTEXT *) get_smime_sparep_data(b->sparep); - bodytext = st->data; + bodytext = (char *) st->data; bodylen = st->size; mimetext = NULL; mimelen = 0L; @@ -2724,7 +2698,9 @@ do_detached_signature_verify(BODY *b, long msgno, char *section) * validates when we remove the last two characters. Silence * any failures first. */ - if(((result = do_signature_verify(p7, in, NULL, 1)) == 0) + flag = (bodylen <= 2 || strncmp(bodytext+bodylen-2, "\r\n", 2)) + ? 0 : 1; + if(((result = do_signature_verify(p7, in, NULL, flag)) == 0) && bodylen > 2 && (strncmp(bodytext+bodylen-2,"\r\n", 2) == 0)){ BUF_MEM *biobuf = NULL; @@ -2738,7 +2714,9 @@ do_detached_signature_verify(BODY *b, long msgno, char *section) * information. In this case, we fetch the message and we process * it by hand. */ - if((result = do_signature_verify(p7, in, NULL, 1)) == 0 + flag = (mimelen == 0 || !IS_REMOTE(ps_global->mail_stream->mailbox)) + ? 0 : 1; + if((result = do_signature_verify(p7, in, NULL, flag)) == 0 && mimelen > 0 /* do not do this for encrypted messages */ && IS_REMOTE(ps_global->mail_stream->mailbox)){ char *fetch; @@ -2766,7 +2744,7 @@ do_detached_signature_verify(BODY *b, long msgno, char *section) mail_free_envelope(&env); mail_free_body_part(&b->nested.part); - b->nested.part = body->nested.part; + b->nested.part = mail_body_section(body, section)->nested.part; create_local_cache(bstart, bstart, &b->nested.part->body, 1); modified_the_body = 1; @@ -3086,11 +3064,15 @@ do_decoding(BODY *b, long msgno, const char *section) char *cookie = NULL; PARAMETER *param; for (param = body->parameter; param && !cookie; param = param->next) - if (!strucmp (param->attribute,"BOUNDARY")) cookie = param->value; - st = fs_get(sizeof(SIZEDTEXT)); - st->data = (void *) cpystr(bstart + strlen(cookie)+4); /* 4 = strlen("--\r\n") */ - st->size = body->nested.part->next->body.mime.offset - 2*(strlen(cookie) + 4); - body->sparep = create_smime_sparep(SizedText, (void *)st); + if (!strucmp (param->attribute,"BOUNDARY")) cookie = param->value; + if(cookie != NULL){ + st = fs_get(sizeof(SIZEDTEXT)); + st->data = (void *) cpystr(bstart + strlen(cookie)+4); /* 4 = strlen("--\r\n") */ + st->size = body->nested.part->next->body.mime.offset - 2*(strlen(cookie) + 4); + body->sparep = create_smime_sparep(SizedText, (void *)st); + } + else + q_status_message(SM_ORDER, 3, 3, _("Couldn't find cookie in attachment list.")); } body->mime.offset = 0; body->mime.text.size = 0; diff --git a/pith/smime.h b/pith/smime.h index 8acaaa8e..a2d2c805 100644 --- a/pith/smime.h +++ b/pith/smime.h @@ -34,6 +34,14 @@ #define OUR_PKCS7_ENCLOSURE_SUBTYPE "x-pkcs7-enclosure" +typedef enum {P7Type, CharType, SizedText} SpareType; + +typedef struct smime_sparep_t { + SpareType sptype; + void *data; +} SMIME_SPARE_S; + + /* exported protoypes */ int smime_validate_cert(X509 *cert, long *error); int encrypt_file(char *fp, char *text, PERSONAL_CERT *pc); @@ -73,6 +81,9 @@ void mark_cert_deleted(WhichCerts ctype, int num, unsigned state); unsigned get_cert_deleted(WhichCerts ctype, int num); int smime_expunge_cert(WhichCerts ctype); int add_file_to_container(WhichCerts ctype, char *fpath, char *altname); +void *create_smime_sparep(SpareType stype, void *s); +SpareType get_smime_sparep_type(void *s); +void *get_smime_sparep_data(void *s); #endif /* PITH_SMIME_INCLUDED */ #endif /* SMIME */ diff --git a/pith/smkeys.c b/pith/smkeys.c index 56103e91..23c9d21a 100644 --- a/pith/smkeys.c +++ b/pith/smkeys.c @@ -252,58 +252,6 @@ load_key(PERSONAL_CERT *pc, char *pass) } -#ifdef notdef -static char * -get_x509_name_entry(const char *key, X509_NAME *name) -{ - int i, c, n; - char buf[256]; - char *id; - - if(!name) - return NULL; - - c = X509_NAME_entry_count(name); - - for(i=0; i<c; i++){ - X509_NAME_ENTRY *e; - - e = X509_NAME_get_entry(name, i); - if(!e) - continue; - - buf[0] = 0; - id = buf; - - n = OBJ_obj2nid(e->object); - if((n == NID_undef) || ((id=(char*) OBJ_nid2sn(n)) == NULL)){ - i2t_ASN1_OBJECT(buf, sizeof(buf), e->object); - id = buf; - } - - if((strucmp(id, "email")==0) || (strucmp(id, "emailAddress")==0)){ - X509_NAME_get_text_by_OBJ(name, e->object, buf, sizeof(buf)-1); - return cpystr(buf); - } - } - - return NULL; -} - - -char * -get_x509_subject_email(X509 *x) -{ - char* result; - result = get_x509_name_entry("email", X509_get_subject_name(x)); - if( !result ){ - result = get_x509_name_entry("emailAddress", X509_get_subject_name(x)); - } - - return result; -} -#endif /* notdef */ - #include <openssl/x509v3.h> /* * This newer version is from Adrian Vogel. It looks for the email @@ -392,7 +340,9 @@ save_cert_for(char *email, X509 *cert, WhichCerts ctype) } else if(SMHOLDERTYPE(ctype) == Container){ REMDATA_S *rd = NULL; + char *ret_dir = NULL; char path[MAXPATH]; + char fpath[MAXPATH]; char *upath = PATHCERTDIR(ctype); char *tempfile = NULL; int err = 0; @@ -472,15 +422,26 @@ save_cert_for(char *email, X509 *cert, WhichCerts ctype) path[sizeof(path)-1] = '\0'; } - tempfile = tempfile_in_same_dir(path, "az", NULL); + tempfile = tempfile_in_same_dir(path, "az", &ret_dir); if(tempfile){ if(certlist_to_file(tempfile, DATACERT(ctype))) err++; + if(!err && ret_dir){ + if(strlen(path) + strlen(tempfile) - strlen(ret_dir) + 1 < sizeof(path)) + snprintf(fpath, sizeof(fpath), "%s%c%s", + path, tempfile[strlen(ret_dir)], tempfile + strlen(ret_dir) + 1); + else + err++; + } + else err++; + + fs_give((void **)&ret_dir); + if(!err){ - if(rename_file(tempfile, path) < 0){ + if(rename_file(tempfile, fpath) < 0){ q_status_message2(SM_ORDER, 3, 3, - _("Can't rename %s to %s"), tempfile, path); + _("Can't rename %s to %s"), tempfile, fpath); err++; } } |