static int openpgp_message_p (estream_t fp) { int ctb; ctb = es_getc (fp); if (ctb != EOF) { if (es_ungetc (ctb, fp)) log_fatal ("error ungetting first byte: %s\n", gpg_strerror (gpg_error_from_syserror ())); if ((ctb & 0x80)) { switch ((ctb & 0x40) ? (ctb & 0x3f) : ((ctb>>2)&0xf)) { case PKT_MARKER: case PKT_SYMKEY_ENC: case PKT_ONEPASS_SIG: case PKT_PUBKEY_ENC: case PKT_SIGNATURE: case PKT_COMMENT: case PKT_OLD_COMMENT: case PKT_PLAINTEXT: case PKT_COMPRESSED: case PKT_ENCRYPTED: return 1; /* Yes, this seems to be an OpenPGP message. */ default: break; } } } return 0; }
int main (int argc, char **argv) { int last_argc = -1; gpg_error_t err; int rc; parsed_uri_t uri; uri_tuple_t r; http_t hd; int c; unsigned int my_http_flags = 0; int no_out = 0; int tls_dbg = 0; const char *cafile = NULL; http_session_t session = NULL; gpgrt_init (); log_set_prefix (PGM, 1 | 4); if (argc) { argc--; argv++; } while (argc && last_argc != argc ) { last_argc = argc; if (!strcmp (*argv, "--")) { argc--; argv++; break; } else if (!strcmp (*argv, "--help")) { fputs ("usage: " PGM " URL\n" "Options:\n" " --verbose print timings etc.\n" " --debug flyswatter\n" " --gnutls-debug N use GNUTLS debug level N\n" " --cacert FNAME expect CA certificate in file FNAME\n" " --no-verify do not verify the certificate\n" " --force-tls use HTTP_FLAG_FORCE_TLS\n" " --no-out do not print the content\n", stdout); exit (0); } else if (!strcmp (*argv, "--verbose")) { verbose++; argc--; argv++; } else if (!strcmp (*argv, "--debug")) { verbose += 2; debug++; argc--; argv++; } else if (!strcmp (*argv, "--gnutls-debug")) { argc--; argv++; if (argc) { tls_dbg = atoi (*argv); argc--; argv++; } } else if (!strcmp (*argv, "--cacert")) { argc--; argv++; if (argc) { cafile = *argv; argc--; argv++; } } else if (!strcmp (*argv, "--no-verify")) { no_verify = 1; argc--; argv++; } else if (!strcmp (*argv, "--force-tls")) { my_http_flags |= HTTP_FLAG_FORCE_TLS; argc--; argv++; } else if (!strcmp (*argv, "--no-out")) { no_out = 1; argc--; argv++; } else if (!strncmp (*argv, "--", 2)) { fprintf (stderr, PGM ": unknown option '%s'\n", *argv); exit (1); } } if (argc != 1) { fprintf (stderr, PGM ": no or too many URLS given\n"); exit (1); } if (!cafile) cafile = prepend_srcdir ("tls-ca.pem"); #if HTTP_USE_NTBTLS (void)err; ntbtls_set_debug (tls_dbg, NULL, NULL); #elif HTTP_USE_GNUTLS rc = gnutls_global_init (); if (rc) log_error ("gnutls_global_init failed: %s\n", gnutls_strerror (rc)); http_register_tls_callback (verify_callback); http_register_tls_ca (cafile); err = http_session_new (&session, NULL); if (err) log_error ("http_session_new failed: %s\n", gpg_strerror (err)); /* rc = gnutls_dh_params_init(&dh_params); */ /* if (rc) */ /* log_error ("gnutls_dh_params_init failed: %s\n", gnutls_strerror (rc)); */ /* read_dh_params ("dh_param.pem"); */ /* rc = gnutls_certificate_set_x509_trust_file */ /* (certcred, "ca.pem", GNUTLS_X509_FMT_PEM); */ /* if (rc) */ /* log_error ("gnutls_certificate_set_x509_trust_file failed: %s\n", */ /* gnutls_strerror (rc)); */ /* gnutls_certificate_set_dh_params (certcred, dh_params); */ gnutls_global_set_log_function (my_gnutls_log); if (tls_dbg) gnutls_global_set_log_level (tls_dbg); #endif /*HTTP_USE_GNUTLS*/ rc = http_parse_uri (&uri, *argv, 1); if (rc) { log_error ("'%s': %s\n", *argv, gpg_strerror (rc)); return 1; } printf ("Scheme: %s\n", uri->scheme); if (uri->opaque) printf ("Value : %s\n", uri->path); else { printf ("Auth : %s\n", uri->auth? uri->auth:"[none]"); printf ("Host : %s\n", uri->host); printf ("Port : %u\n", uri->port); printf ("Path : %s\n", uri->path); for (r = uri->params; r; r = r->next) { printf ("Params: %s", r->name); if (!r->no_value) { printf ("=%s", r->value); if (strlen (r->value) != r->valuelen) printf (" [real length=%d]", (int) r->valuelen); } putchar ('\n'); } for (r = uri->query; r; r = r->next) { printf ("Query : %s", r->name); if (!r->no_value) { printf ("=%s", r->value); if (strlen (r->value) != r->valuelen) printf (" [real length=%d]", (int) r->valuelen); } putchar ('\n'); } printf ("TLS : %s\n", uri->use_tls? "yes": (my_http_flags&HTTP_FLAG_FORCE_TLS)? "forced" : "no"); } fflush (stdout); http_release_parsed_uri (uri); uri = NULL; rc = http_open_document (&hd, *argv, NULL, my_http_flags, NULL, session, NULL, NULL); if (rc) { log_error ("can't get '%s': %s\n", *argv, gpg_strerror (rc)); return 1; } log_info ("open_http_document succeeded; status=%u\n", http_get_status_code (hd)); { const char **names; int i; names = http_get_header_names (hd); if (!names) log_fatal ("http_get_header_names failed: %s\n", gpg_strerror (gpg_error_from_syserror ())); for (i = 0; names[i]; i++) printf ("HDR: %s: %s\n", names[i], http_get_header (hd, names[i])); xfree (names); } fflush (stdout); switch (http_get_status_code (hd)) { case 200: case 400: case 401: case 403: case 404: { unsigned long count = 0; while ((c = es_getc (http_get_read_ptr (hd))) != EOF) { count++; if (!no_out) putchar (c); } log_info ("Received bytes: %lu\n", count); } break; case 301: case 302: case 307: log_info ("Redirected to: %s\n", http_get_header (hd, "Location")); break; } http_close (hd, 0); http_session_release (session); #ifdef HTTP_USE_GNUTLS gnutls_global_deinit (); #endif /*HTTP_USE_GNUTLS*/ return 0; }
/* The thread spawned by runner_spawn. */ static void * runner_thread (void *arg) { runner_t runner = arg; gpg_error_t err = 0; log_debug ("starting runner thread\n"); /* If a status_fp is available, the thread's main task is to read from that stream and invoke the backend's handler function. This is done on a line by line base and the line length is limited to a reasonable value (about 1000 characters). Other work will continue either due to an EOF of the stream or by demand of the engine. */ if (runner->status_fp) { int c, cont_line; unsigned int pos; char buffer[1024]; estream_t fp = runner->status_fp; pos = 0; cont_line = 0; while (!err && !runner->cancel_flag && (c=es_getc (fp)) != EOF) { buffer[pos++] = c; if (pos >= sizeof buffer - 5 || c == '\n') { buffer[pos - (c == '\n')] = 0; if (opt.verbose) log_info ("%s%s: %s\n", runner->name, cont_line? "(cont)":"", buffer); /* We handle only complete lines and ignore any stuff we possibly had to truncate. That is - at least for the encfs engine - not an issue because our changes to the tool make sure that only relatively short prompt lines are of interest. */ if (!cont_line && runner->handler) err = runner->handler (runner->handler_data, runner, buffer); pos = 0; cont_line = (c != '\n'); } } if (!err && runner->cancel_flag) log_debug ("runner thread noticed cancel flag\n"); else log_debug ("runner thread saw EOF\n"); if (pos) { buffer[pos] = 0; if (opt.verbose) log_info ("%s%s: %s\n", runner->name, cont_line? "(cont)":"", buffer); if (!cont_line && !err && runner->handler) err = runner->handler (runner->handler_data, runner, buffer); } if (!err && es_ferror (fp)) { err = gpg_error_from_syserror (); log_error ("error reading from %s: %s\n", runner->name, gpg_strerror (err)); } runner->status_fp = NULL; es_fclose (fp); log_debug ("runner thread closed status fp\n"); } /* Now wait for the process to finish. */ if (!err && runner->pid != (pid_t)(-1)) { int exitcode; log_debug ("runner thread waiting ...\n"); err = gnupg_wait_process (runner->name, runner->pid, 1, &exitcode); gnupg_release_process (runner->pid); runner->pid = (pid_t)(-1); if (err) log_error ("running '%s' failed (exitcode=%d): %s\n", runner->name, exitcode, gpg_strerror (err)); log_debug ("runner thread waiting finished\n"); } /* Get rid of the runner object (note: it is refcounted). */ log_debug ("runner thread releasing runner ...\n"); { runner_t r, rprev; for (r = running_threads, rprev = NULL; r; rprev = r, r = r->next_running) if (r == runner) { if (!rprev) running_threads = r->next_running; else rprev->next_running = r->next_running; r->next_running = NULL; break; } } runner_release (runner); log_debug ("runner thread runner released\n"); return NULL; }
/* Decrypt the collected data. */ static void decrypt_data (receive_ctx_t ctx) { gpg_error_t err; ccparray_t ccp; const char **argv; int c; es_rewind (ctx->encrypted); if (!ctx->plaintext) ctx->plaintext = es_fopenmem (0, "w+b"); if (!ctx->plaintext) { err = gpg_error_from_syserror (); log_error ("error allocating space for plaintext: %s\n", gpg_strerror (err)); return; } ccparray_init (&ccp, 0); /* We limit the output to 64 KiB to avoid DoS using compression * tricks. A regular client will anyway only send a minimal key; * that is one w/o key signatures and attribute packets. */ ccparray_put (&ccp, "--max-output=0xf0000"); /*FIXME: Change s/F/1/ */ ccparray_put (&ccp, "--batch"); if (opt.verbose) ccparray_put (&ccp, "--verbose"); ccparray_put (&ccp, "--always-trust"); ccparray_put (&ccp, "--decrypt"); ccparray_put (&ccp, "--"); ccparray_put (&ccp, NULL); argv = ccparray_get (&ccp, NULL); if (!argv) { err = gpg_error_from_syserror (); goto leave; } err = gnupg_exec_tool_stream (opt.gpg_program, argv, ctx->encrypted, NULL, ctx->plaintext, decrypt_data_status_cb, ctx); if (err) { log_error ("decryption failed: %s\n", gpg_strerror (err)); goto leave; } if (opt.debug) { es_rewind (ctx->plaintext); log_debug ("plaintext: '"); while ((c = es_getc (ctx->plaintext)) != EOF) log_printf ("%c", c); log_printf ("'\n"); } es_rewind (ctx->plaintext); leave: xfree (argv); }
/* Parse the /etc/gnupg/g13tab for user USERNAME. Return a table for the user on success. Return NULL on error and print diagnostics. */ static tab_item_t parse_g13tab (const char *username) { gpg_error_t err; int c, n; char line[512]; char *p; char *fname; estream_t fp; int lnr; char **words = NULL; tab_item_t table = NULL; tab_item_t *tabletail, ti; fname = make_filename (gnupg_sysconfdir (), G13_NAME"tab", NULL); fp = es_fopen (fname, "r"); if (!fp) { err = gpg_error_from_syserror (); log_error (_("error opening '%s': %s\n"), fname, gpg_strerror (err)); goto leave; } tabletail = &table; err = 0; lnr = 0; while (es_fgets (line, DIM(line)-1, fp)) { lnr++; n = strlen (line); if (!n || line[n-1] != '\n') { /* Eat until end of line. */ while ((c=es_getc (fp)) != EOF && c != '\n') ; err = gpg_error (*line? GPG_ERR_LINE_TOO_LONG : GPG_ERR_INCOMPLETE_LINE); log_error (_("file '%s', line %d: %s\n"), fname, lnr, gpg_strerror (err)); continue; } line[--n] = 0; /* Chop the LF. */ if (n && line[n-1] == '\r') line[--n] = 0; /* Chop an optional CR. */ /* Allow for empty lines and spaces */ for (p=line; spacep (p); p++) ; if (!*p || *p == '#') continue; /* Parse the line. The format is * <username> <blockdev> [<label>|"-" [<mountpoint>]] */ xfree (words); words = strtokenize (p, " \t"); if (!words) { err = gpg_error_from_syserror (); break; } if (!words[0] || !words[1]) { log_error (_("file '%s', line %d: %s\n"), fname, lnr, gpg_strerror (GPG_ERR_SYNTAX)); continue; } if (!(*words[1] == '/' || !strncmp (words[1], "PARTUUID=", 9) || !strncmp (words[1], "partuuid=", 9))) { log_error (_("file '%s', line %d: %s\n"), fname, lnr, "Invalid block device syntax"); continue; } if (words[2]) { if (strlen (words[2]) > 16 || strchr (words[2], '/')) { log_error (_("file '%s', line %d: %s\n"), fname, lnr, "Label too long or invalid syntax"); continue; } if (words[3] && *words[3] != '/') { log_error (_("file '%s', line %d: %s\n"), fname, lnr, "Invalid mountpoint syntax"); continue; } } if (strcmp (words[0], username)) continue; /* Skip entries for other usernames! */ ti = xtrymalloc (sizeof *ti + strlen (words[1])); if (!ti) { err = gpg_error_from_syserror (); break; } ti->next = NULL; ti->label = NULL; ti->mountpoint = NULL; strcpy (ti->blockdev, *words[1]=='/'? words[1] : words[1]+9); if (words[2]) { if (strcmp (words[2], "-") && !(ti->label = xtrystrdup (words[2]))) { err = gpg_error_from_syserror (); xfree (ti); break; } if (words[3] && !(ti->mountpoint = xtrystrdup (words[3]))) { err = gpg_error_from_syserror (); xfree (ti->label); xfree (ti); break; } } *tabletail = ti; tabletail = &ti->next; } if (!err && !es_feof (fp)) err = gpg_error_from_syserror (); if (err) log_error (_("error reading '%s', line %d: %s\n"), fname, lnr, gpg_strerror (err)); leave: xfree (words); es_fclose (fp); xfree (fname); if (err) { release_tab_items (table); return NULL; } return table; }
/* do the actual encryption */ static int encrypt_cb (void *cb_value, char *buffer, size_t count, size_t *nread) { struct encrypt_cb_parm_s *parm = cb_value; int blklen = parm->dek->ivlen; unsigned char *p; size_t n; *nread = 0; if (!buffer) return -1; /* not supported */ if (parm->ready) return -1; if (count < blklen) BUG (); if (!parm->eof_seen) { /* fillup the buffer */ p = parm->buffer; for (n=parm->buflen; n < parm->bufsize; n++) { int c = es_getc (parm->fp); if (c == EOF) { if (es_ferror (parm->fp)) { parm->readerror = errno; return -1; } parm->eof_seen = 1; break; } p[n] = c; } parm->buflen = n; } n = parm->buflen < count? parm->buflen : count; n = n/blklen * blklen; if (n) { /* encrypt the stuff */ gcry_cipher_encrypt (parm->dek->chd, buffer, n, parm->buffer, n); *nread = n; /* Who cares about cycles, take the easy way and shift the buffer */ parm->buflen -= n; memmove (parm->buffer, parm->buffer+n, parm->buflen); } else if (parm->eof_seen) { /* no complete block but eof: add padding */ /* fixme: we should try to do this also in the above code path */ int i, npad = blklen - (parm->buflen % blklen); p = parm->buffer; for (n=parm->buflen, i=0; n < parm->bufsize && i < npad; n++, i++) p[n] = npad; gcry_cipher_encrypt (parm->dek->chd, buffer, n, parm->buffer, n); *nread = n; parm->ready = 1; } return 0; }
/* Receive a WKS mail from FP and process it accordingly. On success * the RESULT_CB is called with the mediatype and a stream with the * decrypted data. */ gpg_error_t wks_receive (estream_t fp, gpg_error_t (*result_cb)(void *opaque, const char *mediatype, estream_t data), void *cb_data) { gpg_error_t err; receive_ctx_t ctx; mime_parser_t parser; estream_t plaintext = NULL; int c; ctx = xtrycalloc (1, sizeof *ctx); if (!ctx) return gpg_error_from_syserror (); err = mime_parser_new (&parser, ctx); if (err) goto leave; if (opt.verbose > 1 || opt.debug) mime_parser_set_verbose (parser, opt.debug? 10: 1); mime_parser_set_new_part (parser, new_part); mime_parser_set_part_data (parser, part_data); mime_parser_set_collect_encrypted (parser, collect_encrypted); mime_parser_set_collect_signeddata (parser, collect_signeddata); mime_parser_set_collect_signature (parser, collect_signature); err = mime_parser_parse (parser, fp); if (err) goto leave; if (ctx->key_data) log_info ("key data found\n"); if (ctx->wkd_data) log_info ("wkd data found\n"); if (ctx->plaintext) { if (opt.verbose) log_info ("parsing decrypted message\n"); plaintext = ctx->plaintext; ctx->plaintext = NULL; if (ctx->encrypted) es_rewind (ctx->encrypted); if (ctx->signeddata) es_rewind (ctx->signeddata); if (ctx->signature) es_rewind (ctx->signature); err = mime_parser_parse (parser, plaintext); if (err) return err; } if (!ctx->key_data && !ctx->wkd_data) { log_error ("no suitable data found in the message\n"); err = gpg_error (GPG_ERR_NO_DATA); goto leave; } if (ctx->key_data) { if (opt.debug) { es_rewind (ctx->key_data); log_debug ("Key: '"); log_printf ("\n"); while ((c = es_getc (ctx->key_data)) != EOF) log_printf ("%c", c); log_printf ("'\n"); } if (result_cb) { es_rewind (ctx->key_data); err = result_cb (cb_data, "application/pgp-keys", ctx->key_data); if (err) goto leave; } } if (ctx->wkd_data) { if (opt.debug) { es_rewind (ctx->wkd_data); log_debug ("WKD: '"); log_printf ("\n"); while ((c = es_getc (ctx->wkd_data)) != EOF) log_printf ("%c", c); log_printf ("'\n"); } if (result_cb) { es_rewind (ctx->wkd_data); err = result_cb (cb_data, "application/vnd.gnupg.wks", ctx->wkd_data); if (err) goto leave; } } leave: es_fclose (plaintext); mime_parser_release (parser); es_fclose (ctx->encrypted); es_fclose (ctx->plaintext); es_fclose (ctx->signeddata); es_fclose (ctx->signature); es_fclose (ctx->key_data); es_fclose (ctx->wkd_data); xfree (ctx); return err; }
/* Search the keyserver identified by URI for keys matching PATTERN. On success R_FP has an open stream to read the data. */ gpg_error_t ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern, estream_t *r_fp) { gpg_error_t err; KEYDB_SEARCH_DESC desc; char fprbuf[2+40+1]; char *hostport = NULL; char *request = NULL; estream_t fp = NULL; int reselect; unsigned int httpflags; char *httphost = NULL; unsigned int tries = SEND_REQUEST_RETRIES; *r_fp = NULL; /* Remove search type indicator and adjust PATTERN accordingly. Note that HKP keyservers like the 0x to be present when searching by keyid. We need to re-format the fingerprint and keyids so to remove the gpg specific force-use-of-this-key flag ("!"). */ err = classify_user_id (pattern, &desc, 1); if (err) return err; switch (desc.mode) { case KEYDB_SEARCH_MODE_EXACT: case KEYDB_SEARCH_MODE_SUBSTR: case KEYDB_SEARCH_MODE_MAIL: case KEYDB_SEARCH_MODE_MAILSUB: pattern = desc.u.name; break; case KEYDB_SEARCH_MODE_SHORT_KID: snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]); pattern = fprbuf; break; case KEYDB_SEARCH_MODE_LONG_KID: snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX", (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]); pattern = fprbuf; break; case KEYDB_SEARCH_MODE_FPR16: bin2hex (desc.u.fpr, 16, fprbuf); pattern = fprbuf; break; case KEYDB_SEARCH_MODE_FPR20: case KEYDB_SEARCH_MODE_FPR: bin2hex (desc.u.fpr, 20, fprbuf); pattern = fprbuf; break; default: return gpg_error (GPG_ERR_INV_USER_ID); } /* Build the request string. */ reselect = 0; again: { char *searchkey; xfree (hostport); hostport = NULL; xfree (httphost); httphost = NULL; err = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect, &hostport, &httpflags, &httphost); if (err) goto leave; searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS); if (!searchkey) { err = gpg_error_from_syserror (); goto leave; } xfree (request); request = strconcat (hostport, "/pks/lookup?op=index&options=mr&search=", searchkey, NULL); xfree (searchkey); if (!request) { err = gpg_error_from_syserror (); goto leave; } } /* Send the request. */ err = send_request (ctrl, request, hostport, httphost, httpflags, NULL, NULL, &fp); if (handle_send_request_error (err, request, &tries)) { reselect = 1; goto again; } if (err) goto leave; err = dirmngr_status (ctrl, "SOURCE", hostport, NULL); if (err) goto leave; /* Peek at the response. */ { int c = es_getc (fp); if (c == -1) { err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF); log_error ("error reading response: %s\n", gpg_strerror (err)); goto leave; } if (c == '<') { /* The document begins with a '<': Assume a HTML response, which we don't support. */ err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING); goto leave; } es_ungetc (c, fp); } /* Return the read stream. */ *r_fp = fp; fp = NULL; leave: es_fclose (fp); xfree (request); xfree (hostport); xfree (httphost); return err; }
static gpg_error_t read_one_trustfile (const char *fname, int allow_include, trustitem_t **addr_of_table, size_t *addr_of_tablesize, int *addr_of_tableidx) { gpg_error_t err = 0; estream_t fp; int n, c; char *p, line[256]; trustitem_t *table, *ti; int tableidx; size_t tablesize; int lnr = 0; table = *addr_of_table; tablesize = *addr_of_tablesize; tableidx = *addr_of_tableidx; fp = es_fopen (fname, "r"); if (!fp) { err = gpg_error_from_syserror (); log_error (_("error opening `%s': %s\n"), fname, gpg_strerror (err)); goto leave; } while (es_fgets (line, DIM(line)-1, fp)) { lnr++; n = strlen (line); if (!n || line[n-1] != '\n') { /* Eat until end of line. */ while ( (c=es_getc (fp)) != EOF && c != '\n') ; err = gpg_error (*line? GPG_ERR_LINE_TOO_LONG : GPG_ERR_INCOMPLETE_LINE); log_error (_("file `%s', line %d: %s\n"), fname, lnr, gpg_strerror (err)); continue; } line[--n] = 0; /* Chop the LF. */ if (n && line[n-1] == '\r') line[--n] = 0; /* Chop an optional CR. */ /* Allow for empty lines and spaces */ for (p=line; spacep (p); p++) ; if (!*p || *p == '#') continue; if (!strncmp (p, "include-default", 15) && (!p[15] || spacep (p+15))) { char *etcname; gpg_error_t err2; if (!allow_include) { log_error (_("statement \"%s\" ignored in `%s', line %d\n"), "include-default", fname, lnr); continue; } /* fixme: Should check for trailing garbage. */ etcname = make_filename (gnupg_sysconfdir (), "trustlist.txt", NULL); if ( !strcmp (etcname, fname) ) /* Same file. */ log_info (_("statement \"%s\" ignored in `%s', line %d\n"), "include-default", fname, lnr); else if ( access (etcname, F_OK) && errno == ENOENT ) { /* A non existent system trustlist is not an error. Just print a note. */ log_info (_("system trustlist `%s' not available\n"), etcname); } else { err2 = read_one_trustfile (etcname, 0, &table, &tablesize, &tableidx); if (err2) err = err2; } xfree (etcname); continue; } if (tableidx == tablesize) /* Need more space. */ { trustitem_t *tmp; size_t tmplen; tmplen = tablesize + 20; tmp = xtryrealloc (table, tmplen * sizeof *table); if (!tmp) { err = gpg_error_from_syserror (); goto leave; } table = tmp; tablesize = tmplen; } ti = table + tableidx; memset (&ti->flags, 0, sizeof ti->flags); if (*p == '!') { ti->flags.disabled = 1; p++; while (spacep (p)) p++; } n = hexcolon2bin (p, ti->fpr, 20); if (n < 0) { log_error (_("bad fingerprint in `%s', line %d\n"), fname, lnr); err = gpg_error (GPG_ERR_BAD_DATA); continue; } p += n; for (; spacep (p); p++) ; /* Process the first flag which needs to be the first for backward compatibility. */ if (!*p || *p == '*' ) { ti->flags.for_smime = 1; ti->flags.for_pgp = 1; } else if ( *p == 'P' || *p == 'p') { ti->flags.for_pgp = 1; } else if ( *p == 'S' || *p == 's') { ti->flags.for_smime = 1; } else { log_error (_("invalid keyflag in `%s', line %d\n"), fname, lnr); err = gpg_error (GPG_ERR_BAD_DATA); continue; } p++; if ( *p && !spacep (p) ) { log_error (_("invalid keyflag in `%s', line %d\n"), fname, lnr); err = gpg_error (GPG_ERR_BAD_DATA); continue; } /* Now check for more key-value pairs of the form NAME[=VALUE]. */ while (*p) { for (; spacep (p); p++) ; if (!*p) break; n = strcspn (p, "= \t"); if (p[n] == '=') { log_error ("assigning a value to a flag is not yet supported; " "in `%s', line %d\n", fname, lnr); err = gpg_error (GPG_ERR_BAD_DATA); p++; } else if (n == 5 && !memcmp (p, "relax", 5)) ti->flags.relax = 1; else if (n == 2 && !memcmp (p, "cm", 2)) ti->flags.cm = 1; else log_error ("flag `%.*s' in `%s', line %d ignored\n", n, p, fname, lnr); p += n; } tableidx++; } if ( !err && !es_feof (fp) ) { err = gpg_error_from_syserror (); log_error (_("error reading `%s', line %d: %s\n"), fname, lnr, gpg_strerror (err)); } leave: es_fclose (fp); *addr_of_table = table; *addr_of_tablesize = tablesize; *addr_of_tableidx = tableidx; return err; }
int main (int argc, char **argv) { int last_argc = -1; gpg_error_t err; int rc; parsed_uri_t uri; uri_tuple_t r; http_t hd; int c; unsigned int my_http_flags = 0; int no_out = 0; int tls_dbg = 0; int no_crl = 0; const char *cafile = NULL; http_session_t session = NULL; unsigned int timeout = 0; gpgrt_init (); log_set_prefix (PGM, GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_PID); if (argc) { argc--; argv++; } while (argc && last_argc != argc ) { last_argc = argc; if (!strcmp (*argv, "--")) { argc--; argv++; break; } else if (!strcmp (*argv, "--help")) { fputs ("usage: " PGM " URL\n" "Options:\n" " --verbose print timings etc.\n" " --debug flyswatter\n" " --tls-debug N use TLS debug level N\n" " --cacert FNAME expect CA certificate in file FNAME\n" " --timeout MS timeout for connect in MS\n" " --no-verify do not verify the certificate\n" " --force-tls use HTTP_FLAG_FORCE_TLS\n" " --force-tor use HTTP_FLAG_FORCE_TOR\n" " --no-out do not print the content\n" " --no-crl do not consuilt a CRL\n", stdout); exit (0); } else if (!strcmp (*argv, "--verbose")) { verbose++; argc--; argv++; } else if (!strcmp (*argv, "--debug")) { verbose += 2; debug++; argc--; argv++; } else if (!strcmp (*argv, "--tls-debug")) { argc--; argv++; if (argc) { tls_dbg = atoi (*argv); argc--; argv++; } } else if (!strcmp (*argv, "--cacert")) { argc--; argv++; if (argc) { cafile = *argv; argc--; argv++; } } else if (!strcmp (*argv, "--timeout")) { argc--; argv++; if (argc) { timeout = strtoul (*argv, NULL, 10); argc--; argv++; } } else if (!strcmp (*argv, "--no-verify")) { no_verify = 1; argc--; argv++; } else if (!strcmp (*argv, "--force-tls")) { my_http_flags |= HTTP_FLAG_FORCE_TLS; argc--; argv++; } else if (!strcmp (*argv, "--force-tor")) { my_http_flags |= HTTP_FLAG_FORCE_TOR; argc--; argv++; } else if (!strcmp (*argv, "--no-out")) { no_out = 1; argc--; argv++; } else if (!strcmp (*argv, "--no-crl")) { no_crl = 1; argc--; argv++; } else if (!strncmp (*argv, "--", 2)) { fprintf (stderr, PGM ": unknown option '%s'\n", *argv); exit (1); } } if (argc != 1) { fprintf (stderr, PGM ": no or too many URLS given\n"); exit (1); } if (!cafile) cafile = prepend_srcdir ("tls-ca.pem"); if (verbose) my_http_flags |= HTTP_FLAG_LOG_RESP; if (verbose || debug) http_set_verbose (verbose, debug); /* http.c makes use of the assuan socket wrapper. */ assuan_sock_init (); if ((my_http_flags & HTTP_FLAG_FORCE_TOR)) { enable_dns_tormode (1); if (assuan_sock_set_flag (ASSUAN_INVALID_FD, "tor-mode", 1)) { log_error ("error enabling Tor mode: %s\n", strerror (errno)); log_info ("(is your Libassuan recent enough?)\n"); } } #if HTTP_USE_NTBTLS log_info ("new session.\n"); err = http_session_new (&session, NULL, ((no_crl? HTTP_FLAG_NO_CRL : 0) | HTTP_FLAG_TRUST_DEF), my_http_tls_verify_cb, NULL); if (err) log_error ("http_session_new failed: %s\n", gpg_strerror (err)); ntbtls_set_debug (tls_dbg, NULL, NULL); #elif HTTP_USE_GNUTLS rc = gnutls_global_init (); if (rc) log_error ("gnutls_global_init failed: %s\n", gnutls_strerror (rc)); http_register_tls_callback (verify_callback); http_register_tls_ca (cafile); err = http_session_new (&session, NULL, ((no_crl? HTTP_FLAG_NO_CRL : 0) | HTTP_FLAG_TRUST_DEF), NULL, NULL); if (err) log_error ("http_session_new failed: %s\n", gpg_strerror (err)); /* rc = gnutls_dh_params_init(&dh_params); */ /* if (rc) */ /* log_error ("gnutls_dh_params_init failed: %s\n", gnutls_strerror (rc)); */ /* read_dh_params ("dh_param.pem"); */ /* rc = gnutls_certificate_set_x509_trust_file */ /* (certcred, "ca.pem", GNUTLS_X509_FMT_PEM); */ /* if (rc) */ /* log_error ("gnutls_certificate_set_x509_trust_file failed: %s\n", */ /* gnutls_strerror (rc)); */ /* gnutls_certificate_set_dh_params (certcred, dh_params); */ gnutls_global_set_log_function (my_gnutls_log); if (tls_dbg) gnutls_global_set_log_level (tls_dbg); #else (void)err; (void)tls_dbg; (void)no_crl; #endif /*HTTP_USE_GNUTLS*/ rc = http_parse_uri (&uri, *argv, 1); if (rc) { log_error ("'%s': %s\n", *argv, gpg_strerror (rc)); return 1; } printf ("Scheme: %s\n", uri->scheme); if (uri->opaque) printf ("Value : %s\n", uri->path); else { printf ("Auth : %s\n", uri->auth? uri->auth:"[none]"); printf ("Host : %s\n", uri->host); printf ("Port : %u\n", uri->port); printf ("Path : %s\n", uri->path); for (r = uri->params; r; r = r->next) { printf ("Params: %s", r->name); if (!r->no_value) { printf ("=%s", r->value); if (strlen (r->value) != r->valuelen) printf (" [real length=%d]", (int) r->valuelen); } putchar ('\n'); } for (r = uri->query; r; r = r->next) { printf ("Query : %s", r->name); if (!r->no_value) { printf ("=%s", r->value); if (strlen (r->value) != r->valuelen) printf (" [real length=%d]", (int) r->valuelen); } putchar ('\n'); } printf ("Flags :%s%s%s%s\n", uri->is_http? " http":"", uri->opaque? " opaque":"", uri->v6lit? " v6lit":"", uri->onion? " onion":""); printf ("TLS : %s\n", uri->use_tls? "yes": (my_http_flags&HTTP_FLAG_FORCE_TLS)? "forced" : "no"); printf ("Tor : %s\n", (my_http_flags&HTTP_FLAG_FORCE_TOR)? "yes" : "no"); } fflush (stdout); http_release_parsed_uri (uri); uri = NULL; if (session) http_session_set_timeout (session, timeout); rc = http_open_document (NULL, &hd, *argv, NULL, my_http_flags, NULL, session, NULL, NULL); if (rc) { log_error ("can't get '%s': %s\n", *argv, gpg_strerror (rc)); return 1; } log_info ("open_http_document succeeded; status=%u\n", http_get_status_code (hd)); { const char **names; int i; names = http_get_header_names (hd); if (!names) log_fatal ("http_get_header_names failed: %s\n", gpg_strerror (gpg_error_from_syserror ())); for (i = 0; names[i]; i++) printf ("HDR: %s: %s\n", names[i], http_get_header (hd, names[i])); xfree (names); } fflush (stdout); switch (http_get_status_code (hd)) { case 200: case 400: case 401: case 403: case 404: { unsigned long count = 0; while ((c = es_getc (http_get_read_ptr (hd))) != EOF) { count++; if (!no_out) putchar (c); } log_info ("Received bytes: %lu\n", count); } break; case 301: case 302: case 307: log_info ("Redirected to: %s\n", http_get_header (hd, "Location")); break; } http_close (hd, 0); http_session_release (session); #ifdef HTTP_USE_GNUTLS gnutls_global_deinit (); #endif /*HTTP_USE_GNUTLS*/ return 0; }
int main (int argc, char **argv) { gpg_error_t err; int rc; parsed_uri_t uri; uri_tuple_t r; http_t hd; int c; http_session_t session = NULL; gpgrt_init (); log_set_prefix ("t-http", 1 | 4); if (argc != 2) { fprintf (stderr, "usage: t-http uri\n"); return 1; } argc--; argv++; #ifdef HTTP_USE_GNUTLS rc = gnutls_global_init (); if (rc) log_error ("gnutls_global_init failed: %s\n", gnutls_strerror (rc)); http_register_tls_callback (verify_callback); http_register_tls_ca ("tls-ca.pem"); err = http_session_new (&session, NULL); if (err) log_error ("http_session_new failed: %s\n", gpg_strerror (err)); /* rc = gnutls_dh_params_init(&dh_params); */ /* if (rc) */ /* log_error ("gnutls_dh_params_init failed: %s\n", gnutls_strerror (rc)); */ /* read_dh_params ("dh_param.pem"); */ /* rc = gnutls_certificate_set_x509_trust_file */ /* (certcred, "ca.pem", GNUTLS_X509_FMT_PEM); */ /* if (rc) */ /* log_error ("gnutls_certificate_set_x509_trust_file failed: %s\n", */ /* gnutls_strerror (rc)); */ /* gnutls_certificate_set_dh_params (certcred, dh_params); */ gnutls_global_set_log_function (my_gnutls_log); /* gnutls_global_set_log_level (2); */ #endif /*HTTP_USE_GNUTLS*/ rc = http_parse_uri (&uri, *argv, 1); if (rc) { log_error ("'%s': %s\n", *argv, gpg_strerror (rc)); return 1; } printf ("Scheme: %s\n", uri->scheme); if (uri->opaque) printf ("Value : %s\n", uri->path); else { printf ("Auth : %s\n", uri->auth? uri->auth:"[none]"); printf ("Host : %s\n", uri->host); printf ("Port : %u\n", uri->port); printf ("Path : %s\n", uri->path); for (r = uri->params; r; r = r->next) { printf ("Params: %s", r->name); if (!r->no_value) { printf ("=%s", r->value); if (strlen (r->value) != r->valuelen) printf (" [real length=%d]", (int) r->valuelen); } putchar ('\n'); } for (r = uri->query; r; r = r->next) { printf ("Query : %s", r->name); if (!r->no_value) { printf ("=%s", r->value); if (strlen (r->value) != r->valuelen) printf (" [real length=%d]", (int) r->valuelen); } putchar ('\n'); } } http_release_parsed_uri (uri); uri = NULL; rc = http_open_document (&hd, *argv, NULL, 0, NULL, session, NULL, NULL); if (rc) { log_error ("can't get '%s': %s\n", *argv, gpg_strerror (rc)); return 1; } log_info ("open_http_document succeeded; status=%u\n", http_get_status_code (hd)); { const char **names; int i; names = http_get_header_names (hd); if (!names) log_fatal ("http_get_header_names failed: %s\n", gpg_strerror (gpg_error_from_syserror ())); for (i = 0; names[i]; i++) printf ("HDR: %s: %s\n", names[i], http_get_header (hd, names[i])); xfree (names); } switch (http_get_status_code (hd)) { case 200: case 400: case 401: case 403: case 404: while ((c = es_getc (http_get_read_ptr (hd))) != EOF) putchar (c); break; case 301: case 302: printf ("Redirected to '%s'\n", http_get_header (hd, "Location")); break; } http_close (hd, 0); http_session_release (session); #ifdef HTTP_USE_GNUTLS gnutls_global_deinit (); #endif /*HTTP_USE_GNUTLS*/ return 0; }
void read_exchange_rates (void) { gpg_error_t err = 0; estream_t fp; int lnr = 0; int n, c, idx; char line[256]; char *p, *pend; double rate; fp = es_fopen (euroxref_fname, "r"); if (!fp) { err = gpg_error_from_syserror (); log_error ("error opening '%s': %s\n", euroxref_fname, gpg_strerror (err)); return; } while (es_fgets (line, DIM(line)-1, fp)) { lnr++; n = strlen (line); if (!n || line[n-1] != '\n') { /* Eat until end of line. */ while ((c=es_getc (fp)) != EOF && c != '\n') ; err = gpg_error (*line? GPG_ERR_LINE_TOO_LONG : GPG_ERR_INCOMPLETE_LINE); log_error ("error reading '%s', line %d: %s\n", euroxref_fname, lnr, gpg_strerror (err)); continue; } line[--n] = 0; /* Chop the LF. */ if (n && line[n-1] == '\r') line[--n] = 0; /* Chop an optional CR. */ /* Allow leading spaces and skip empty and comment lines. */ for (p=line; spacep (p); p++) ; if (!*p || *p == '#') continue; /* Parse the currency name. */ pend = strchr (p, '='); if (!pend) { log_error ("error parsing '%s', line %d: %s\n", euroxref_fname, lnr, "missing '='"); continue; } *pend++ = 0; trim_spaces (p); if (!*p) { log_error ("error parsing '%s', line %d: %s\n", euroxref_fname, lnr, "currency name missing"); continue; } /* Note that we start at 1 to skip the first entry which is EUR. */ for (idx=1; idx < DIM(currency_table); idx++) if (!strcasecmp (currency_table[idx].name, p)) break; if (!(idx < DIM(currency_table))) continue; /* Currency not supported. */ /* Parse the rate. */ p = pend; errno = 0; rate = strtod (p, &pend); if ((!rate && p == pend) || errno || rate <= 0.0 || rate > 10000.0) { log_error ("error parsing '%s', line %d: %s\n", euroxref_fname, lnr, "invalid exchange rate"); continue; } p = pend; trim_spaces (p); if (*p) { log_error ("error parsing '%s', line %d: %s\n", euroxref_fname, lnr, "garbage after exchange rate"); continue; } /* Update the tbale. */ if (currency_table[idx].rate != rate) { if (!currency_table[idx].rate) log_info ("setting exchange rate for %s to %.4f\n", currency_table[idx].name, rate); else log_info ("changing exchange rate for %s from %.4f to %.4f\n", currency_table[idx].name, currency_table[idx].rate, rate); currency_table[idx].rate = rate; jrnl_store_exchange_rate_record (currency_table[idx].name, rate); } } es_fclose (fp); }