static int sort_hostpool (const void *xa, const void *xb) { int a = *(int *)xa; int b = *(int *)xb; assert (a >= 0 && a < hosttable_size); assert (b >= 0 && b < hosttable_size); assert (hosttable[a]); assert (hosttable[b]); return ascii_strcasecmp (hosttable[a]->name, hosttable[b]->name); }
int mutt_is_text_part (BODY * b) { int t = b->type; char *s = b->subtype; if ((WithCrypto & APPLICATION_PGP) && mutt_is_application_pgp (b)) return 0; if (t == TYPETEXT) return 1; if (t == TYPEMESSAGE) { if (!ascii_strcasecmp ("delivery-status", s)) return 1; } if ((WithCrypto & APPLICATION_PGP) && t == TYPEAPPLICATION) { if (!ascii_strcasecmp ("pgp-keys", s)) return 1; } return 0; }
/**************** * Return 1 for yes, -1 for quit, or 0 for no */ int answer_is_yes_no_quit ( const char *s ) { /* TRANSLATORS: See doc/TRANSLATE about this string. */ const char *long_yes = _("yes"); /* TRANSLATORS: See doc/TRANSLATE about this string. */ const char *long_no = _("no"); /* TRANSLATORS: See doc/TRANSLATE about this string. */ const char *long_quit = _("quit"); const char *short_yes = _("yY"); const char *short_no = _("nN"); const char *short_quit = _("qQ"); /* Note: we have to use a local dependent compare here. */ if ( match_multistr(long_no,s) ) return 0; if ( match_multistr(long_yes,s) ) return 1; if ( match_multistr(long_quit,s) ) return -1; if ( *s && strchr( short_no, *s ) && !s[1] ) return 0; if ( *s && strchr( short_yes, *s ) && !s[1] ) return 1; if ( *s && strchr( short_quit, *s ) && !s[1] ) return -1; /* but not here. */ if ( !ascii_strcasecmp(s, "yes" ) ) return 1; if ( !ascii_strcasecmp(s, "quit" ) ) return -1; if ( *s && strchr( "yY", *s ) && !s[1] ) return 1; if ( *s && strchr( "qQ", *s ) && !s[1] ) return -1; return 0; }
/* This function is used by the serialno command to check for an application conflict which may appear if the serialno command is used to request a specific application and the connection has already done a select_application. */ gpg_error_t check_application_conflict (ctrl_t ctrl, int slot, const char *name) { app_t app; (void)ctrl; if (slot < 0 || slot >= DIM (lock_table)) return gpg_error (GPG_ERR_INV_VALUE); app = lock_table[slot].initialized ? lock_table[slot].app : NULL; if (app && app->apptype && name) if ( ascii_strcasecmp (app->apptype, name)) return gpg_error (GPG_ERR_CONFLICT); return 0; }
int mutt_is_application_pgp (BODY *m) { int t = 0; char *p; if (m->type == TYPEAPPLICATION) { if (!ascii_strcasecmp (m->subtype, "pgp") || !ascii_strcasecmp (m->subtype, "x-pgp-message")) { if ((p = mutt_get_parameter ("x-action", m->parameter)) && (!ascii_strcasecmp (p, "sign") || !ascii_strcasecmp (p, "signclear"))) t |= PGPSIGN; if ((p = mutt_get_parameter ("format", m->parameter)) && !ascii_strcasecmp (p, "keys-only")) t |= PGPKEY; if(!t) t |= PGPENCRYPT; /* not necessarily correct, but... */ } if (!ascii_strcasecmp (m->subtype, "pgp-signed")) t |= PGPSIGN; if (!ascii_strcasecmp (m->subtype, "pgp-keys")) t |= PGPKEY; } else if (m->type == TYPETEXT && ascii_strcasecmp ("plain", m->subtype) == 0) { if (((p = mutt_get_parameter ("x-mutt-action", m->parameter)) || (p = mutt_get_parameter ("x-action", m->parameter)) || (p = mutt_get_parameter ("action", m->parameter))) && !ascii_strncasecmp ("pgp-sign", p, 8)) t |= PGPSIGN; else if (p && !ascii_strncasecmp ("pgp-encrypt", p, 11)) t |= PGPENCRYPT; else if (p && !ascii_strncasecmp ("pgp-keys", p, 7)) t |= PGPKEY; } if (t) t |= PGPINLINE; return t; }
/* imap_wordcasecmp: find word a in word list b */ int imap_wordcasecmp (const char *a, const char *b) { char tmp[SHORT_STRING]; char *s = (char *) b; int i; tmp[SHORT_STRING - 1] = 0; for (i = 0; i < SHORT_STRING - 2; i++, s++) { if (!*s || ISSPACE (*s)) { tmp[i] = 0; break; } tmp[i] = *s; } tmp[i + 1] = 0; return ascii_strcasecmp (a, tmp); }
static int GetPager(sqlite3 *db, const char *zName, Pager **pPager, unsigned *pnPageSize){ Btree *pBt = NULL; int i; for( i=0; i<db->nDb; ++i ){ if( ascii_strcasecmp(db->aDb[i].zName, zName)==0 ){ pBt = db->aDb[i].pBt; break; } } if( !pBt ){ return SQLITE_ERROR; } *pPager = sqlite3BtreePager(pBt); *pnPageSize = sqlite3BtreeGetPageSize(pBt) - sqlite3BtreeGetReserve(pBt); return SQLITE_OK; }
/* mutt_account_match: compare account info (host/port/user) */ int mutt_account_match (const ACCOUNT* a1, const ACCOUNT* a2) { const char* user = NONULL (Username); if (a1->type != a2->type) return 0; if (ascii_strcasecmp (a1->host, a2->host)) return 0; if (a1->port != a2->port) return 0; #ifdef USE_IMAP if (a1->type == M_ACCT_TYPE_IMAP) { if (ImapUser) user = ImapUser; } #endif #ifdef USE_POP if (a1->type == M_ACCT_TYPE_POP && PopUser) user = PopUser; #endif #ifdef USE_NNTP if (a1->type == M_ACCT_TYPE_NNTP && NntpUser) user = NntpUser; #endif if (a1->flags & a2->flags & M_ACCT_USER) return (!strcmp (a1->user, a2->user)); #ifdef USE_NNTP if (a1->type == M_ACCT_TYPE_NNTP) return a1->flags & M_ACCT_USER && a1->user[0] ? 0 : 1; #endif if (a1->flags & M_ACCT_USER) return (!strcmp (a1->user, user)); if (a2->flags & M_ACCT_USER) return (!strcmp (a2->user, user)); return 1; }
/* for compatibility with metamail */ static int is_mmnoask (const char *buf) { char tmp[LONG_STRING], *p, *q; int lng; if ((p = getenv ("MM_NOASK")) != NULL && *p) { if (mutt_strcmp (p, "1") == 0) return (1); strfcpy (tmp, p, sizeof (tmp)); p = tmp; while ((p = strtok (p, ",")) != NULL) { if ((q = strrchr (p, '/')) != NULL) { if (*(q+1) == '*') { if (ascii_strncasecmp (buf, p, q-p) == 0) return (1); } else { if (ascii_strcasecmp (buf, p) == 0) return (1); } } else { lng = mutt_strlen (p); if (buf[lng] == '/' && mutt_strncasecmp (buf, p, lng) == 0) return (1); } p = NULL; } } return (0); }
void mutt_check_lookup_list(BODY *b, char *type, int len) { LIST *t = MimeLookupList; int i; for (; t; t = t->next) { i = mutt_strlen(t->data) - 1; if (((i > 0) && (t->data[i - 1] == '/') && (t->data[i] == '*') && (ascii_strncasecmp(type, t->data, i) == 0)) || (ascii_strcasecmp(type, t->data) == 0)) { BODY tmp = { 0 }; int n; if ((n = mutt_lookup_mime_type(&tmp, b->filename)) != TYPEOTHER) { snprintf(type, len, "%s/%s", n == TYPEAUDIO ? "audio" : n == TYPEAPPLICATION ? "application" : n == TYPEIMAGE ? "image" : n == TYPEMESSAGE ? "message" : n == TYPEMODEL ? "model" : n == TYPEMULTIPART ? "multipart" : n == TYPETEXT ? "text" : n == TYPEVIDEO ? "video" : "other", tmp.subtype); dprint(1, "mutt_check_lookup_list: \"%s\" -> %s\n", b->filename, type); } if (tmp.subtype) safe_free(&tmp.subtype); if (tmp.xtype) safe_free(&tmp.xtype); } } }
void mutt_set_parameter (const char *attribute, const char *value, PARAMETER ** p) { PARAMETER *q; if (!value) { mutt_delete_parameter (attribute, p); return; } for (q = *p; q; q = q->next) { if (ascii_strcasecmp (attribute, q->attribute) == 0) { str_replace (&q->value, value); return; } } q = mutt_new_parameter (); q->attribute = str_dup (attribute); q->value = str_dup (value); q->next = *p; *p = q; }
int mutt_is_application_smime (BODY *m) { char *t=NULL; int len, complain=0; if(!m) return 0; if ((m->type & TYPEAPPLICATION) && m->subtype) { /* S/MIME MIME types don't need x- anymore, see RFC2311 */ if (!ascii_strcasecmp (m->subtype, "x-pkcs7-mime") || !ascii_strcasecmp (m->subtype, "pkcs7-mime")) { if ((t = mutt_get_parameter ("smime-type", m->parameter))) { if (!ascii_strcasecmp (t, "enveloped-data")) return SMIMEENCRYPT; else if (!ascii_strcasecmp (t, "signed-data")) return (SMIMESIGN|SMIMEOPAQUE); else return 0; } /* Netscape 4.7 uses * Content-Description: S/MIME Encrypted Message * instead of Content-Type parameter */ if (!ascii_strcasecmp (m->description, "S/MIME Encrypted Message")) return SMIMEENCRYPT; complain = 1; } else if (ascii_strcasecmp (m->subtype, "octet-stream")) return 0; t = mutt_get_parameter ("name", m->parameter); if (!t) t = m->d_filename; if (!t) t = m->filename; if (!t) { if (complain) mutt_message (_("S/MIME messages with no hints on content are unsupported.")); return 0; } /* no .p7c, .p10 support yet. */ len = mutt_strlen (t) - 4; if (len > 0 && *(t+len) == '.') { len++; if (!ascii_strcasecmp ((t+len), "p7m")) #if 0 return SMIMEENCRYPT; #else /* Not sure if this is the correct thing to do, but it's required for compatibility with Outlook */ return (SMIMESIGN|SMIMEOPAQUE); #endif else if (!ascii_strcasecmp ((t+len), "p7s")) return (SMIMESIGN|SMIMEOPAQUE); }
int parse_keyserver_options(char *options) { int ret=1; char *tok; char *max_cert=NULL; keyserver_opts[0].value=&max_cert; while((tok=optsep(&options))) { if(tok[0]=='\0') continue; /* For backwards compatibility. 1.2.x used honor-http-proxy and there are a good number of documents published that recommend it. */ if(ascii_strcasecmp(tok,"honor-http-proxy")==0) tok="http-proxy"; else if(ascii_strcasecmp(tok,"no-honor-http-proxy")==0) tok="no-http-proxy"; /* We accept quite a few possible options here - some options to handle specially, the keyserver_options list, and import and export options that pertain to keyserver operations. Note that you must use strncasecmp here as there might be an =argument attached which will foil the use of strcasecmp. */ #ifdef EXEC_TEMPFILE_ONLY if(ascii_strncasecmp(tok,"use-temp-files",14)==0 || ascii_strncasecmp(tok,"no-use-temp-files",17)==0) log_info(_("WARNING: keyserver option '%s' is not used" " on this platform\n"),tok); #else if(ascii_strncasecmp(tok,"use-temp-files",14)==0) opt.keyserver_options.options|=KEYSERVER_USE_TEMP_FILES; else if(ascii_strncasecmp(tok,"no-use-temp-files",17)==0) opt.keyserver_options.options&=~KEYSERVER_USE_TEMP_FILES; #endif else if(!parse_options(tok,&opt.keyserver_options.options, keyserver_opts,0) && !parse_import_options(tok, &opt.keyserver_options.import_options,0) && !parse_export_options(tok, &opt.keyserver_options.export_options,0)) { /* All of the standard options have failed, so the option is destined for a keyserver plugin. */ add_canonical_option(tok,&opt.keyserver_options.other); } } if(max_cert) { max_cert_size=strtoul(max_cert,(char **)NULL,10); if(max_cert_size==0) max_cert_size=DEFAULT_MAX_CERT_SIZE; } return ret; }
int mutt_protect (HEADER *msg, char *keylist) { BODY *pbody = NULL, *tmp_pbody = NULL; BODY *tmp_smime_pbody = NULL; BODY *tmp_pgp_pbody = NULL; int flags = (WithCrypto & APPLICATION_PGP)? msg->security: 0; int i; if (!WithCrypto) return -1; if (!(msg->security & (ENCRYPT | SIGN))) return 0; if ((msg->security & SIGN) && !crypt_valid_passphrase (msg->security)) return (-1); if ((WithCrypto & APPLICATION_PGP) && ((msg->security & PGPINLINE) == PGPINLINE)) { if ((msg->content->type != TYPETEXT) || ascii_strcasecmp (msg->content->subtype, "plain")) { if ((i = query_quadoption (OPT_PGPMIMEAUTO, _("Inline PGP can't be used with attachments. Revert to PGP/MIME?"))) != MUTT_YES) { mutt_error _("Mail not sent: inline PGP can't be used with attachments."); return -1; } } else { /* they really want to send it inline... go for it */ if (!isendwin ()) mutt_endwin _("Invoking PGP..."); pbody = crypt_pgp_traditional_encryptsign (msg->content, flags, keylist); if (pbody) { msg->content = pbody; return 0; } /* otherwise inline won't work...ask for revert */ if ((i = query_quadoption (OPT_PGPMIMEAUTO, _("Message can't be sent inline. Revert to using PGP/MIME?"))) != MUTT_YES) { mutt_error _("Mail not sent."); return -1; } } /* go ahead with PGP/MIME */ } if (!isendwin ()) mutt_endwin (NULL); if ((WithCrypto & APPLICATION_SMIME)) tmp_smime_pbody = msg->content; if ((WithCrypto & APPLICATION_PGP)) tmp_pgp_pbody = msg->content; if (option (OPTCRYPTUSEPKA) && (msg->security & SIGN)) { /* Set sender (necessary for e.g. PKA). */ if ((WithCrypto & APPLICATION_SMIME) && (msg->security & APPLICATION_SMIME)) crypt_smime_set_sender (msg->env->from->mailbox); else if ((WithCrypto & APPLICATION_PGP) && (msg->security & APPLICATION_PGP)) crypt_pgp_set_sender (msg->env->from->mailbox); } if (msg->security & SIGN) { if ((WithCrypto & APPLICATION_SMIME) && (msg->security & APPLICATION_SMIME)) { if (!(tmp_pbody = crypt_smime_sign_message (msg->content))) return -1; pbody = tmp_smime_pbody = tmp_pbody; } if ((WithCrypto & APPLICATION_PGP) && (msg->security & APPLICATION_PGP) && (!(flags & ENCRYPT) || option (OPTPGPRETAINABLESIG))) { if (!(tmp_pbody = crypt_pgp_sign_message (msg->content))) return -1; flags &= ~SIGN; pbody = tmp_pgp_pbody = tmp_pbody; } if (WithCrypto && (msg->security & APPLICATION_SMIME) && (msg->security & APPLICATION_PGP)) { /* here comes the draft ;-) */ } } if (msg->security & ENCRYPT) { if ((WithCrypto & APPLICATION_SMIME) && (msg->security & APPLICATION_SMIME)) { if (!(tmp_pbody = crypt_smime_build_smime_entity (tmp_smime_pbody, keylist))) { /* signed ? free it! */ return (-1); } /* free tmp_body if messages was signed AND encrypted ... */ if (tmp_smime_pbody != msg->content && tmp_smime_pbody != tmp_pbody) { /* detatch and don't delete msg->content, which tmp_smime_pbody->parts after signing. */ tmp_smime_pbody->parts = tmp_smime_pbody->parts->next; msg->content->next = NULL; mutt_free_body (&tmp_smime_pbody); } pbody = tmp_pbody; } if ((WithCrypto & APPLICATION_PGP) && (msg->security & APPLICATION_PGP)) { if (!(pbody = crypt_pgp_encrypt_message (tmp_pgp_pbody, keylist, flags & SIGN))) { /* did we perform a retainable signature? */ if (flags != msg->security) { /* remove the outer multipart layer */ tmp_pgp_pbody = mutt_remove_multipart (tmp_pgp_pbody); /* get rid of the signature */ mutt_free_body (&tmp_pgp_pbody->next); } return (-1); } /* destroy temporary signature envelope when doing retainable * signatures. */ if (flags != msg->security) { tmp_pgp_pbody = mutt_remove_multipart (tmp_pgp_pbody); mutt_free_body (&tmp_pgp_pbody->next); } } } if(pbody) msg->content = pbody; return 0; }
/* * * special form: file /name * causes us to go read from this file instead. * */ static void esp_print_decode_onesecret(netdissect_options *ndo, char *line, const char *file, int lineno) { struct sa_list sa1; int sa_def; char *spikey; char *decode; spikey = strsep(&line, " \t"); sa_def = 0; memset(&sa1, 0, sizeof(struct sa_list)); /* if there is only one token, then it is an algo:key token */ if (line == NULL) { decode = spikey; spikey = NULL; /* sa1.daddr.version = 0; */ /* memset(&sa1.daddr, 0, sizeof(sa1.daddr)); */ /* sa1.spi = 0; */ sa_def = 1; } else decode = line; if (spikey && ascii_strcasecmp(spikey, "file") == 0) { /* open file and read it */ FILE *secretfile; char fileline[1024]; int subfile_lineno=0; char *nl; char *filename = line; secretfile = fopen(filename, FOPEN_READ_TXT); if (secretfile == NULL) { perror(filename); exit(3); } while (fgets(fileline, sizeof(fileline)-1, secretfile) != NULL) { subfile_lineno++; /* remove newline from the line */ nl = strchr(fileline, '\n'); if (nl) *nl = '\0'; if (fileline[0] == '#') continue; if (fileline[0] == '\0') continue; esp_print_decode_onesecret(ndo, fileline, filename, subfile_lineno); } fclose(secretfile); return; } if (spikey && ascii_strcasecmp(spikey, "ikev2") == 0) { esp_print_decode_ikeline(ndo, line, file, lineno); return; } if (spikey) { char *spistr, *foo; uint32_t spino; spistr = strsep(&spikey, "@"); spino = strtoul(spistr, &foo, 0); if (spistr == foo || !spikey) { (*ndo->ndo_warning)(ndo, "print_esp: failed to decode spi# %s\n", foo); return; } sa1.spi = spino; if (strtoaddr6(spikey, &sa1.daddr.in6) == 1) { sa1.daddr_version = 6; } else if (strtoaddr(spikey, &sa1.daddr.in4) == 1) { sa1.daddr_version = 4; } else { (*ndo->ndo_warning)(ndo, "print_esp: can not decode IP# %s\n", spikey); return; } } if (decode) { /* skip any blank spaces */ while (isspace((unsigned char)*decode)) decode++; if(!espprint_decode_encalgo(ndo, decode, &sa1)) { return; } } esp_print_addsa(ndo, &sa1, sa_def); }
/* If called with NAME as NULL, select the best fitting application and return a context; otherwise select the application with NAME and return a context. SLOT identifies the reader device. Returns an error code and stores NULL at R_APP if no application was found or no card is present. */ gpg_error_t select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app) { gpg_error_t err; app_t app = NULL; unsigned char *result = NULL; size_t resultlen; int want_undefined; (void)ctrl; *r_app = NULL; want_undefined = (name && !strcmp (name, "undefined")); err = lock_reader (slot, ctrl); if (err) return err; /* First check whether we already have an application to share. */ app = lock_table[slot].initialized ? lock_table[slot].app : NULL; if (app && name) if (!app->apptype || ascii_strcasecmp (app->apptype, name)) { unlock_reader (slot); if (app->apptype) log_info ("application '%s' in use by reader %d - can't switch\n", app->apptype, slot); return gpg_error (GPG_ERR_CONFLICT); } /* Don't use a non-reusable marked application. */ if (app && app->no_reuse) { unlock_reader (slot); log_info ("lingering application '%s' in use by reader %d" " - can't switch\n", app->apptype? app->apptype:"?", slot); return gpg_error (GPG_ERR_CONFLICT); } /* If we don't have an app, check whether we have a saved application for that slot. This is useful so that a card does not get reset even if only one session is using the card - this way the PIN cache and other cached data are preserved. */ if (!app && lock_table[slot].initialized && lock_table[slot].last_app) { app = lock_table[slot].last_app; if (!name || (app->apptype && !ascii_strcasecmp (app->apptype, name)) ) { /* Yes, we can reuse this application - either the caller requested an unspecific one or the requested one matches the saved one. */ lock_table[slot].app = app; lock_table[slot].last_app = NULL; } else { /* No, this saved application can't be used - deallocate it. */ lock_table[slot].last_app = NULL; deallocate_app (app); app = NULL; } } /* If we can reuse an application, bump the reference count and return it. */ if (app) { if (app->slot != slot) log_bug ("slot mismatch %d/%d\n", app->slot, slot); app->slot = slot; app->ref_count++; *r_app = app; unlock_reader (slot); return 0; /* Okay: We share that one. */ } /* Need to allocate a new one. */ app = xtrycalloc (1, sizeof *app); if (!app) { err = gpg_error_from_syserror (); log_info ("error allocating context: %s\n", gpg_strerror (err)); unlock_reader (slot); return err; } app->slot = slot; /* Fixme: We should now first check whether a card is at all present. */ /* Try to read the GDO file first to get a default serial number. We skip this if the undefined application has been requested. */ if (!want_undefined) { err = iso7816_select_file (slot, 0x3F00, 1, NULL, NULL); if (!err) err = iso7816_select_file (slot, 0x2F02, 0, NULL, NULL); if (!err) err = iso7816_read_binary (slot, 0, 0, &result, &resultlen); if (!err) { size_t n; const unsigned char *p; p = find_tlv_unchecked (result, resultlen, 0x5A, &n); if (p) resultlen -= (p-result); if (p && n > resultlen && n == 0x0d && resultlen+1 == n) { /* The object it does not fit into the buffer. This is an invalid encoding (or the buffer is too short. However, I have some test cards with such an invalid encoding and therefore I use this ugly workaround to return something I can further experiment with. */ log_info ("enabling BMI testcard workaround\n"); n--; } if (p && n <= resultlen) { /* The GDO file is pretty short, thus we simply reuse it for storing the serial number. */ memmove (result, p, n); app->serialno = result; app->serialnolen = n; err = app_munge_serialno (app); if (err) goto leave; } else xfree (result); result = NULL; } } /* For certain error codes, there is no need to try more. */ if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT || gpg_err_code (err) == GPG_ERR_ENODEV) goto leave; /* Figure out the application to use. */ if (want_undefined) { /* We switch to the "undefined" application only if explicitly requested. */ app->apptype = "UNDEFINED"; err = 0; } else err = gpg_error (GPG_ERR_NOT_FOUND); if (err && is_app_allowed ("openpgp") && (!name || !strcmp (name, "openpgp"))) err = app_select_openpgp (app); if (err && is_app_allowed ("nks") && (!name || !strcmp (name, "nks"))) err = app_select_nks (app); if (err && is_app_allowed ("p15") && (!name || !strcmp (name, "p15"))) err = app_select_p15 (app); if (err && is_app_allowed ("geldkarte") && (!name || !strcmp (name, "geldkarte"))) err = app_select_geldkarte (app); if (err && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig"))) err = app_select_dinsig (app); if (err && name) err = gpg_error (GPG_ERR_NOT_SUPPORTED); leave: if (err) { if (name) log_info ("can't select application '%s': %s\n", name, gpg_strerror (err)); else log_info ("no supported card application found: %s\n", gpg_strerror (err)); xfree (app); unlock_reader (slot); return err; } app->ref_count = 1; lock_table[slot].app = app; *r_app = app; unlock_reader (slot); return 0; }
int set_native_charset( const char *newset ) { const char *full_newset; if (!newset) { #ifdef _WIN32 static char codepage[30]; unsigned int cpno; const char *aliases; /* We are a console program thus we need to use the GetConsoleOutputCP function and not the the GetACP which would give the codepage for a GUI program. Note this is not a bulletproof detection because GetConsoleCP might return a different one for console input. Not sure how to cope with that. If the console Code page is not known we fall back to the system code page. */ cpno = GetConsoleOutputCP (); if (!cpno) cpno = GetACP (); sprintf (codepage, "CP%u", cpno ); /* Resolve alias. We use a long string string and not the usual array to optimize if the code is taken to a DSO. Taken from libiconv 1.9.2. */ newset = codepage; for (aliases = ("CP936" "\0" "GBK" "\0" "CP1361" "\0" "JOHAB" "\0" "CP20127" "\0" "ASCII" "\0" "CP20866" "\0" "KOI8-R" "\0" "CP21866" "\0" "KOI8-RU" "\0" "CP28591" "\0" "ISO-8859-1" "\0" "CP28592" "\0" "ISO-8859-2" "\0" "CP28593" "\0" "ISO-8859-3" "\0" "CP28594" "\0" "ISO-8859-4" "\0" "CP28595" "\0" "ISO-8859-5" "\0" "CP28596" "\0" "ISO-8859-6" "\0" "CP28597" "\0" "ISO-8859-7" "\0" "CP28598" "\0" "ISO-8859-8" "\0" "CP28599" "\0" "ISO-8859-9" "\0" "CP28605" "\0" "ISO-8859-15" "\0" "CP65001" "\0" "UTF-8" "\0"); *aliases; aliases += strlen (aliases) + 1, aliases += strlen (aliases) + 1) { if (!strcmp (codepage, aliases) ||(*aliases == '*' && !aliases[1])) { newset = aliases + strlen (aliases) + 1; break; } } #else #ifdef HAVE_LANGINFO_CODESET newset = nl_langinfo (CODESET); #else /* !HAVE_LANGINFO_CODESET */ /* Try to get the used charset from environment variables. */ static char codepage[30]; const char *lc, *dot, *mod; strcpy (codepage, "iso-8859-1"); lc = getenv ("LC_ALL"); if (!lc || !*lc) { lc = getenv ("LC_CTYPE"); if (!lc || !*lc) lc = getenv ("LANG"); } if (lc && *lc) { dot = strchr (lc, '.'); if (dot) { mod = strchr (++dot, '@'); if (!mod) mod = dot + strlen (dot); if (mod - dot < sizeof codepage && dot != mod) { memcpy (codepage, dot, mod - dot); codepage [mod - dot] = 0; } } } newset = codepage; #endif /* !HAVE_LANGINFO_CODESET */ #endif } full_newset = newset; if (strlen (newset) > 3 && !ascii_memcasecmp (newset, "iso", 3)) { newset += 3; if (*newset == '-' || *newset == '_') newset++; } /* Note that we silently assume that plain ASCII is actually meant as Latin-1. This makes sense because many Unix system don't have their locale set up properly and thus would get annoying error messages and we have to handle all the "bug" reports. Latin-1 has always been the character set used for 8 bit characters on Unix systems. */ if( !*newset || !ascii_strcasecmp (newset, "8859-1" ) || !ascii_strcasecmp (newset, "646" ) || !ascii_strcasecmp (newset, "ASCII" ) || !ascii_strcasecmp (newset, "ANSI_X3.4-1968" ) ) { active_charset_name = "iso-8859-1"; no_translation = 0; active_charset = NULL; use_iconv = 0; } else if( !ascii_strcasecmp (newset, "utf8" ) || !ascii_strcasecmp(newset, "utf-8") ) { active_charset_name = "utf-8"; no_translation = 1; active_charset = NULL; use_iconv = 0; } #ifdef USE_GNUPG_ICONV else { iconv_t cd; #ifdef _WIN32 if (load_libiconv ()) return G10ERR_GENERAL; #endif /*_WIN32*/ cd = iconv_open (full_newset, "utf-8"); if (cd == (iconv_t)-1) { handle_iconv_error (full_newset, "utf-8", 0); return G10ERR_GENERAL; } iconv_close (cd); cd = iconv_open ("utf-8", full_newset); if (cd == (iconv_t)-1) { handle_iconv_error ("utf-8", full_newset, 0); return G10ERR_GENERAL; } iconv_close (cd); active_charset_name = full_newset; no_translation = 0; active_charset = NULL; use_iconv = 1; } #else /*!USE_GNUPG_ICONV*/ else if( !ascii_strcasecmp( newset, "8859-2" ) ) {
int main(int argc,char *argv[]) { int arg,ret=KEYSERVER_INTERNAL_ERROR,try_srv=1; char line[MAX_LINE]; int failed=0; struct keylist *keylist=NULL,*keyptr=NULL; char *proxy=NULL; struct curl_slist *headers=NULL; console=stderr; /* Kludge to implement standard GNU options. */ if (argc > 1 && !strcmp (argv[1], "--version")) { printf ("gpgkeys_hkp (GnuPG) %s\n", VERSION); printf ("Uses: %s\n", curl_version()); return 0; } else if (argc > 1 && !strcmp (argv[1], "--help")) { show_help (stdout); return 0; } while((arg=getopt(argc,argv,"hVo:"))!=-1) switch(arg) { default: case 'h': show_help (console); return KEYSERVER_OK; case 'V': fprintf(stdout,"%d\n%s\n",KEYSERVER_PROTO_VERSION,VERSION); return KEYSERVER_OK; case 'o': output=fopen(optarg,"w"); if(output==NULL) { fprintf(console,"gpgkeys: Cannot open output file `%s': %s\n", optarg,strerror(errno)); return KEYSERVER_INTERNAL_ERROR; } break; } if(argc>optind) { input=fopen(argv[optind],"r"); if(input==NULL) { fprintf(console,"gpgkeys: Cannot open input file `%s': %s\n", argv[optind],strerror(errno)); return KEYSERVER_INTERNAL_ERROR; } } if(input==NULL) input=stdin; if(output==NULL) output=stdout; opt=init_ks_options(); if(!opt) return KEYSERVER_NO_MEMORY; /* Get the command and info block */ while(fgets(line,MAX_LINE,input)!=NULL) { int err; char option[MAX_OPTION+1]; if(line[0]=='\n') break; err=parse_ks_options(line,opt); if(err>0) { ret=err; goto fail; } else if(err==0) continue; if(sscanf(line,"OPTION %" MKSTRING(MAX_OPTION) "s\n",option)==1) { int no=0; char *start=&option[0]; option[MAX_OPTION]='\0'; if(ascii_strncasecmp(option,"no-",3)==0) { no=1; start=&option[3]; } if(ascii_strncasecmp(start,"http-proxy",10)==0) { if(no) { free(proxy); proxy=strdup(""); } else if(start[10]=='=') { if(strlen(&start[11])<MAX_PROXY) { free(proxy); proxy=strdup(&start[11]); } } } else if(ascii_strcasecmp(start,"try-dns-srv")==0) { if(no) try_srv=0; else try_srv=1; } continue; } } if(!opt->scheme) { fprintf(console,"gpgkeys: no scheme supplied!\n"); ret=KEYSERVER_SCHEME_NOT_FOUND; goto fail; } if(ascii_strcasecmp(opt->scheme,"hkps")==0) { proto="https"; port="443"; } else { proto="http"; port="11371"; } if(!opt->host) { fprintf(console,"gpgkeys: no keyserver host provided\n"); goto fail; } if(opt->timeout && register_timeout()==-1) { fprintf(console,"gpgkeys: unable to register timeout handler\n"); return KEYSERVER_INTERNAL_ERROR; } curl_global_init(CURL_GLOBAL_DEFAULT); curl=curl_easy_init(); if(!curl) { fprintf(console,"gpgkeys: unable to initialize curl\n"); ret=KEYSERVER_INTERNAL_ERROR; goto fail; } /* If the user gives a :port, then disable SRV. The semantics of a specified port and SRV do not play well together. */ if(opt->port) port=opt->port; else if(try_srv) { char *srvtag; if(ascii_strcasecmp(opt->scheme,"hkp")==0) srvtag="pgpkey-http"; else if(ascii_strcasecmp(opt->scheme,"hkps")==0) srvtag="pgpkey-https"; else srvtag=NULL; #ifdef HAVE_LIBCURL /* We're using libcurl, so fake SRV support via our wrapper. This isn't as good as true SRV support, as we do not try all possible targets at one particular level and work our way down the list, but it's better than nothing. */ srv_replace(srvtag); #else /* We're using our internal curl shim, so we can use its (true) SRV support. Obviously, CURLOPT_SRVTAG_GPG_HACK isn't a real libcurl option. It's specific to our shim. */ curl_easy_setopt(curl,CURLOPT_SRVTAG_GPG_HACK,srvtag); #endif } curl_easy_setopt(curl,CURLOPT_ERRORBUFFER,errorbuffer); if(opt->auth) curl_easy_setopt(curl,CURLOPT_USERPWD,opt->auth); if(opt->debug) { fprintf(console,"gpgkeys: curl version = %s\n",curl_version()); curl_easy_setopt(curl,CURLOPT_STDERR,console); curl_easy_setopt(curl,CURLOPT_VERBOSE,1L); } curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,(long)opt->flags.check_cert); curl_easy_setopt(curl,CURLOPT_CAINFO,opt->ca_cert_file); /* Avoid caches to get the most recent copy of the key. This is bug #1061. In pre-curl versions of the code, we didn't do it. Then we did do it (as a curl default) until curl changed the default. Now we're doing it again, but in such a way that changing defaults in the future won't impact us. We set both the Pragma and Cache-Control versions of the header, so we're good with both HTTP 1.0 and 1.1. */ headers=curl_slist_append(headers,"Pragma: no-cache"); if(headers) headers=curl_slist_append(headers,"Cache-Control: no-cache"); if(!headers) { fprintf(console,"gpgkeys: out of memory when building HTTP headers\n"); ret=KEYSERVER_NO_MEMORY; goto fail; } curl_easy_setopt(curl,CURLOPT_HTTPHEADER,headers); if(proxy) curl_easy_setopt(curl,CURLOPT_PROXY,proxy); /* If it's a GET or a SEARCH, the next thing to come in is the keyids. If it's a SEND, then there are no keyids. */ if(opt->action==KS_SEND) while(fgets(line,MAX_LINE,input)!=NULL && line[0]!='\n'); else if(opt->action==KS_GET || opt->action==KS_GETNAME || opt->action==KS_SEARCH) { for(;;) { struct keylist *work; if(fgets(line,MAX_LINE,input)==NULL) break; else { if(line[0]=='\n' || line[0]=='\0') break; work=xtrymalloc(sizeof(struct keylist)); if(work==NULL) { fprintf(console,"gpgkeys: out of memory while " "building key list\n"); ret=KEYSERVER_NO_MEMORY; goto fail; } strcpy(work->str,line); /* Trim the trailing \n */ work->str[strlen(line)-1]='\0'; work->next=NULL; /* Always attach at the end to keep the list in proper order for searching */ if(keylist==NULL) keylist=work; else keyptr->next=work; keyptr=work; } } } else { fprintf(console,"gpgkeys: no keyserver command specified\n"); goto fail; } /* Send the response */ fprintf(output,"VERSION %d\n",KEYSERVER_PROTO_VERSION); fprintf(output,"PROGRAM %s %s\n\n",VERSION,curl_version()); if(opt->verbose>1) { fprintf(console,"Host:\t\t%s\n",opt->host); if(opt->port) fprintf(console,"Port:\t\t%s\n",opt->port); if(strcmp(opt->path,"/")!=0) fprintf(console,"Path:\t\t%s\n",opt->path); fprintf(console,"Command:\t%s\n",ks_action_to_string(opt->action)); } if(opt->action==KS_GET) { keyptr=keylist; while(keyptr!=NULL) { set_timeout(opt->timeout); if(get_key(keyptr->str)!=KEYSERVER_OK) failed++; keyptr=keyptr->next; } } else if(opt->action==KS_GETNAME) { keyptr=keylist; while(keyptr!=NULL) { set_timeout(opt->timeout); if(get_name(keyptr->str)!=KEYSERVER_OK) failed++; keyptr=keyptr->next; } } else if(opt->action==KS_SEND) { int eof=0; do { set_timeout(opt->timeout); if(send_key(&eof)!=KEYSERVER_OK) failed++; } while(!eof); } else if(opt->action==KS_SEARCH) { char *searchkey=NULL; int len=0; set_timeout(opt->timeout); /* To search, we stick a space in between each key to search for. */ keyptr=keylist; while(keyptr!=NULL) { len+=strlen(keyptr->str)+1; keyptr=keyptr->next; } searchkey=xtrymalloc(len+1); if(searchkey==NULL) { ret=KEYSERVER_NO_MEMORY; fail_all(keylist,KEYSERVER_NO_MEMORY); goto fail; } searchkey[0]='\0'; keyptr=keylist; while(keyptr!=NULL) { strcat(searchkey,keyptr->str); strcat(searchkey," "); keyptr=keyptr->next; } /* Nail that last space */ if(*searchkey) searchkey[strlen(searchkey)-1]='\0'; if(search_key(searchkey)!=KEYSERVER_OK) failed++; free(searchkey); } else abort(); if(!failed) ret=KEYSERVER_OK; fail: while(keylist!=NULL) { struct keylist *current=keylist; keylist=keylist->next; free(current); } if(input!=stdin) fclose(input); if(output!=stdout) fclose(output); free_ks_options(opt); curl_slist_free_all(headers); if(curl) curl_easy_cleanup(curl); free(proxy); return ret; }
int mutt_prepare_template (FILE *fp, CONTEXT *ctx, HEADER *newhdr, HEADER *hdr, short weed) { MESSAGE *msg = NULL; char file[_POSIX_PATH_MAX]; BODY *b; FILE *bfp; int rv = -1; STATE s; memset (&s, 0, sizeof (s)); if (!fp && (msg = mx_open_message (ctx, hdr->msgno)) == NULL) return (-1); if (!fp) fp = msg->fp; bfp = fp; /* parse the message header and MIME structure */ fseeko (fp, hdr->offset, 0); newhdr->offset = hdr->offset; newhdr->env = mutt_read_rfc822_header (fp, newhdr, 1, weed); newhdr->content->length = hdr->content->length; mutt_parse_part (fp, newhdr->content); /* If message_id is set, then we are resending a message and don't want * message_id or mail_followup_to. Otherwise, we are resuming a * postponed message, and want to keep the mail_followup_to. */ if (newhdr->env->message_id != NULL) { FREE (&newhdr->env->message_id); FREE (&newhdr->env->mail_followup_to); } /* decrypt pgp/mime encoded messages */ if ((WithCrypto & (APPLICATION_PGP|APPLICATION_SMIME) & hdr->security) && mutt_is_multipart_encrypted (newhdr->content)) { int ccap = WithCrypto & (APPLICATION_PGP|APPLICATION_SMIME) & hdr->security; newhdr->security |= ENCRYPT | ccap; if (!crypt_valid_passphrase (ccap)) goto err; mutt_message _("Decrypting message..."); if (((ccap & APPLICATION_PGP) && crypt_pgp_decrypt_mime (fp, &bfp, newhdr->content, &b) == -1) || ((ccap & APPLICATION_SMIME) && crypt_smime_decrypt_mime (fp, &bfp, newhdr->content, &b) == -1) || b == NULL) { err: mx_close_message (&msg); mutt_free_envelope (&newhdr->env); mutt_free_body (&newhdr->content); mutt_error _("Decryption failed."); return -1; } mutt_free_body (&newhdr->content); newhdr->content = b; mutt_clear_error (); } /* * remove a potential multipart/signed layer - useful when * resending messages */ if (WithCrypto && mutt_is_multipart_signed (newhdr->content)) { newhdr->security |= SIGN; if ((WithCrypto & APPLICATION_PGP) && ascii_strcasecmp (mutt_get_parameter ("protocol", newhdr->content->parameter), "application/pgp-signature") == 0) newhdr->security |= APPLICATION_PGP; else if ((WithCrypto & APPLICATION_SMIME)) newhdr->security |= APPLICATION_SMIME; /* destroy the signature */ mutt_free_body (&newhdr->content->parts->next); newhdr->content = mutt_remove_multipart (newhdr->content); } /* * We don't need no primary multipart. * Note: We _do_ preserve messages! * * XXX - we don't handle multipart/alternative in any * smart way when sending messages. However, one may * consider this a feature. * */ if (newhdr->content->type == TYPEMULTIPART) newhdr->content = mutt_remove_multipart (newhdr->content); s.fpin = bfp; /* create temporary files for all attachments */ for (b = newhdr->content; b; b = b->next) { /* what follows is roughly a receive-mode variant of * mutt_get_tmp_attachment () from muttlib.c */ file[0] = '\0'; if (b->filename) { strfcpy (file, b->filename, sizeof (file)); b->d_filename = safe_strdup (b->filename); } else { /* avoid Content-Disposition: header with temporary filename */ b->use_disp = 0; } /* set up state flags */ s.flags = 0; if (b->type == TYPETEXT) { if (!ascii_strcasecmp ("yes", mutt_get_parameter ("x-mutt-noconv", b->parameter))) b->noconv = 1; else { s.flags |= M_CHARCONV; b->noconv = 0; } mutt_delete_parameter ("x-mutt-noconv", &b->parameter); } mutt_adv_mktemp (file, sizeof(file)); if ((s.fpout = safe_fopen (file, "w")) == NULL) goto bail; if ((WithCrypto & APPLICATION_PGP) && (mutt_is_application_pgp (b) & (ENCRYPT|SIGN))) { mutt_body_handler (b, &s); newhdr->security |= mutt_is_application_pgp (newhdr->content); b->type = TYPETEXT; mutt_str_replace (&b->subtype, "plain"); mutt_delete_parameter ("x-action", &b->parameter); } else mutt_decode_attachment (b, &s); if (safe_fclose (&s.fpout) != 0) goto bail; mutt_str_replace (&b->filename, file); b->unlink = 1; mutt_stamp_attachment (b); mutt_free_body (&b->parts); if (b->hdr) b->hdr->content = NULL; /* avoid dangling pointer */ } /* Fix encryption flags. */ /* No inline if multipart. */ if (WithCrypto && (newhdr->security & INLINE) && newhdr->content->next) newhdr->security &= ~INLINE; /* Do we even support multiple mechanisms? */ newhdr->security &= WithCrypto | ~(APPLICATION_PGP|APPLICATION_SMIME); /* Theoretically, both could be set. Take the one the user wants to set by default. */ if ((newhdr->security & APPLICATION_PGP) && (newhdr->security & APPLICATION_SMIME)) { if (option (OPTSMIMEISDEFAULT)) newhdr->security &= ~APPLICATION_PGP; else newhdr->security &= ~APPLICATION_SMIME; } rv = 0; bail: /* that's it. */ if (bfp != fp) safe_fclose (&bfp); if (msg) mx_close_message (&msg); if (rv == -1) { mutt_free_envelope (&newhdr->env); mutt_free_body (&newhdr->content); } return rv; }
int ci_send_message (int flags, /* send mode */ HEADER *msg, /* template to use for new message */ char *tempfile, /* file specified by -i or -H */ CONTEXT *ctx, /* current mailbox */ HEADER *cur) /* current message */ { char buffer[LONG_STRING]; char fcc[_POSIX_PATH_MAX] = ""; /* where to copy this message */ FILE *tempfp = NULL; BODY *pbody; int i, killfrom = 0; int fcc_error = 0; int free_clear_content = 0; BODY *save_content = NULL; BODY *clear_content = NULL; char *pgpkeylist = NULL; /* save current value of "pgp_sign_as" */ char *signas = NULL; char *tag = NULL, *err = NULL; char *ctype; int rv = -1; if (!flags && !msg && quadoption (OPT_RECALL) != M_NO && mutt_num_postponed (1)) { /* If the user is composing a new message, check to see if there * are any postponed messages first. */ if ((i = query_quadoption (OPT_RECALL, _("Recall postponed message?"))) == -1) return rv; if(i == M_YES) flags |= SENDPOSTPONED; } if ((WithCrypto & APPLICATION_PGP) && (flags & SENDPOSTPONED)) signas = safe_strdup(PgpSignAs); /* Delay expansion of aliases until absolutely necessary--shouldn't * be necessary unless we are prompting the user or about to execute a * send-hook. */ if (!msg) { msg = mutt_new_header (); if (flags == SENDPOSTPONED) { if ((flags = mutt_get_postponed (ctx, msg, &cur, fcc, sizeof (fcc))) < 0) goto cleanup; } if (flags & (SENDPOSTPONED|SENDRESEND)) { if ((tempfp = safe_fopen (msg->content->filename, "a+")) == NULL) { mutt_perror (msg->content->filename); goto cleanup; } } if (!msg->env) msg->env = mutt_new_envelope (); } /* Parse and use an eventual list-post header */ if ((flags & SENDLISTREPLY) && cur && cur->env && cur->env->list_post) { /* Use any list-post header as a template */ url_parse_mailto (msg->env, NULL, cur->env->list_post); /* We don't let them set the sender's address. */ rfc822_free_address (&msg->env->from); } if (! (flags & (SENDKEY | SENDPOSTPONED | SENDRESEND))) { pbody = mutt_new_body (); pbody->next = msg->content; /* don't kill command-line attachments */ msg->content = pbody; if (!(ctype = safe_strdup (ContentType))) ctype = safe_strdup ("text/plain"); mutt_parse_content_type (ctype, msg->content); FREE (&ctype); msg->content->unlink = 1; msg->content->use_disp = 0; msg->content->disposition = DISPINLINE; if (!tempfile) { mutt_mktemp (buffer, sizeof (buffer)); tempfp = safe_fopen (buffer, "w+"); msg->content->filename = safe_strdup (buffer); } else { tempfp = safe_fopen (tempfile, "a+"); msg->content->filename = safe_strdup (tempfile); } if (!tempfp) { dprint(1,(debugfile, "newsend_message: can't create tempfile %s (errno=%d)\n", msg->content->filename, errno)); mutt_perror (msg->content->filename); goto cleanup; } } /* this is handled here so that the user can match ~f in send-hook */ if (cur && option (OPTREVNAME) && !(flags & (SENDPOSTPONED|SENDRESEND))) { /* we shouldn't have to worry about freeing `msg->env->from' before * setting it here since this code will only execute when doing some * sort of reply. the pointer will only be set when using the -H command * line option. * * We shouldn't have to worry about alias expansion here since we are * either replying to a real or postponed message, therefore no aliases * should exist since the user has not had the opportunity to add * addresses to the list. We just have to ensure the postponed messages * have their aliases expanded. */ msg->env->from = set_reverse_name (cur->env); } if (! (flags & (SENDPOSTPONED|SENDRESEND))) { if ((flags & (SENDREPLY | SENDFORWARD)) && ctx && envelope_defaults (msg->env, ctx, cur, flags) == -1) goto cleanup; if (option (OPTHDRS)) process_user_recips (msg->env); /* Expand aliases and remove duplicates/crossrefs */ mutt_expand_aliases_env (msg->env); if (flags & SENDREPLY) mutt_fix_reply_recipients (msg->env); if (! (flags & (SENDMAILX|SENDBATCH)) && ! (option (OPTAUTOEDIT) && option (OPTEDITHDRS)) && ! ((flags & SENDREPLY) && option (OPTFASTREPLY))) { if (edit_envelope (msg->env) == -1) goto cleanup; } /* the from address must be set here regardless of whether or not * $use_from is set so that the `~P' (from you) operator in send-hook * patterns will work. if $use_from is unset, the from address is killed * after send-hooks are evaulated */ if (!msg->env->from) { msg->env->from = mutt_default_from (); killfrom = 1; } if ((flags & SENDREPLY) && cur) { /* change setting based upon message we are replying to */ mutt_message_hook (ctx, cur, M_REPLYHOOK); /* * set the replied flag for the message we are generating so that the * user can use ~Q in a send-hook to know when reply-hook's are also * being used. */ msg->replied = 1; } /* change settings based upon recipients */ mutt_message_hook (NULL, msg, M_SENDHOOK); /* * Unset the replied flag from the message we are composing since it is * no longer required. This is done here because the FCC'd copy of * this message was erroneously get the 'R'eplied flag when stored in * a maildir-style mailbox. */ msg->replied = 0; if (! (flags & SENDKEY)) { if (option (OPTTEXTFLOWED) && msg->content->type == TYPETEXT && !ascii_strcasecmp (msg->content->subtype, "plain")) mutt_set_parameter ("format", "flowed", &msg->content->parameter); } /* $use_from and/or $from might have changed in a send-hook */ if (killfrom) { rfc822_free_address (&msg->env->from); if (option (OPTUSEFROM) && !(flags & (SENDPOSTPONED|SENDRESEND))) msg->env->from = mutt_default_from (); killfrom = 0; } if (option (OPTHDRS)) process_user_header (msg->env); if (flags & SENDBATCH) mutt_copy_stream (stdin, tempfp); if (option (OPTSIGONTOP) && ! (flags & (SENDMAILX|SENDKEY|SENDBATCH)) && Editor && mutt_strcmp (Editor, "builtin") != 0) append_signature (tempfp); /* include replies/forwarded messages, unless we are given a template */ if (!tempfile && (ctx || !(flags & (SENDREPLY|SENDFORWARD))) && generate_body (tempfp, msg, flags, ctx, cur) == -1) goto cleanup; if (!option (OPTSIGONTOP) && ! (flags & (SENDMAILX|SENDKEY|SENDBATCH)) && Editor && mutt_strcmp (Editor, "builtin") != 0) append_signature (tempfp); } /* * This hook is even called for postponed messages, and can, e.g., be * used for setting the editor, the sendmail path, or the * envelope sender. */ mutt_message_hook (NULL, msg, M_SEND2HOOK); /* wait until now to set the real name portion of our return address so that $realname can be set in a send-hook */ if (msg->env->from && !msg->env->from->personal && !(flags & (SENDRESEND|SENDPOSTPONED))) msg->env->from->personal = safe_strdup (Realname); if (!((WithCrypto & APPLICATION_PGP) && (flags & SENDKEY))) safe_fclose (&tempfp); if (flags & SENDMAILX) { if (mutt_builtin_editor (msg->content->filename, msg, cur) == -1) goto cleanup; } else if (! (flags & SENDBATCH)) { struct stat st; time_t mtime = mutt_decrease_mtime (msg->content->filename, NULL); mutt_update_encoding (msg->content); /* * Select whether or not the user's editor should be called now. We * don't want to do this when: * 1) we are sending a key/cert * 2) we are forwarding a message and the user doesn't want to edit it. * This is controlled by the quadoption $forward_edit. However, if * both $edit_headers and $autoedit are set, we want to ignore the * setting of $forward_edit because the user probably needs to add the * recipients. */ if (! (flags & SENDKEY) && ((flags & SENDFORWARD) == 0 || (option (OPTEDITHDRS) && option (OPTAUTOEDIT)) || query_quadoption (OPT_FORWEDIT, _("Edit forwarded message?")) == M_YES)) { /* If the this isn't a text message, look for a mailcap edit command */ if (mutt_needs_mailcap (msg->content)) { if (!mutt_edit_attachment (msg->content)) goto cleanup; } else if (!Editor || mutt_strcmp ("builtin", Editor) == 0) mutt_builtin_editor (msg->content->filename, msg, cur); else if (option (OPTEDITHDRS)) { mutt_env_to_local (msg->env); mutt_edit_headers (Editor, msg->content->filename, msg, fcc, sizeof (fcc)); mutt_env_to_idna (msg->env, NULL, NULL); } else { mutt_edit_file (Editor, msg->content->filename); if (stat (msg->content->filename, &st) == 0) { if (mtime != st.st_mtime) fix_end_of_file (msg->content->filename); } else mutt_perror (msg->content->filename); } /* If using format=flowed, perform space stuffing. Avoid stuffing when * recalling a postponed message where the stuffing was already * performed. If it has already been performed, the format=flowed * parameter will be present. */ if (option (OPTTEXTFLOWED) && msg->content->type == TYPETEXT && !ascii_strcasecmp("plain", msg->content->subtype)) { char *p = mutt_get_parameter("format", msg->content->parameter); if (ascii_strcasecmp("flowed", NONULL(p))) rfc3676_space_stuff (msg); } mutt_message_hook (NULL, msg, M_SEND2HOOK); } if (! (flags & (SENDPOSTPONED | SENDFORWARD | SENDKEY | SENDRESEND))) { if (stat (msg->content->filename, &st) == 0) { /* if the file was not modified, bail out now */ if (mtime == st.st_mtime && !msg->content->next && query_quadoption (OPT_ABORT, _("Abort unmodified message?")) == M_YES) { mutt_message _("Aborted unmodified message."); goto cleanup; } } else mutt_perror (msg->content->filename); } } /* * Set the message security unless: * 1) crypto support is not enabled (WithCrypto==0) * 2) pgp: header field was present during message editing with $edit_headers (msg->security != 0) * 3) we are resending a message * 4) we are recalling a postponed message (don't override the user's saved settings) * 5) we are in mailx mode * 6) we are in batch mode * * This is done after allowing the user to edit the message so that security * settings can be configured with send2-hook and $edit_headers. */ if (WithCrypto && (msg->security == 0) && !(flags & (SENDBATCH | SENDMAILX | SENDPOSTPONED | SENDRESEND))) { if (option (OPTCRYPTAUTOSIGN)) msg->security |= SIGN; if (option (OPTCRYPTAUTOENCRYPT)) msg->security |= ENCRYPT; if (option (OPTCRYPTREPLYENCRYPT) && cur && (cur->security & ENCRYPT)) msg->security |= ENCRYPT; if (option (OPTCRYPTREPLYSIGN) && cur && (cur->security & SIGN)) msg->security |= SIGN; if (option (OPTCRYPTREPLYSIGNENCRYPTED) && cur && (cur->security & ENCRYPT)) msg->security |= SIGN; if (WithCrypto & APPLICATION_PGP && (msg->security & (ENCRYPT | SIGN))) { if (option (OPTPGPAUTOINLINE)) msg->security |= INLINE; if (option (OPTPGPREPLYINLINE) && cur && (cur->security & INLINE)) msg->security |= INLINE; } if (msg->security) { /* * When replying / forwarding, use the original message's * crypto system. According to the documentation, * smime_is_default should be disregarded here. * * Problem: At least with forwarding, this doesn't really * make much sense. Should we have an option to completely * disable individual mechanisms at run-time? */ if (cur) { if ((WithCrypto & APPLICATION_PGP) && option (OPTCRYPTAUTOPGP) && (cur->security & APPLICATION_PGP)) msg->security |= APPLICATION_PGP; else if ((WithCrypto & APPLICATION_SMIME) && option (OPTCRYPTAUTOSMIME) && (cur->security & APPLICATION_SMIME)) msg->security |= APPLICATION_SMIME; } /* * No crypto mechanism selected? Use availability + smime_is_default * for the decision. */ if (!(msg->security & (APPLICATION_SMIME | APPLICATION_PGP))) { if ((WithCrypto & APPLICATION_SMIME) && option (OPTCRYPTAUTOSMIME) && option (OPTSMIMEISDEFAULT)) msg->security |= APPLICATION_SMIME; else if ((WithCrypto & APPLICATION_PGP) && option (OPTCRYPTAUTOPGP)) msg->security |= APPLICATION_PGP; else if ((WithCrypto & APPLICATION_SMIME) && option (OPTCRYPTAUTOSMIME)) msg->security |= APPLICATION_SMIME; } } /* No permissible mechanisms found. Don't sign or encrypt. */ if (!(msg->security & (APPLICATION_SMIME|APPLICATION_PGP))) msg->security = 0; } /* specify a default fcc. if we are in batchmode, only save a copy of * the message if the value of $copy is yes or ask-yes */ if (!fcc[0] && !(flags & (SENDPOSTPONED)) && (!(flags & SENDBATCH) || (quadoption (OPT_COPY) & 0x1))) { /* set the default FCC */ if (!msg->env->from) { msg->env->from = mutt_default_from (); killfrom = 1; /* no need to check $use_from because if the user specified a from address it would have already been set by now */ } mutt_select_fcc (fcc, sizeof (fcc), msg); if (killfrom) { rfc822_free_address (&msg->env->from); killfrom = 0; } } mutt_update_encoding (msg->content); if (! (flags & (SENDMAILX | SENDBATCH))) { main_loop: fcc_error = 0; /* reset value since we may have failed before */ mutt_pretty_mailbox (fcc, sizeof (fcc)); i = mutt_compose_menu (msg, fcc, sizeof (fcc), cur); if (i == -1) { /* abort */ mutt_message _("Mail not sent."); goto cleanup; } else if (i == 1) { /* postpone the message until later. */ if (msg->content->next) msg->content = mutt_make_multipart (msg->content); /* * make sure the message is written to the right part of a maildir * postponed folder. */ msg->read = 0; msg->old = 0; encode_descriptions (msg->content, 1); mutt_prepare_envelope (msg->env, 0); mutt_env_to_idna (msg->env, NULL, NULL); /* Handle bad IDNAs the next time. */ if (!Postponed || mutt_write_fcc (NONULL (Postponed), msg, (cur && (flags & SENDREPLY)) ? cur->env->message_id : NULL, 1, fcc) < 0) { msg->content = mutt_remove_multipart (msg->content); decode_descriptions (msg->content); mutt_unprepare_envelope (msg->env); goto main_loop; } mutt_update_num_postponed (); mutt_message _("Message postponed."); goto cleanup; } } if (!has_recips (msg->env->to) && !has_recips (msg->env->cc) && !has_recips (msg->env->bcc)) { if (! (flags & SENDBATCH)) { mutt_error _("No recipients are specified!"); goto main_loop; } else { puts _("No recipients were specified."); goto cleanup; } } if (mutt_env_to_idna (msg->env, &tag, &err)) { mutt_error (_("Bad IDN in \"%s\": '%s'"), tag, err); FREE (&err); if (!(flags & SENDBATCH)) goto main_loop; else goto cleanup; } if (!msg->env->subject && ! (flags & SENDBATCH) && (i = query_quadoption (OPT_SUBJECT, _("No subject, abort sending?"))) != M_NO) { /* if the abort is automatic, print an error message */ if (quadoption (OPT_SUBJECT) == M_YES) mutt_error _("No subject specified."); goto main_loop; } if (msg->content->next) msg->content = mutt_make_multipart (msg->content); /* * Ok, we need to do it this way instead of handling all fcc stuff in * one place in order to avoid going to main_loop with encoded "env" * in case of error. Ugh. */ encode_descriptions (msg->content, 1); /* * Make sure that clear_content and free_clear_content are * properly initialized -- we may visit this particular place in * the code multiple times, including after a failed call to * mutt_protect(). */ clear_content = NULL; free_clear_content = 0; if (WithCrypto) { if (msg->security) { /* save the decrypted attachments */ clear_content = msg->content; if ((crypt_get_keys (msg, &pgpkeylist) == -1) || mutt_protect (msg, pgpkeylist) == -1) { msg->content = mutt_remove_multipart (msg->content); FREE (&pgpkeylist); decode_descriptions (msg->content); goto main_loop; } encode_descriptions (msg->content, 0); } /* * at this point, msg->content is one of the following three things: * - multipart/signed. In this case, clear_content is a child. * - multipart/encrypted. In this case, clear_content exists * independently * - application/pgp. In this case, clear_content exists independently. * - something else. In this case, it's the same as clear_content. */ /* This is ugly -- lack of "reporting back" from mutt_protect(). */ if (clear_content && (msg->content != clear_content) && (msg->content->parts != clear_content)) free_clear_content = 1; } if (!option (OPTNOCURSES) && !(flags & SENDMAILX)) mutt_message _("Sending message..."); mutt_prepare_envelope (msg->env, 1); /* save a copy of the message, if necessary. */ mutt_expand_path (fcc, sizeof (fcc)); /* Don't save a copy when we are in batch-mode, and the FCC * folder is on an IMAP server: This would involve possibly lots * of user interaction, which is not available in batch mode. * * Note: A patch to fix the problems with the use of IMAP servers * from non-curses mode is available from Brendan Cully. However, * I'd like to think a bit more about this before including it. */ #ifdef USE_IMAP if ((flags & SENDBATCH) && fcc[0] && mx_is_imap (fcc)) fcc[0] = '\0'; #endif if (*fcc && mutt_strcmp ("/dev/null", fcc) != 0) { BODY *tmpbody = msg->content; BODY *save_sig = NULL; BODY *save_parts = NULL; if (WithCrypto && msg->security && option (OPTFCCCLEAR)) msg->content = clear_content; /* check to see if the user wants copies of all attachments */ if (query_quadoption (OPT_FCCATTACH, _("Save attachments in Fcc?")) != M_YES && msg->content->type == TYPEMULTIPART) { if (WithCrypto && (mutt_strcmp (msg->content->subtype, "encrypted") == 0 || mutt_strcmp (msg->content->subtype, "signed") == 0)) { if (clear_content->type == TYPEMULTIPART) { if(!(msg->security & ENCRYPT) && (msg->security & SIGN)) { /* save initial signature and attachments */ save_sig = msg->content->parts->next; save_parts = clear_content->parts->next; } /* this means writing only the main part */ msg->content = clear_content->parts; if (mutt_protect (msg, pgpkeylist) == -1) { /* we can't do much about it at this point, so * fallback to saving the whole thing to fcc */ msg->content = tmpbody; save_sig = NULL; goto full_fcc; } save_content = msg->content; } } else msg->content = msg->content->parts; } full_fcc: if (msg->content) { /* update received time so that when storing to a mbox-style folder * the From_ line contains the current time instead of when the * message was first postponed. */ msg->received = time (NULL); if (mutt_write_fcc (fcc, msg, NULL, 0, NULL) == -1) { /* * Error writing FCC, we should abort sending. */ fcc_error = 1; } } msg->content = tmpbody; if (WithCrypto && save_sig) { /* cleanup the second signature structures */ if (save_content->parts) { mutt_free_body (&save_content->parts->next); save_content->parts = NULL; } mutt_free_body (&save_content); /* restore old signature and attachments */ msg->content->parts->next = save_sig; msg->content->parts->parts->next = save_parts; } else if (WithCrypto && save_content) { /* destroy the new encrypted body. */ mutt_free_body (&save_content); } } /* * Don't attempt to send the message if the FCC failed. Just pretend * the send failed as well so we give the user a chance to fix the * error. */ if (fcc_error || (i = send_message (msg)) < 0) { if (!(flags & SENDBATCH)) { if (!WithCrypto) ; else if ((msg->security & ENCRYPT) || ((msg->security & SIGN) && msg->content->type == TYPEAPPLICATION)) { mutt_free_body (&msg->content); /* destroy PGP data */ msg->content = clear_content; /* restore clear text. */ } else if ((msg->security & SIGN) && msg->content->type == TYPEMULTIPART) { mutt_free_body (&msg->content->parts->next); /* destroy sig */ msg->content = mutt_remove_multipart (msg->content); } msg->content = mutt_remove_multipart (msg->content); decode_descriptions (msg->content); mutt_unprepare_envelope (msg->env); goto main_loop; } else { puts _("Could not send the message."); goto cleanup; } } else if (!option (OPTNOCURSES) && ! (flags & SENDMAILX)) mutt_message (i == 0 ? _("Mail sent.") : _("Sending in background.")); if (WithCrypto && (msg->security & ENCRYPT)) FREE (&pgpkeylist); if (WithCrypto && free_clear_content) mutt_free_body (&clear_content); /* set 'replied' flag only if the user didn't change/remove In-Reply-To: and References: headers during edit */ if (flags & SENDREPLY) { if (cur && ctx) mutt_set_flag (ctx, cur, M_REPLIED, is_reply (cur, msg)); else if (!(flags & SENDPOSTPONED) && ctx && ctx->tagged) { for (i = 0; i < ctx->vcount; i++) if (ctx->hdrs[ctx->v2r[i]]->tagged) mutt_set_flag (ctx, ctx->hdrs[ctx->v2r[i]], M_REPLIED, is_reply (ctx->hdrs[ctx->v2r[i]], msg)); } } rv = 0; cleanup: if ((WithCrypto & APPLICATION_PGP) && (flags & SENDPOSTPONED)) { if(signas) { FREE (&PgpSignAs); PgpSignAs = signas; } } safe_fclose (&tempfp); mutt_free_header (&msg); return rv; }
/* Returns a keyrec (which must be freed) once a key is complete, and NULL otherwise. Call with a NULL keystring once key parsing is complete to return any unfinished keys. */ static struct keyrec * parse_keyrec(char *keystring) { /* FIXME: Remove the static and put the data into the parms we use for the caller anyway. */ static struct keyrec *work=NULL; struct keyrec *ret=NULL; char *record; int i; if(keystring==NULL) { if(work==NULL) return NULL; else if(work->desc.mode==KEYDB_SEARCH_MODE_NONE) { xfree(work); return NULL; } else { ret=work; work=NULL; return ret; } } if(work==NULL) { work=xmalloc_clear(sizeof(struct keyrec)); work->uidbuf=iobuf_temp(); } trim_trailing_ws (keystring, strlen (keystring)); if((record=strsep(&keystring,":"))==NULL) return ret; if(ascii_strcasecmp("pub",record)==0) { char *tok; gpg_error_t err; if(work->desc.mode) { ret=work; work=xmalloc_clear(sizeof(struct keyrec)); work->uidbuf=iobuf_temp(); } if((tok=strsep(&keystring,":"))==NULL) return ret; err = classify_user_id (tok, &work->desc, 1); if (err || (work->desc.mode != KEYDB_SEARCH_MODE_SHORT_KID && work->desc.mode != KEYDB_SEARCH_MODE_LONG_KID && work->desc.mode != KEYDB_SEARCH_MODE_FPR16 && work->desc.mode != KEYDB_SEARCH_MODE_FPR20)) { work->desc.mode=KEYDB_SEARCH_MODE_NONE; return ret; } /* Note all items after this are optional. This allows us to have a pub line as simple as pub:keyid and nothing else. */ work->lines++; if((tok=strsep(&keystring,":"))==NULL) return ret; work->type=atoi(tok); if((tok=strsep(&keystring,":"))==NULL) return ret; work->size=atoi(tok); if((tok=strsep(&keystring,":"))==NULL) return ret; if(atoi(tok)<=0) work->createtime=0; else work->createtime=atoi(tok); if((tok=strsep(&keystring,":"))==NULL) return ret; if(atoi(tok)<=0) work->expiretime=0; else { work->expiretime=atoi(tok); /* Force the 'e' flag on if this key is expired. */ if(work->expiretime<=make_timestamp()) work->flags|=4; } if((tok=strsep(&keystring,":"))==NULL) return ret; while(*tok) switch(*tok++) { case 'r': case 'R': work->flags|=1; break; case 'd': case 'D': work->flags|=2; break; case 'e': case 'E': work->flags|=4; break; } } else if(ascii_strcasecmp("uid",record)==0 && work->desc.mode) { char *userid,*tok,*decoded; if((tok=strsep(&keystring,":"))==NULL) return ret; if(strlen(tok)==0) return ret; userid=tok; /* By definition, de-%-encoding is always smaller than the original string so we can decode in place. */ i=0; while(*tok) if(tok[0]=='%' && tok[1] && tok[2]) { int c; userid[i] = (c=hextobyte(&tok[1])) == -1 ? '?' : c; i++; tok+=3; } else userid[i++]=*tok++; /* We don't care about the other info provided in the uid: line since no keyserver supports marking userids with timestamps or revoked/expired/disabled yet. */ /* No need to check for control characters, as utf8_to_native does this for us. */ decoded=utf8_to_native(userid,i,0); if(strlen(decoded)>opt.screen_columns-10) decoded[opt.screen_columns-10]='\0'; iobuf_writestr(work->uidbuf,decoded); xfree(decoded); iobuf_writestr(work->uidbuf,"\n\t"); work->lines++; } /* Ignore any records other than "pri" and "uid" for easy future growth. */ return ret; }
static void slow_gatherer_windowsNT( void (*add)(const void*, size_t, int), int requester ) { static int is_initialized = 0; static NETSTATISTICSGET pNetStatisticsGet = NULL; static NETAPIBUFFERSIZE pNetApiBufferSize = NULL; static NETAPIBUFFERFREE pNetApiBufferFree = NULL; static int is_workstation = 1; static int cbPerfData = PERFORMANCE_BUFFER_SIZE; PERF_DATA_BLOCK *pPerfData; HANDLE hDevice, hNetAPI32 = NULL; DWORD dwSize, status; int nDrive; if ( !is_initialized ) { HKEY hKey; if ( debug_me ) log_debug ("rndw32#slow_gatherer_nt: init toolkit\n" ); /* Find out whether this is an NT server or workstation if necessary */ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\ProductOptions", 0, KEY_READ, &hKey) == ERROR_SUCCESS) { BYTE szValue[32]; dwSize = sizeof (szValue); if ( debug_me ) log_debug ("rndw32#slow_gatherer_nt: check product options\n" ); status = RegQueryValueEx (hKey, "ProductType", 0, NULL, szValue, &dwSize); if (status == ERROR_SUCCESS && ascii_strcasecmp (szValue, "WinNT")) { /* Note: There are (at least) three cases for ProductType: * WinNT = NT Workstation, ServerNT = NT Server, LanmanNT = * NT Server acting as a Domain Controller */ is_workstation = 0; if ( debug_me ) log_debug ("rndw32: this is a NT server\n"); } RegCloseKey (hKey); } /* Initialize the NetAPI32 function pointers if necessary */ if ( (hNetAPI32 = LoadLibrary ("NETAPI32.DLL")) ) { if ( debug_me ) log_debug ("rndw32#slow_gatherer_nt: netapi32 loaded\n" ); pNetStatisticsGet = (NETSTATISTICSGET) GetProcAddress (hNetAPI32, "NetStatisticsGet"); pNetApiBufferSize = (NETAPIBUFFERSIZE) GetProcAddress (hNetAPI32, "NetApiBufferSize"); pNetApiBufferFree = (NETAPIBUFFERFREE) GetProcAddress (hNetAPI32, "NetApiBufferFree"); if ( !pNetStatisticsGet || !pNetApiBufferSize || !pNetApiBufferFree ) { FreeLibrary (hNetAPI32); hNetAPI32 = NULL; g10_log_debug ("rndw32: No NETAPI found\n" ); } } is_initialized = 1; } /* Get network statistics. Note: Both NT Workstation and NT Server by * default will be running both the workstation and server services. The * heuristic below is probably useful though on the assumption that the * majority of the network traffic will be via the appropriate service. * In any case the network statistics return almost no randomness */ { LPBYTE lpBuffer; if (hNetAPI32 && !pNetStatisticsGet (NULL, is_workstation ? L"LanmanWorkstation" : L"LanmanServer", 0, 0, &lpBuffer) ) { if ( debug_me ) log_debug ("rndw32#slow_gatherer_nt: get netstats\n" ); pNetApiBufferSize (lpBuffer, &dwSize); (*add) ( lpBuffer, dwSize,requester ); pNetApiBufferFree (lpBuffer); } } /* Get disk I/O statistics for all the hard drives */ for (nDrive = 0;; nDrive++) { char diskPerformance[SIZEOF_DISK_PERFORMANCE_STRUCT]; char szDevice[50]; /* Check whether we can access this device */ sprintf (szDevice, "\\\\.\\PhysicalDrive%d", nDrive); hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (hDevice == INVALID_HANDLE_VALUE) break; /* Note: This only works if you have turned on the disk performance * counters with 'diskperf -y'. These counters are off by default */ if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, diskPerformance, SIZEOF_DISK_PERFORMANCE_STRUCT, &dwSize, NULL)) { if ( debug_me ) log_debug ("rndw32#slow_gatherer_nt: iostats drive %d\n", nDrive ); (*add) (diskPerformance, dwSize, requester ); } else { log_info ("NOTE: you should run 'diskperf -y' " "to enable the disk statistics\n"); } CloseHandle (hDevice); } #if 0 /* we don't need this in GnuPG */ /* Wait for any async keyset driver binding to complete. You may be * wondering what this call is doing here... the reason it's necessary is * because RegQueryValueEx() will hang indefinitely if the async driver * bind is in progress. The problem occurs in the dynamic loading and * linking of driver DLL's, which work as follows: * * hDriver = LoadLibrary( DRIVERNAME ); * pFunction1 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC1 ); * pFunction2 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC2 ); * * If RegQueryValueEx() is called while the GetProcAddress()'s are in * progress, it will hang indefinitely. This is probably due to some * synchronisation problem in the NT kernel where the GetProcAddress() * calls affect something like a module reference count or function * reference count while RegQueryValueEx() is trying to take a snapshot * of the statistics, which include the reference counts. Because of * this, we have to wait until any async driver bind has completed * before we can call RegQueryValueEx() */ waitSemaphore (SEMAPHORE_DRIVERBIND); #endif /* Get information from the system performance counters. This can take * a few seconds to do. In some environments the call to * RegQueryValueEx() can produce an access violation at some random time * in the future, adding a short delay after the following code block * makes the problem go away. This problem is extremely difficult to * reproduce, I haven't been able to get it to occur despite running it * on a number of machines. The best explanation for the problem is that * on the machine where it did occur, it was caused by an external driver * or other program which adds its own values under the * HKEY_PERFORMANCE_DATA key. The NT kernel calls the required external * modules to map in the data, if there's a synchronisation problem the * external module would write its data at an inappropriate moment, * causing the access violation. A low-level memory checker indicated * that ExpandEnvironmentStrings() in KERNEL32.DLL, called an * interminable number of calls down inside RegQueryValueEx(), was * overwriting memory (it wrote twice the allocated size of a buffer to a * buffer allocated by the NT kernel). This may be what's causing the * problem, but since it's in the kernel there isn't much which can be * done. * * In addition to these problems the code in RegQueryValueEx() which * estimates the amount of memory required to return the performance * counter information isn't very accurate, since it always returns a * worst-case estimate which is usually nowhere near the actual amount * required. For example it may report that 128K of memory is required, * but only return 64K of data */ if (getenv("GNUPG_RNDW32_NOPERF")) { static int shown; if (!shown) { shown = 1; g10_log_info ("note: get performance data has been disabled\n"); } } else { pPerfData = xmalloc (cbPerfData); for (;;) { dwSize = cbPerfData; if ( debug_me ) log_debug ("rndw32#slow_gatherer_nt: get perf data\n" ); status = RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, (LPBYTE) pPerfData, &dwSize); if (status == ERROR_SUCCESS) { if (!memcmp (pPerfData->Signature, L"PERF", 8)) { (*add) ( pPerfData, dwSize, requester ); } else g10_log_debug ( "rndw32: no PERF signature\n"); break; } else if (status == ERROR_MORE_DATA) { cbPerfData += PERFORMANCE_BUFFER_STEP; pPerfData = xrealloc (pPerfData, cbPerfData); } else { g10_log_debug ( "rndw32: get performance data problem\n"); break; } } xfree (pPerfData); } /* Although this isn't documented in the Win32 API docs, it's necessary to explicitly close the HKEY_PERFORMANCE_DATA key after use (it's implicitly opened on the first call to RegQueryValueEx()). If this isn't done then any system components which provide performance data can't be removed or changed while the handle remains active */ RegCloseKey (HKEY_PERFORMANCE_DATA); }
int keyserver_refresh (ctrl_t ctrl, strlist_t users) { int rc,count,numdesc,fakev3=0; KEYDB_SEARCH_DESC *desc; unsigned int options=opt.keyserver_options.import_options; /* We switch merge-only on during a refresh, as 'refresh' should never import new keys, even if their keyids match. */ opt.keyserver_options.import_options|=IMPORT_MERGE_ONLY; /* Similarly, we switch on fast-import, since refresh may make multiple import sets (due to preferred keyserver URLs). We don't want each set to rebuild the trustdb. Instead we do it once at the end here. */ opt.keyserver_options.import_options|=IMPORT_FAST; /* If refresh_add_fake_v3_keyids is on and it's a HKP or MAILTO scheme, then enable fake v3 keyid generation. */ if((opt.keyserver_options.options&KEYSERVER_ADD_FAKE_V3) && opt.keyserver && (ascii_strcasecmp(opt.keyserver->scheme,"hkp")==0 || ascii_strcasecmp(opt.keyserver->scheme,"mailto")==0)) fakev3=1; rc=keyidlist(users,&desc,&numdesc,fakev3); if(rc) return rc; count=numdesc; if(count>0) { int i; /* Try to handle preferred keyserver keys first */ for(i=0;i<numdesc;i++) { if(desc[i].skipfncvalue) { struct keyserver_spec *keyserver=desc[i].skipfncvalue; /* We use the keyserver structure we parsed out before. Note that a preferred keyserver without a scheme:// will be interpreted as hkp:// */ rc = keyserver_get (ctrl, &desc[i], 1, keyserver); if(rc) log_info(_("WARNING: unable to refresh key %s" " via %s: %s\n"),keystr_from_desc(&desc[i]), keyserver->uri,g10_errstr(rc)); else { /* We got it, so mark it as NONE so we don't try and get it again from the regular keyserver. */ desc[i].mode=KEYDB_SEARCH_MODE_NONE; count--; } free_keyserver_spec(keyserver); } } } if(count>0) { if(opt.keyserver) { if(count==1) log_info(_("refreshing 1 key from %s\n"),opt.keyserver->uri); else log_info(_("refreshing %d keys from %s\n"), count,opt.keyserver->uri); } rc=keyserver_get (ctrl, desc, numdesc, NULL); } xfree(desc); opt.keyserver_options.import_options=options; /* If the original options didn't have fast import, and the trustdb is dirty, rebuild. */ if(!(opt.keyserver_options.import_options&IMPORT_FAST)) trustdb_check_or_update(); return rc; }
int mutt_print_attachment (FILE *fp, BODY *a) { char newfile[_POSIX_PATH_MAX] = ""; char type[STRING]; pid_t thepid; FILE *ifp, *fpout; short unlink_newfile = 0; snprintf (type, sizeof (type), "%s/%s", TYPE (a), a->subtype); if (rfc1524_mailcap_lookup (a, type, NULL, M_PRINT)) { char command[_POSIX_PATH_MAX+STRING]; rfc1524_entry *entry; int piped = FALSE; dprint (2, (debugfile, "Using mailcap...\n")); entry = rfc1524_new_entry (); rfc1524_mailcap_lookup (a, type, entry, M_PRINT); if (rfc1524_expand_filename (entry->nametemplate, a->filename, newfile, sizeof (newfile))) { if (!fp) { if (safe_symlink(a->filename, newfile) == -1) { if (mutt_yesorno (_("Can't match nametemplate, continue?"), M_YES) != M_YES) { rfc1524_free_entry (&entry); return 0; } strfcpy (newfile, a->filename, sizeof (newfile)); } else unlink_newfile = 1; } } /* in recv mode, save file to newfile first */ if (fp) mutt_save_attachment (fp, a, newfile, 0, NULL); strfcpy (command, entry->printcommand, sizeof (command)); piped = rfc1524_expand_command (a, newfile, type, command, sizeof (command)); mutt_endwin (NULL); /* interactive program */ if (piped) { if ((ifp = fopen (newfile, "r")) == NULL) { mutt_perror ("fopen"); rfc1524_free_entry (&entry); return (0); } if ((thepid = mutt_create_filter (command, &fpout, NULL, NULL)) < 0) { mutt_perror _("Can't create filter"); rfc1524_free_entry (&entry); safe_fclose (&ifp); return 0; } mutt_copy_stream (ifp, fpout); safe_fclose (&fpout); safe_fclose (&ifp); if (mutt_wait_filter (thepid) || option (OPTWAITKEY)) mutt_any_key_to_continue (NULL); } else { if (mutt_system (command) || option (OPTWAITKEY)) mutt_any_key_to_continue (NULL); } if (fp) mutt_unlink (newfile); else if (unlink_newfile) unlink(newfile); rfc1524_free_entry (&entry); return (1); } if (!ascii_strcasecmp ("text/plain", type) || !ascii_strcasecmp ("application/postscript", type)) { return (mutt_pipe_attachment (fp, a, NONULL(PrintCmd), NULL)); } else if (mutt_can_decode (a)) { /* decode and print */ int rc = 0; ifp = NULL; fpout = NULL; mutt_mktemp (newfile, sizeof (newfile)); if (mutt_decode_save_attachment (fp, a, newfile, M_PRINTING, 0) == 0) { dprint (2, (debugfile, "successfully decoded %s type attachment to %s\n", type, newfile)); if ((ifp = fopen (newfile, "r")) == NULL) { mutt_perror ("fopen"); goto bail0; } dprint (2, (debugfile, "successfully opened %s read-only\n", newfile)); mutt_endwin (NULL); if ((thepid = mutt_create_filter (NONULL(PrintCmd), &fpout, NULL, NULL)) < 0) { mutt_perror _("Can't create filter"); goto bail0; } dprint (2, (debugfile, "Filter created.\n")); mutt_copy_stream (ifp, fpout); safe_fclose (&fpout); safe_fclose (&ifp); if (mutt_wait_filter (thepid) != 0 || option (OPTWAITKEY)) mutt_any_key_to_continue (NULL); rc = 1; } bail0: safe_fclose (&ifp); safe_fclose (&fpout); mutt_unlink (newfile); return rc; } else { mutt_error _("I don't know how to print that!"); return 0; } }
static int rfc1524_mailcap_parse (BODY *a, char *filename, char *type, rfc1524_entry *entry, int opt) { FILE *fp; char *buf = NULL; size_t buflen; char *ch; char *field; int found = FALSE; int copiousoutput; int composecommand; int editcommand; int printcommand; int btlen; int line = 0; /* rfc1524 mailcap file is of the format: * base/type; command; extradefs * type can be * for matching all * base with no /type is an implicit wild * command contains a %s for the filename to pass, default to pipe on stdin * extradefs are of the form: * def1="definition"; def2="define \;"; * line wraps with a \ at the end of the line * # for comments */ /* find length of basetype */ if ((ch = strchr (type, '/')) == NULL) return FALSE; btlen = ch - type; if ((fp = fopen (filename, "r")) != NULL) { while (!found && (buf = mutt_read_line (buf, &buflen, fp, &line, M_CONT)) != NULL) { /* ignore comments */ if (*buf == '#') continue; dprint (2, (debugfile, "mailcap entry: %s\n", buf)); /* check type */ ch = get_field (buf); if (ascii_strcasecmp (buf, type) && (ascii_strncasecmp (buf, type, btlen) || (buf[btlen] != 0 && /* implicit wild */ mutt_strcmp (buf + btlen, "/*")))) /* wildsubtype */ continue; /* next field is the viewcommand */ field = ch; ch = get_field (ch); if (entry) entry->command = safe_strdup (field); /* parse the optional fields */ found = TRUE; copiousoutput = FALSE; composecommand = FALSE; editcommand = FALSE; printcommand = FALSE; while (ch) { field = ch; ch = get_field (ch); dprint (2, (debugfile, "field: %s\n", field)); if (!ascii_strcasecmp (field, "needsterminal")) { if (entry) entry->needsterminal = TRUE; } else if (!ascii_strcasecmp (field, "copiousoutput")) { copiousoutput = TRUE; if (entry) entry->copiousoutput = TRUE; } else if (!ascii_strncasecmp (field, "composetyped", 12)) { /* this compare most occur before compose to match correctly */ if (get_field_text (field + 12, entry ? &entry->composetypecommand : NULL, type, filename, line)) composecommand = TRUE; } else if (!ascii_strncasecmp (field, "compose", 7)) { if (get_field_text (field + 7, entry ? &entry->composecommand : NULL, type, filename, line)) composecommand = TRUE; } else if (!ascii_strncasecmp (field, "print", 5)) { if (get_field_text (field + 5, entry ? &entry->printcommand : NULL, type, filename, line)) printcommand = TRUE; } else if (!ascii_strncasecmp (field, "edit", 4)) { if (get_field_text (field + 4, entry ? &entry->editcommand : NULL, type, filename, line)) editcommand = TRUE; } else if (!ascii_strncasecmp (field, "nametemplate", 12)) { get_field_text (field + 12, entry ? &entry->nametemplate : NULL, type, filename, line); } else if (!ascii_strncasecmp (field, "x-convert", 9)) { get_field_text (field + 9, entry ? &entry->convert : NULL, type, filename, line); } else if (!ascii_strncasecmp (field, "test", 4)) { /* * This routine executes the given test command to determine * if this is the right entry. */ char *test_command = NULL; size_t len; if (get_field_text (field + 4, &test_command, type, filename, line) && test_command) { len = mutt_strlen (test_command) + STRING; safe_realloc (&test_command, len); rfc1524_expand_command (a, a->filename, type, test_command, len); if (mutt_system (test_command)) { /* a non-zero exit code means test failed */ found = FALSE; } FREE (&test_command); } } } /* while (ch) */ if (opt == M_AUTOVIEW) { if (!copiousoutput) found = FALSE; } else if (opt == M_COMPOSE) { if (!composecommand) found = FALSE; } else if (opt == M_EDIT) { if (!editcommand) found = FALSE; } else if (opt == M_PRINT) { if (!printcommand) found = FALSE; } if (!found) { /* reset */ if (entry) { FREE (&entry->command); FREE (&entry->composecommand); FREE (&entry->composetypecommand); FREE (&entry->editcommand); FREE (&entry->printcommand); FREE (&entry->nametemplate); FREE (&entry->convert); entry->needsterminal = 0; entry->copiousoutput = 0; } } } /* while (!found && (buf = mutt_read_line ())) */ safe_fclose (&fp); } /* if ((fp = fopen ())) */ FREE (&buf); return found; }
keyserver_spec_t parse_keyserver_uri (const char *string,int require_scheme, const char *configname,unsigned int configlineno) { int assume_hkp=0; struct keyserver_spec *keyserver; const char *idx; int count; char *uri,*options; assert(string!=NULL); keyserver=xmalloc_clear(sizeof(struct keyserver_spec)); uri=xstrdup(string); options=strchr(uri,' '); if(options) { char *tok; *options='\0'; options++; while((tok=optsep(&options))) add_canonical_option(tok,&keyserver->options); } /* Get the scheme */ for(idx=uri,count=0;*idx && *idx!=':';idx++) { count++; /* Do we see the start of an RFC-2732 ipv6 address here? If so, there clearly isn't a scheme so get out early. */ if(*idx=='[') { /* Was the '[' the first thing in the string? If not, we have a mangled scheme with a [ in it so fail. */ if(count==1) break; else goto fail; } } if(count==0) goto fail; if(*idx=='\0' || *idx=='[') { if(require_scheme) return NULL; /* Assume HKP if there is no scheme */ assume_hkp=1; keyserver->scheme=xstrdup("hkp"); keyserver->uri=xmalloc(strlen(keyserver->scheme)+3+strlen(uri)+1); strcpy(keyserver->uri,keyserver->scheme); strcat(keyserver->uri,"://"); strcat(keyserver->uri,uri); } else { int i; keyserver->uri=xstrdup(uri); keyserver->scheme=xmalloc(count+1); /* Force to lowercase */ for(i=0;i<count;i++) keyserver->scheme[i]=ascii_tolower(uri[i]); keyserver->scheme[i]='\0'; /* Skip past the scheme and colon */ uri+=count+1; } if(ascii_strcasecmp(keyserver->scheme,"x-broken-hkp")==0) { deprecated_warning(configname,configlineno,"x-broken-hkp", "--keyserver-options ","broken-http-proxy"); xfree(keyserver->scheme); keyserver->scheme=xstrdup("hkp"); append_to_strlist(&opt.keyserver_options.other,"broken-http-proxy"); } else if(ascii_strcasecmp(keyserver->scheme,"x-hkp")==0) { /* Canonicalize this to "hkp" so it works with both the internal and external keyserver interface. */ xfree(keyserver->scheme); keyserver->scheme=xstrdup("hkp"); } if (uri[0]=='/' && uri[1]=='/' && uri[2] == '/') { /* Three slashes means network path with a default host name. This is a hack because it does not crok all possible combiantions. We should better repalce all code bythe parser from http.c. */ keyserver->path = xstrdup (uri+2); } else if(assume_hkp || (uri[0]=='/' && uri[1]=='/')) { /* Two slashes means network path. */ /* Skip over the "//", if any */ if(!assume_hkp) uri+=2; /* Do we have userinfo auth data present? */ for(idx=uri,count=0;*idx && *idx!='@' && *idx!='/';idx++) count++; /* We found a @ before the slash, so that means everything before the @ is auth data. */ if(*idx=='@') { if(count==0) goto fail; keyserver->auth=xmalloc(count+1); strncpy(keyserver->auth,uri,count); keyserver->auth[count]='\0'; uri+=count+1; } /* Is it an RFC-2732 ipv6 [literal address] ? */ if(*uri=='[') { for(idx=uri+1,count=1;*idx && ((isascii (*idx) && isxdigit(*idx)) || *idx==':' || *idx=='.');idx++) count++; /* Is the ipv6 literal address terminated? */ if(*idx==']') count++; else goto fail; } else for(idx=uri,count=0;*idx && *idx!=':' && *idx!='/';idx++) count++; if(count==0) goto fail; keyserver->host=xmalloc(count+1); strncpy(keyserver->host,uri,count); keyserver->host[count]='\0'; /* Skip past the host */ uri+=count; if(*uri==':') { /* It would seem to be reasonable to limit the range of the ports to values between 1-65535, but RFC 1738 and 1808 imply there is no limit. Of course, the real world has limits. */ for(idx=uri+1,count=0;*idx && *idx!='/';idx++) { count++; /* Ports are digits only */ if(!digitp(idx)) goto fail; } keyserver->port=xmalloc(count+1); strncpy(keyserver->port,uri+1,count); keyserver->port[count]='\0'; /* Skip past the colon and port number */ uri+=1+count; } /* Everything else is the path */ if(*uri) keyserver->path=xstrdup(uri); else keyserver->path=xstrdup("/"); if(keyserver->path[1]) keyserver->flags.direct_uri=1; } else if(uri[0]!='/') { /* No slash means opaque. Just record the opaque blob and get out. */ keyserver->opaque=xstrdup(uri); } else { /* One slash means absolute path. We don't need to support that yet. */ goto fail; } return keyserver; fail: free_keyserver_spec(keyserver); return NULL; }
/* imap_authenticate: Attempt to authenticate using either user-specified * authentication method if specified, or any. */ int imap_authenticate (IMAP_DATA* idata) { const imap_auth_t* authenticator; char* methods; char* method; char* delim; int r = -1; if (ImapAuthenticators && *ImapAuthenticators) { /* Try user-specified list of authentication methods */ methods = safe_strdup (ImapAuthenticators); for (method = methods; method; method = delim) { delim = strchr (method, ':'); if (delim) *delim++ = '\0'; if (! method[0]) continue; dprint (2, (debugfile, "imap_authenticate: Trying method %s\n", method)); authenticator = imap_authenticators; while (authenticator->authenticate) { if (!authenticator->method || !ascii_strcasecmp (authenticator->method, method)) if ((r = authenticator->authenticate (idata, method)) != IMAP_AUTH_UNAVAIL) { FREE (&methods); return r; } authenticator++; } } FREE (&methods); } else { /* Fall back to default: any authenticator */ dprint (2, (debugfile, "imap_authenticate: Using any available method.\n")); authenticator = imap_authenticators; while (authenticator->authenticate) { if ((r = authenticator->authenticate (idata, NULL)) != IMAP_AUTH_UNAVAIL) return r; authenticator++; } } if (r == IMAP_AUTH_UNAVAIL) { mutt_error (_("No authenticators available")); mutt_sleep (1); } return r; }
static int recoverInit( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ const unsigned kTypeCol = 4; Recover *pRecover; char *zDot; u32 iRootPage; char *zCreateSql; int rc; if( ascii_strcasecmp(argv[1], "temp")!=0 ){ *pzErr = sqlite3_mprintf("recover table must be in temp database"); return SQLITE_MISUSE; } if( argc<=kTypeCol ){ *pzErr = sqlite3_mprintf("no columns specified"); return SQLITE_MISUSE; } pRecover = sqlite3_malloc(sizeof(Recover)); if( !pRecover ){ return SQLITE_NOMEM; } memset(pRecover, 0, sizeof(*pRecover)); pRecover->base.pModule = &recoverModule; pRecover->db = db; zDot = strchr(argv[3], '.'); if( !zDot ){ pRecover->zDb = sqlite3_strdup(db->aDb[0].zName); pRecover->zTable = sqlite3_strdup(argv[3]); }else if( zDot>argv[3] && zDot[1]!='\0' ){ pRecover->zDb = sqlite3_strndup(argv[3], zDot - argv[3]); pRecover->zTable = sqlite3_strdup(zDot + 1); }else{ *pzErr = sqlite3_mprintf("ill-formed table specifier"); recoverRelease(pRecover); return SQLITE_ERROR; } pRecover->nCols = argc - kTypeCol; pRecover->pTypes = sqlite3_malloc(pRecover->nCols); if( !pRecover->zDb || !pRecover->zTable || !pRecover->pTypes ){ recoverRelease(pRecover); return SQLITE_NOMEM; } rc = getRootPage(pRecover->db, pRecover->zDb, pRecover->zTable, &iRootPage); if( rc!=SQLITE_OK ){ *pzErr = sqlite3_mprintf("unable to find backing table"); recoverRelease(pRecover); return rc; } rc = ParseColumnsAndGenerateCreate(pRecover->nCols, argv + kTypeCol, &zCreateSql, pRecover->pTypes, pzErr); if( rc!=SQLITE_OK ){ recoverRelease(pRecover); return rc; } rc = sqlite3_declare_vtab(db, zCreateSql); sqlite3_free(zCreateSql); if( rc!=SQLITE_OK ){ recoverRelease(pRecover); return rc; } *ppVtab = (sqlite3_vtab *)pRecover; return SQLITE_OK; }
/* imap_auth_sasl: Default authenticator if available. */ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata, const char* method) { sasl_conn_t* saslconn; sasl_interact_t* interaction = NULL; int rc, irc; char buf[HUGE_STRING]; const char* mech; const char *pc = NULL; unsigned int len, olen; unsigned char client_start; if (mutt_sasl_client_new (idata->conn, &saslconn) < 0) { dprint (1, (debugfile, "imap_auth_sasl: Error allocating SASL connection.\n")); return IMAP_AUTH_FAILURE; } rc = SASL_FAIL; /* If the user hasn't specified a method, use any available */ if (!method) { method = idata->capstr; /* hack for SASL ANONYMOUS support: * 1. Fetch username. If it's "" or "anonymous" then * 2. attempt sasl_client_start with only "AUTH=ANONYMOUS" capability * 3. if sasl_client_start fails, fall through... */ if (mutt_account_getuser (&idata->conn->account)) return IMAP_AUTH_FAILURE; if (mutt_bit_isset (idata->capabilities, AUTH_ANON) && (!idata->conn->account.user[0] || !ascii_strncmp (idata->conn->account.user, "anonymous", 9))) rc = sasl_client_start (saslconn, "AUTH=ANONYMOUS", NULL, &pc, &olen, &mech); } else if (!ascii_strcasecmp ("login", method) && !strstr (NONULL (idata->capstr), "AUTH=LOGIN")) /* do not use SASL login for regular IMAP login (#3556) */ return IMAP_AUTH_UNAVAIL; if (rc != SASL_OK && rc != SASL_CONTINUE) do { rc = sasl_client_start (saslconn, method, &interaction, &pc, &olen, &mech); if (rc == SASL_INTERACT) mutt_sasl_interact (interaction); } while (rc == SASL_INTERACT); client_start = (olen > 0); if (rc != SASL_OK && rc != SASL_CONTINUE) { if (method) dprint (2, (debugfile, "imap_auth_sasl: %s unavailable\n", method)); else dprint (1, (debugfile, "imap_auth_sasl: Failure starting authentication exchange. No shared mechanisms?\n")); /* SASL doesn't support LOGIN, so fall back */ return IMAP_AUTH_UNAVAIL; } mutt_message (_("Authenticating (%s)..."), mech); snprintf (buf, sizeof (buf), "AUTHENTICATE %s", mech); if (mutt_bit_isset (idata->capabilities, SASL_IR) && client_start) { len = mutt_strlen (buf); buf[len++] = ' '; if (sasl_encode64 (pc, olen, buf + len, sizeof (buf) - len, &olen) != SASL_OK) { dprint (1, (debugfile, "imap_auth_sasl: error base64-encoding client response.\n")); goto bail; } client_start = olen = 0; } imap_cmd_start (idata, buf); irc = IMAP_CMD_CONTINUE; /* looping protocol */ while (rc == SASL_CONTINUE || olen > 0) { do irc = imap_cmd_step (idata); while (irc == IMAP_CMD_CONTINUE); if (irc == IMAP_CMD_BAD || irc == IMAP_CMD_NO) goto bail; if (irc == IMAP_CMD_RESPOND) { /* Exchange incorrectly returns +\r\n instead of + \r\n */ if (idata->buf[1] == '\0') { buf[0] = '\0'; len = 0; } else if (sasl_decode64 (idata->buf+2, strlen (idata->buf+2), buf, LONG_STRING-1, &len) != SASL_OK) { dprint (1, (debugfile, "imap_auth_sasl: error base64-decoding server response.\n")); goto bail; } } /* client-start is only available with the SASL-IR extension, but * SASL 2.1 seems to want to use it regardless, at least for DIGEST * fast reauth. Override if the server sent an initial continuation */ if (!client_start || buf[0]) { do { rc = sasl_client_step (saslconn, buf, len, &interaction, &pc, &olen); if (rc == SASL_INTERACT) mutt_sasl_interact (interaction); } while (rc == SASL_INTERACT); } else client_start = 0; /* send out response, or line break if none needed */ if (olen) { if (sasl_encode64 (pc, olen, buf, sizeof (buf), &olen) != SASL_OK) { dprint (1, (debugfile, "imap_auth_sasl: error base64-encoding client response.\n")); goto bail; } } if (irc == IMAP_CMD_RESPOND) { strfcpy (buf + olen, "\r\n", sizeof (buf) - olen); mutt_socket_write (idata->conn, buf); } /* If SASL has errored out, send an abort string to the server */ if (rc < 0) { mutt_socket_write (idata->conn, "*\r\n"); dprint (1, (debugfile, "imap_auth_sasl: sasl_client_step error %d\n",rc)); } olen = 0; } while (irc != IMAP_CMD_OK) if ((irc = imap_cmd_step (idata)) != IMAP_CMD_CONTINUE) break; if (rc != SASL_OK) goto bail; if (imap_code (idata->buf)) { mutt_sasl_setup_conn (idata->conn, saslconn); return IMAP_AUTH_SUCCESS; } bail: sasl_dispose (&saslconn); if (method) { dprint (2, (debugfile, "imap_auth_sasl: %s failed\n", method)); return IMAP_AUTH_UNAVAIL; } mutt_error _("SASL authentication failed."); mutt_sleep(2); return IMAP_AUTH_FAILURE; }
int main(int argc,char *argv[]) { int arg,ret=KEYSERVER_INTERNAL_ERROR,i; char line[MAX_LINE]; char *thekey=NULL; long follow_redirects=5; char *proxy=NULL; curl_version_info_data *curldata; struct curl_slist *headers=NULL; console=stderr; /* Kludge to implement standard GNU options. */ if (argc > 1 && !strcmp (argv[1], "--version")) { printf ("gpgkeys_curl (GnuPG) %s\n", VERSION); printf ("Uses: %s\n", curl_version()); return 0; } else if (argc > 1 && !strcmp (argv[1], "--help")) { show_help (stdout); return 0; } while((arg=getopt(argc,argv,"hVo:"))!=-1) switch(arg) { default: case 'h': show_help (console); return KEYSERVER_OK; case 'V': fprintf(stdout,"%d\n%s\n",KEYSERVER_PROTO_VERSION,VERSION); return KEYSERVER_OK; case 'o': output=fopen(optarg,"wb"); if(output==NULL) { fprintf(console,"gpgkeys: Cannot open output file `%s': %s\n", optarg,strerror(errno)); return KEYSERVER_INTERNAL_ERROR; } break; } if(argc>optind) { input=fopen(argv[optind],"r"); if(input==NULL) { fprintf(console,"gpgkeys: Cannot open input file `%s': %s\n", argv[optind],strerror(errno)); return KEYSERVER_INTERNAL_ERROR; } } if(input==NULL) input=stdin; if(output==NULL) output=stdout; opt=init_ks_options(); if(!opt) return KEYSERVER_NO_MEMORY; /* Get the command and info block */ while(fgets(line,MAX_LINE,input)!=NULL) { int err; char option[MAX_OPTION+1]; if(line[0]=='\n') break; err=parse_ks_options(line,opt); if(err>0) { ret=err; goto fail; } else if(err==0) continue; if(sscanf(line,"OPTION %" MKSTRING(MAX_OPTION) "s\n",option)==1) { int no=0; char *start=&option[0]; option[MAX_OPTION]='\0'; if(ascii_strncasecmp(option,"no-",3)==0) { no=1; start=&option[3]; } if(ascii_strncasecmp(start,"http-proxy",10)==0) { /* Safe to not check the return code of strdup() here. If it fails, we simply won't use a proxy. */ if(no) { free(proxy); proxy=strdup(""); } else if(start[10]=='=') { if(strlen(&start[11])<MAX_PROXY) { free(proxy); proxy=strdup(&start[11]); } } } else if(ascii_strncasecmp(start,"follow-redirects",16)==0) { if(no) follow_redirects=0; else if(start[16]=='=') follow_redirects=atoi(&start[17]); else if(start[16]=='\0') follow_redirects=-1; } continue; } } if(!opt->scheme) { fprintf(console,"gpgkeys: no scheme supplied!\n"); ret=KEYSERVER_SCHEME_NOT_FOUND; goto fail; } if(!opt->host) { fprintf(console,"gpgkeys: no keyserver host provided\n"); goto fail; } if(opt->timeout && register_timeout()==-1) { fprintf(console,"gpgkeys: unable to register timeout handler\n"); return KEYSERVER_INTERNAL_ERROR; } curl_global_init(CURL_GLOBAL_DEFAULT); curl=curl_easy_init(); if(!curl) { fprintf(console,"gpgkeys: unable to initialize curl\n"); ret=KEYSERVER_INTERNAL_ERROR; goto fail; } /* Make sure we have the protocol the user is asking for so we can print a nicer error message. */ curldata=curl_version_info(CURLVERSION_NOW); for(i=0;curldata->protocols[i];i++) if(ascii_strcasecmp(curldata->protocols[i],opt->scheme)==0) break; if(curldata->protocols[i]==NULL) { fprintf(console,"gpgkeys: protocol `%s' not supported\n",opt->scheme); ret=KEYSERVER_SCHEME_NOT_FOUND; goto fail; } if(follow_redirects) { curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,1L); if(follow_redirects>0) curl_easy_setopt(curl,CURLOPT_MAXREDIRS,follow_redirects); } if(opt->auth) curl_easy_setopt(curl,CURLOPT_USERPWD,opt->auth); if(opt->debug) { fprintf(console,"gpgkeys: curl version = %s\n",curl_version()); curl_easy_setopt(curl,CURLOPT_STDERR,console); curl_easy_setopt(curl,CURLOPT_VERBOSE,1L); } curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,(long)opt->flags.check_cert); if (opt->ca_cert_file) curl_easy_setopt (curl, CURLOPT_CAINFO, opt->ca_cert_file); /* Avoid caches to get the most recent copy of the key. This is bug #1061. In pre-curl versions of the code, we didn't do it. Then we did do it (as a curl default) until curl changed the default. Now we're doing it again, but in such a way that changing defaults in the future won't impact us. We set both the Pragma and Cache-Control versions of the header, so we're good with both HTTP 1.0 and 1.1. */ headers=curl_slist_append(headers,"Pragma: no-cache"); if(headers) headers=curl_slist_append(headers,"Cache-Control: no-cache"); if(!headers) { fprintf(console,"gpgkeys: out of memory when building HTTP headers\n"); ret=KEYSERVER_NO_MEMORY; goto fail; } curl_easy_setopt(curl,CURLOPT_HTTPHEADER,headers); if(proxy) curl_easy_setopt(curl,CURLOPT_PROXY,proxy); /* If it's a GET or a SEARCH, the next thing to come in is the keyids. If it's a SEND, then there are no keyids. */ if(opt->action==KS_GET) { /* Eat the rest of the file */ for(;;) { if(fgets(line,MAX_LINE,input)==NULL) break; else { if(line[0]=='\n' || line[0]=='\0') break; if(!thekey) { thekey=strdup(line); if(!thekey) { fprintf(console,"gpgkeys: out of memory while " "building key list\n"); ret=KEYSERVER_NO_MEMORY; goto fail; } /* Trim the trailing \n */ thekey[strlen(line)-1]='\0'; } } } } else { fprintf(console, "gpgkeys: this keyserver type only supports key retrieval\n"); goto fail; } if(!thekey) { fprintf(console,"gpgkeys: invalid keyserver instructions\n"); goto fail; } /* Send the response */ fprintf(output,"VERSION %d\n",KEYSERVER_PROTO_VERSION); fprintf(output,"PROGRAM %s\n\n",VERSION); if(opt->verbose) { fprintf(console,"Scheme:\t\t%s\n",opt->scheme); fprintf(console,"Host:\t\t%s\n",opt->host); if(opt->port) fprintf(console,"Port:\t\t%s\n",opt->port); if(opt->path) fprintf(console,"Path:\t\t%s\n",opt->path); fprintf(console,"Command:\tGET\n"); } set_timeout(opt->timeout); ret=get_key(thekey); fail: free(thekey); if(input!=stdin) fclose(input); if(output!=stdout) fclose(output); free_ks_options(opt); curl_slist_free_all(headers); if(curl) curl_easy_cleanup(curl); free(proxy); curl_global_cleanup(); return ret; }