void write_status_text (int no, const char *text) { if (!statusfp || !status_currently_allowed (no) ) return; /* Not enabled or allowed. */ es_fputs ("[GNUPG:] ", statusfp); es_fputs (get_status_string (no), statusfp); if ( text ) { es_putc ( ' ', statusfp); for (; *text; text++) { if (*text == '\n') es_fputs ("\\n", statusfp); else if (*text == '\r') es_fputs ("\\r", statusfp); else es_fputc ( *(const byte *)text, statusfp); } } es_putc ('\n', statusfp); if (es_fflush (statusfp) && opt.exit_on_status_write_error) g10_exit (0); }
static gpg_error_t part_data (void *cookie, const void *data, size_t datalen) { receive_ctx_t ctx = cookie; if (data) { if (opt.debug) log_debug ("part_data: '%.*s'\n", (int)datalen, (const char*)data); if (ctx->collect_key_data) { if (es_write (ctx->key_data, data, datalen, NULL) || es_fputs ("\n", ctx->key_data)) return gpg_error_from_syserror (); } if (ctx->collect_wkd_data) { if (es_write (ctx->wkd_data, data, datalen, NULL) || es_fputs ("\n", ctx->wkd_data)) return gpg_error_from_syserror (); } } else { if (opt.debug) log_debug ("part_data: finished\n"); ctx->collect_key_data = 0; ctx->collect_wkd_data = 0; } return 0; }
/* This is a variant of gpgsm_print_name sending it output to an estream. */ void gpgsm_es_print_name2 (estream_t fp, const char *name, int translate) { const unsigned char *s = (const unsigned char *)name; int i; if (!s) { es_fputs (_("[Error - No name]"), fp); } else if (*s == '<') { const char *s2 = strchr ( (char*)s+1, '>'); if (s2) { if (translate) es_write_sanitized_utf8_buffer (fp, s + 1, s2 - (char*)s - 1, NULL, NULL); else es_write_sanitized (fp, s + 1, s2 - (char*)s - 1, NULL, NULL); } } else if (*s == '(') { pretty_es_print_sexp (fp, s, gcry_sexp_canon_len (s, 0, NULL, NULL)); } else if (!((*s >= '0' && *s < '9') || (*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z'))) es_fputs (_("[Error - invalid encoding]"), fp); else { struct dn_array_s *dn = parse_dn (s); if (!dn) es_fputs (_("[Error - invalid DN]"), fp); else { print_dn_parts (NULL, fp, dn, translate); for (i=0; dn[i].key; i++) { xfree (dn[i].key); xfree (dn[i].value); } xfree (dn); } } }
/* Print some info about the certifciate CERT to FP or STREAM */ static void print_short_info (ksba_cert_t cert, estream_t stream) { char *p; ksba_sexp_t sexp; int idx; for (idx=0; (p = ksba_cert_get_issuer (cert, idx)); idx++) { es_fputs ((!idx ? "Issuer ...: " : "\n aka ...: "), stream); gpgsm_es_print_name (stream, p); xfree (p); } es_putc ('\n', stream); es_fputs ("Serial ...: ", stream); sexp = ksba_cert_get_serial (cert); if (sexp) { int len; const unsigned char *s = sexp; if (*s == '(') { s++; for (len=0; *s && *s != ':' && digitp (s); s++) len = len*10 + atoi_1 (s); if (*s == ':') es_write_hexstring (stream, s+1, len, 0, NULL); } xfree (sexp); } es_putc ('\n', stream); for (idx=0; (p = ksba_cert_get_subject (cert, idx)); idx++) { es_fputs ((!idx ? "Subject ..: " : "\n aka ..: "), stream); gpgsm_es_print_name (stream, p); xfree (p); } es_putc ('\n', stream); }
void gpgsm_print_time (estream_t fp, ksba_isotime_t t) { if (!t || !*t) es_fputs (_("none"), fp); else es_fprintf (fp, "%.4s-%.2s-%.2s %.2s:%.2s:%s", t, t+4, t+6, t+9, t+11, t+13); }
/* Write a status line with code NO followed by the outout of the * printf style FORMAT. The caller needs to make sure that LFs and * CRs are not printed. */ void wks_write_status (int no, const char *format, ...) { va_list arg_ptr; if (!statusfp) return; /* Not enabled. */ es_fputs ("[GNUPG:] ", statusfp); es_fputs (get_status_string (no), statusfp); if (format) { es_putc (' ', statusfp); va_start (arg_ptr, format); es_vfprintf (statusfp, format, arg_ptr); va_end (arg_ptr); } es_putc ('\n', statusfp); }
/* Print the first element of an S-Expression. */ void gpgsm_print_serial (estream_t fp, ksba_const_sexp_t sn) { const char *p = (const char *)sn; unsigned long n; char *endp; if (!p) es_fputs (_("none"), fp); else if (*p != '(') es_fputs ("[Internal error - not an S-expression]", fp); else { p++; n = strtoul (p, &endp, 10); p = endp; if (*p++ != ':') es_fputs ("[Internal Error - invalid S-expression]", fp); else es_write_hexstring (fp, p, n, 0, NULL); } }
static gpg_error_t collect_signeddata (void *cookie, const char *data) { receive_ctx_t ctx = cookie; if (!ctx->signeddata) if (!(ctx->signeddata = es_fopenmem (MAX_SIGNEDDATA, "w+b,samethread"))) return gpg_error_from_syserror (); if (data) es_fputs (data, ctx->signeddata); if (es_ferror (ctx->signeddata)) return gpg_error_from_syserror (); return 0; }
/* Helper for ks_hkp_put. */ static gpg_error_t put_post_cb (void *opaque, http_t http) { struct put_post_parm_s *parm = opaque; gpg_error_t err = 0; estream_t fp; size_t len; fp = http_get_write_ptr (http); len = strlen (parm->datastring); es_fprintf (fp, "Content-Type: application/x-www-form-urlencoded\r\n" "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */); http_start_data (http); if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL)) err = gpg_error_from_syserror (); return err; }
static gpg_error_t collect_signature (void *cookie, const char *data) { receive_ctx_t ctx = cookie; if (!ctx->signature) if (!(ctx->signature = es_fopenmem (MAX_SIGNATURE, "w+b,samethread"))) return gpg_error_from_syserror (); if (data) es_fputs (data, ctx->signature); if (es_ferror (ctx->signature)) return gpg_error_from_syserror (); if (!data) { verify_signature (ctx); } return 0; }
static gpg_error_t collect_encrypted (void *cookie, const char *data) { receive_ctx_t ctx = cookie; if (!ctx->encrypted) if (!(ctx->encrypted = es_fopenmem (MAX_ENCRYPTED, "w+b,samethread"))) return gpg_error_from_syserror (); if (data) es_fputs (data, ctx->encrypted); if (es_ferror (ctx->encrypted)) return gpg_error_from_syserror (); if (!data) { decrypt_data (ctx); } return 0; }
/* Print the S-Expression in BUF to extended STREAM, which has a valid length of BUFLEN, as a human readable string in one line to FP. */ static void pretty_es_print_sexp (estream_t fp, const unsigned char *buf, size_t buflen) { size_t len; gcry_sexp_t sexp; char *result, *p; if ( gcry_sexp_sscan (&sexp, NULL, (const char*)buf, buflen) ) { es_fputs (_("[Error - invalid encoding]"), fp); return; } len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0); assert (len); result = xtrymalloc (len); if (!result) { es_fputs (_("[Error - out of core]"), fp); gcry_sexp_release (sexp); return; } len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, result, len); assert (len); for (p = result; len; len--, p++) { if (*p == '\n') { if (len > 1) /* Avoid printing the trailing LF. */ es_fputs ("\\n", fp); } else if (*p == '\r') es_fputs ("\\r", fp); else if (*p == '\v') es_fputs ("\\v", fp); else if (*p == '\t') es_fputs ("\\t", fp); else es_putc (*p, fp); } xfree (result); gcry_sexp_release (sexp); }
/* Send an HTTP request. On success returns an estream object at R_FP. HOSTPORTSTR is only used for diagnostics. If HTTPHOST is not NULL it will be used as HTTP "Host" header. If POST_CB is not NULL a post request is used and that callback is called to allow writing the post data. */ static gpg_error_t send_request (ctrl_t ctrl, const char *request, const char *hostportstr, const char *httphost, unsigned int httpflags, gpg_error_t (*post_cb)(void *, http_t), void *post_cb_value, estream_t *r_fp) { gpg_error_t err; http_session_t session = NULL; http_t http = NULL; int redirects_left = MAX_REDIRECTS; estream_t fp = NULL; char *request_buffer = NULL; *r_fp = NULL; err = http_session_new (&session, NULL); if (err) goto leave; http_session_set_log_cb (session, cert_log_cb); once_more: err = http_open (&http, post_cb? HTTP_REQ_POST : HTTP_REQ_GET, request, httphost, /* fixme: AUTH */ NULL, (httpflags | (opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)), ctrl->http_proxy, session, NULL, /*FIXME curl->srvtag*/NULL); if (!err) { fp = http_get_write_ptr (http); /* Avoid caches to get the most recent copy of the key. We set both the Pragma and Cache-Control versions of the header, so we're good with both HTTP 1.0 and 1.1. */ es_fputs ("Pragma: no-cache\r\n" "Cache-Control: no-cache\r\n", fp); if (post_cb) err = post_cb (post_cb_value, http); if (!err) { http_start_data (http); if (es_ferror (fp)) err = gpg_error_from_syserror (); } } if (err) { /* Fixme: After a redirection we show the old host name. */ log_error (_("error connecting to '%s': %s\n"), hostportstr, gpg_strerror (err)); goto leave; } /* Wait for the response. */ dirmngr_tick (ctrl); err = http_wait_response (http); if (err) { log_error (_("error reading HTTP response for '%s': %s\n"), hostportstr, gpg_strerror (err)); goto leave; } if (http_get_tls_info (http, NULL)) { /* Update the httpflags so that a redirect won't fallback to an unencrypted connection. */ httpflags |= HTTP_FLAG_FORCE_TLS; } switch (http_get_status_code (http)) { case 200: err = 0; break; /* Success. */ case 301: case 302: case 307: { const char *s = http_get_header (http, "Location"); log_info (_("URL '%s' redirected to '%s' (%u)\n"), request, s?s:"[none]", http_get_status_code (http)); if (s && *s && redirects_left-- ) { xfree (request_buffer); request_buffer = xtrystrdup (s); if (request_buffer) { request = request_buffer; http_close (http, 0); http = NULL; goto once_more; } err = gpg_error_from_syserror (); } else err = gpg_error (GPG_ERR_NO_DATA); log_error (_("too many redirections\n")); } goto leave; default: log_error (_("error accessing '%s': http status %u\n"), request, http_get_status_code (http)); err = gpg_error (GPG_ERR_NO_DATA); goto leave; } /* FIXME: We should register a permanent redirection and whether a host has ever used TLS so that future calls will always use TLS. */ fp = http_get_read_ptr (http); if (!fp) { err = gpg_error (GPG_ERR_BUG); goto leave; } /* Return the read stream and close the HTTP context. */ *r_fp = fp; http_close (http, 1); http = NULL; leave: http_close (http, 0); http_session_release (session); xfree (request_buffer); return err; }
/* Get the key from URL which is expected to specify a http style scheme. On success R_FP has an open stream to read the data. */ gpg_error_t ks_http_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp) { gpg_error_t err; http_session_t session = NULL; http_t http = NULL; int redirects_left = MAX_REDIRECTS; estream_t fp = NULL; char *request_buffer = NULL; err = http_session_new (&session, NULL); if (err) goto leave; http_session_set_log_cb (session, cert_log_cb); *r_fp = NULL; once_more: err = http_open (&http, HTTP_REQ_GET, url, /* httphost */ NULL, /* fixme: AUTH */ NULL, 0, /* fixme: proxy*/ NULL, session, NULL, /*FIXME curl->srvtag*/NULL); if (!err) { fp = http_get_write_ptr (http); /* Avoid caches to get the most recent copy of the key. We set both the Pragma and Cache-Control versions of the header, so we're good with both HTTP 1.0 and 1.1. */ es_fputs ("Pragma: no-cache\r\n" "Cache-Control: no-cache\r\n", fp); http_start_data (http); if (es_ferror (fp)) err = gpg_error_from_syserror (); } if (err) { /* Fixme: After a redirection we show the old host name. */ log_error (_("error connecting to '%s': %s\n"), url, gpg_strerror (err)); goto leave; } /* Wait for the response. */ dirmngr_tick (ctrl); err = http_wait_response (http); if (err) { log_error (_("error reading HTTP response for '%s': %s\n"), url, gpg_strerror (err)); goto leave; } switch (http_get_status_code (http)) { case 200: err = 0; break; /* Success. */ case 301: case 302: case 307: { const char *s = http_get_header (http, "Location"); log_info (_("URL '%s' redirected to '%s' (%u)\n"), url, s?s:"[none]", http_get_status_code (http)); if (s && *s && redirects_left-- ) { xfree (request_buffer); request_buffer = xtrystrdup (s); if (request_buffer) { url = request_buffer; http_close (http, 0); http = NULL; goto once_more; } err = gpg_error_from_syserror (); } else err = gpg_error (GPG_ERR_NO_DATA); log_error (_("too many redirections\n")); } goto leave; default: log_error (_("error accessing '%s': http status %u\n"), url, http_get_status_code (http)); err = gpg_error (GPG_ERR_NO_DATA); goto leave; } fp = http_get_read_ptr (http); if (!fp) { err = gpg_error (GPG_ERR_BUG); goto leave; } /* Return the read stream and close the HTTP context. */ *r_fp = fp; http_close (http, 1); http = NULL; leave: http_close (http, 0); http_session_release (session); xfree (request_buffer); return err; }
/* Get a key by fingerprint from gpg's keyring and make sure that the * mail address ADDRSPEC is included in the key. If EXACT is set the * returned user id must match Addrspec exactly and not just in the * addr-spec (mailbox) part. The key is returned as a new memory * stream at R_KEY. */ gpg_error_t wks_get_key (estream_t *r_key, const char *fingerprint, const char *addrspec, int exact) { gpg_error_t err; ccparray_t ccp; const char **argv = NULL; estream_t key = NULL; struct get_key_status_parm_s parm; char *filterexp = NULL; memset (&parm, 0, sizeof parm); *r_key = NULL; key = es_fopenmem (0, "w+b"); if (!key) { err = gpg_error_from_syserror (); log_error ("error allocating memory buffer: %s\n", gpg_strerror (err)); goto leave; } /* Prefix the key with the MIME content type. */ es_fputs ("Content-Type: application/pgp-keys\n" "\n", key); filterexp = es_bsprintf ("keep-uid=%s=%s", exact? "uid":"mbox", addrspec); if (!filterexp) { err = gpg_error_from_syserror (); log_error ("error allocating memory buffer: %s\n", gpg_strerror (err)); goto leave; } ccparray_init (&ccp, 0); ccparray_put (&ccp, "--no-options"); if (!opt.verbose) ccparray_put (&ccp, "--quiet"); else if (opt.verbose > 1) ccparray_put (&ccp, "--verbose"); ccparray_put (&ccp, "--batch"); ccparray_put (&ccp, "--status-fd=2"); ccparray_put (&ccp, "--always-trust"); ccparray_put (&ccp, "--armor"); ccparray_put (&ccp, "--export-options=export-minimal"); ccparray_put (&ccp, "--export-filter"); ccparray_put (&ccp, filterexp); ccparray_put (&ccp, "--export"); ccparray_put (&ccp, "--"); ccparray_put (&ccp, fingerprint); ccparray_put (&ccp, NULL); argv = ccparray_get (&ccp, NULL); if (!argv) { err = gpg_error_from_syserror (); goto leave; } parm.fpr = fingerprint; err = gnupg_exec_tool_stream (opt.gpg_program, argv, NULL, NULL, key, get_key_status_cb, &parm); if (!err && parm.count > 1) err = gpg_error (GPG_ERR_TOO_MANY); else if (!err && !parm.found) err = gpg_error (GPG_ERR_NOT_FOUND); if (err) { log_error ("export failed: %s\n", gpg_strerror (err)); goto leave; } es_rewind (key); *r_key = key; key = NULL; leave: es_fclose (key); xfree (argv); xfree (filterexp); return err; }
/* Insert the given fpr into our trustdb. We expect FPR to be an all uppercase hexstring of 40 characters. FLAG is either 'P' or 'C'. This function does first check whether that key has already been put into the trustdb and returns success in this case. Before a FPR actually gets inserted, the user is asked by means of the Pinentry whether this is actual want he wants to do. */ gpg_error_t agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag) { gpg_error_t err = 0; char *desc; char *fname; estream_t fp; char *fprformatted; char *nameformatted; int is_disabled; int yes_i_trust; /* Check whether we are at all allowed to modify the trustlist. This is useful so that the trustlist may be a symlink to a global trustlist with only admin priviliges to modify it. Of course this is not a secure way of denying access, but it avoids the usual clicking on an Okay button most users are used to. */ fname = make_filename (opt.homedir, "trustlist.txt", NULL); if ( access (fname, W_OK) && errno != ENOENT) { xfree (fname); return gpg_error (GPG_ERR_EPERM); } xfree (fname); if (!agent_istrusted (ctrl, fpr, &is_disabled)) { return 0; /* We already got this fingerprint. Silently return success. */ } /* This feature must explicitly been enabled. */ if (!opt.allow_mark_trusted) return gpg_error (GPG_ERR_NOT_SUPPORTED); if (is_disabled) { /* There is an disabled entry in the trustlist. Return an error so that the user won't be asked again for that one. Changing this flag with the integrated marktrusted feature is and will not be made possible. */ return gpg_error (GPG_ERR_NOT_TRUSTED); } /* Insert a new one. */ nameformatted = reformat_name (name, "%0A "); if (!nameformatted) return gpg_error_from_syserror (); /* First a general question whether this is trusted. */ desc = xtryasprintf ( /* TRANSLATORS: This prompt is shown by the Pinentry and has one special property: A "%%0A" is used by Pinentry to insert a line break. The double percent sign is actually needed because it is also a printf format string. If you need to insert a plain % sign, you need to encode it as "%%25". The "%s" gets replaced by the name as stored in the certificate. */ _("Do you ultimately trust%%0A" " \"%s\"%%0A" "to correctly certify user certificates?"), nameformatted); if (!desc) { xfree (nameformatted); return out_of_core (); } err = agent_get_confirmation (ctrl, desc, _("Yes"), _("No"), 1); xfree (desc); if (!err) yes_i_trust = 1; else if (gpg_err_code (err) == GPG_ERR_NOT_CONFIRMED) yes_i_trust = 0; else { xfree (nameformatted); return err; } fprformatted = insert_colons (fpr); if (!fprformatted) { xfree (nameformatted); return out_of_core (); } /* If the user trusts this certificate he has to verify the fingerprint of course. */ if (yes_i_trust) { desc = xtryasprintf ( /* TRANSLATORS: This prompt is shown by the Pinentry and has one special property: A "%%0A" is used by Pinentry to insert a line break. The double percent sign is actually needed because it is also a printf format string. If you need to insert a plain % sign, you need to encode it as "%%25". The second "%s" gets replaced by a hexdecimal fingerprint string whereas the first one receives the name as stored in the certificate. */ _("Please verify that the certificate identified as:%%0A" " \"%s\"%%0A" "has the fingerprint:%%0A" " %s"), nameformatted, fprformatted); if (!desc) { xfree (fprformatted); xfree (nameformatted); return out_of_core (); } /* TRANSLATORS: "Correct" is the label of a button and intended to be hit if the fingerprint matches the one of the CA. The other button is "the default "Cancel" of the Pinentry. */ err = agent_get_confirmation (ctrl, desc, _("Correct"), _("Wrong"), 1); xfree (desc); if (gpg_err_code (err) == GPG_ERR_NOT_CONFIRMED) yes_i_trust = 0; else if (err) { xfree (fprformatted); xfree (nameformatted); return err; } } /* Now check again to avoid duplicates. We take the lock to make sure that nobody else plays with our file and force a reread. */ lock_trusttable (); agent_reload_trustlist (); if (!agent_istrusted (ctrl, fpr, &is_disabled) || is_disabled) { unlock_trusttable (); xfree (fprformatted); xfree (nameformatted); return is_disabled? gpg_error (GPG_ERR_NOT_TRUSTED) : 0; } fname = make_filename (opt.homedir, "trustlist.txt", NULL); if ( access (fname, F_OK) && errno == ENOENT) { fp = es_fopen (fname, "wx,mode=-rw-r"); if (!fp) { err = gpg_error_from_syserror (); log_error ("can't create `%s': %s\n", fname, gpg_strerror (err)); xfree (fname); unlock_trusttable (); xfree (fprformatted); xfree (nameformatted); return err; } es_fputs (headerblurb, fp); es_fclose (fp); } fp = es_fopen (fname, "a+,mode=-rw-r"); if (!fp) { err = gpg_error_from_syserror (); log_error ("can't open `%s': %s\n", fname, gpg_strerror (err)); xfree (fname); unlock_trusttable (); xfree (fprformatted); xfree (nameformatted); return err; } /* Append the key. */ es_fputs ("\n# ", fp); xfree (nameformatted); nameformatted = reformat_name (name, "\n# "); if (!nameformatted || strchr (name, '\n')) { /* Note that there should never be a LF in NAME but we better play safe and print a sanitized version in this case. */ es_write_sanitized (fp, name, strlen (name), NULL, NULL); } else es_fputs (nameformatted, fp); es_fprintf (fp, "\n%s%s %c\n", yes_i_trust?"":"!", fprformatted, flag); if (es_ferror (fp)) err = gpg_error_from_syserror (); if (es_fclose (fp)) err = gpg_error_from_syserror (); agent_reload_trustlist (); xfree (fname); unlock_trusttable (); xfree (fprformatted); xfree (nameformatted); return err; }
/* * Write a status line with a buffer using %XX escapes. If WRAP is > * 0 wrap the line after this length. If STRING is not NULL it will * be prepended to the buffer, no escaping is done for string. * A wrap of -1 forces spaces not to be encoded as %20. */ void write_status_text_and_buffer (int no, const char *string, const char *buffer, size_t len, int wrap) { const char *s, *text; int esc, first; int lower_limit = ' '; size_t n, count, dowrap; if (!statusfp || !status_currently_allowed (no)) return; /* Not enabled or allowed. */ if (wrap == -1) { lower_limit--; wrap = 0; } text = get_status_string (no); count = dowrap = first = 1; do { if (dowrap) { es_fprintf (statusfp, "[GNUPG:] %s ", text); count = dowrap = 0; if (first && string) { es_fputs (string, statusfp); count += strlen (string); /* Make sure that there is a space after the string. */ if (*string && string[strlen (string)-1] != ' ') { es_putc (' ', statusfp); count++; } } first = 0; } for (esc=0, s=buffer, n=len; n && !esc; s++, n--) { if (*s == '%' || *(const byte*)s <= lower_limit || *(const byte*)s == 127 ) esc = 1; if (wrap && ++count > wrap) { dowrap=1; break; } } if (esc) { s--; n++; } if (s != buffer) es_fwrite (buffer, s-buffer, 1, statusfp); if ( esc ) { es_fprintf (statusfp, "%%%02X", *(const byte*)s ); s++; n--; } buffer = s; len = n; if (dowrap && len) es_putc ('\n', statusfp); } while (len); es_putc ('\n',statusfp); if (es_fflush (statusfp) && opt.exit_on_status_write_error) g10_exit (0); }
/* Run gpg as a filter on KEY and write the output to a new stream * stored at R_NEWKEY. The new key will contain only the user id UID. * Returns 0 on success. Only one key is expected in KEY. If BINARY * is set the resulting key is returned as a binary (non-armored) * keyblock. */ gpg_error_t wks_filter_uid (estream_t *r_newkey, estream_t key, const char *uid, int binary) { gpg_error_t err; ccparray_t ccp; const char **argv = NULL; estream_t newkey; char *filterexp = NULL; *r_newkey = NULL; /* Open a memory stream. */ newkey = es_fopenmem (0, "w+b"); if (!newkey) { err = gpg_error_from_syserror (); log_error ("error allocating memory buffer: %s\n", gpg_strerror (err)); return err; } /* Prefix the key with the MIME content type. */ if (!binary) es_fputs ("Content-Type: application/pgp-keys\n" "\n", newkey); filterexp = es_bsprintf ("keep-uid=uid=%s", uid); if (!filterexp) { err = gpg_error_from_syserror (); log_error ("error allocating memory buffer: %s\n", gpg_strerror (err)); goto leave; } ccparray_init (&ccp, 0); ccparray_put (&ccp, "--no-options"); if (!opt.verbose) ccparray_put (&ccp, "--quiet"); else if (opt.verbose > 1) ccparray_put (&ccp, "--verbose"); ccparray_put (&ccp, "--batch"); ccparray_put (&ccp, "--status-fd=2"); ccparray_put (&ccp, "--always-trust"); if (!binary) ccparray_put (&ccp, "--armor"); ccparray_put (&ccp, "--import-options=import-export"); ccparray_put (&ccp, "--import-filter"); ccparray_put (&ccp, filterexp); ccparray_put (&ccp, "--import"); 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, key, NULL, newkey, key_status_cb, NULL); if (err) { log_error ("import/export failed: %s\n", gpg_strerror (err)); goto leave; } es_rewind (newkey); *r_newkey = newkey; newkey = NULL; leave: xfree (filterexp); xfree (argv); es_fclose (newkey); return err; }
/* gpgconf main. */ int main (int argc, char **argv) { ARGPARSE_ARGS pargs; const char *fname; int no_more_options = 0; enum cmd_and_opt_values cmd = 0; estream_t outfp = NULL; early_system_init (); gnupg_reopen_std (GPGCONF_NAME); set_strusage (my_strusage); log_set_prefix (GPGCONF_NAME, 1); /* Make sure that our subsystems are ready. */ i18n_init(); init_common_subsystems (&argc, &argv); /* Parse the command line. */ pargs.argc = &argc; pargs.argv = &argv; pargs.flags = 1; /* Do not remove the args. */ while (!no_more_options && optfile_parse (NULL, NULL, NULL, &pargs, opts)) { switch (pargs.r_opt) { case oOutput: opt.outfile = pargs.r.ret_str; break; case oQuiet: opt.quiet = 1; break; case oDryRun: opt.dry_run = 1; break; case oRuntime: opt.runtime = 1; break; case oVerbose: opt.verbose++; break; case oNoVerbose: opt.verbose = 0; break; case aListDirs: case aListComponents: case aCheckPrograms: case aListOptions: case aChangeOptions: case aCheckOptions: case aApplyDefaults: case aListConfig: case aCheckConfig: case aReload: case aLaunch: case aKill: cmd = pargs.r_opt; break; default: pargs.err = 2; break; } } if (log_get_errorcount (0)) exit (2); /* Print a warning if an argument looks like an option. */ if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN)) { int i; for (i=0; i < argc; i++) if (argv[i][0] == '-' && argv[i][1] == '-') log_info (_("Note: '%s' is not considered an option\n"), argv[i]); } fname = argc ? *argv : NULL; switch (cmd) { case aListComponents: default: /* List all components. */ gc_component_list_components (get_outfp (&outfp)); break; case aCheckPrograms: /* Check all programs. */ gc_check_programs (get_outfp (&outfp)); break; case aListOptions: case aChangeOptions: case aCheckOptions: if (!fname) { es_fprintf (es_stderr, _("usage: %s [options] "), GPGCONF_NAME); es_putc ('\n', es_stderr); es_fputs (_("Need one component argument"), es_stderr); es_putc ('\n', es_stderr); exit (2); } else { int idx = gc_component_find (fname); if (idx < 0) { es_fputs (_("Component not found"), es_stderr); es_putc ('\n', es_stderr); exit (1); } if (cmd == aCheckOptions) gc_component_check_options (idx, get_outfp (&outfp), NULL); else { gc_component_retrieve_options (idx); if (gc_process_gpgconf_conf (NULL, 1, 0, NULL)) exit (1); if (cmd == aListOptions) gc_component_list_options (idx, get_outfp (&outfp)); else if (cmd == aChangeOptions) gc_component_change_options (idx, es_stdin, get_outfp (&outfp)); } } break; case aLaunch: case aKill: if (!fname) { es_fprintf (es_stderr, _("usage: %s [options] "), GPGCONF_NAME); es_putc ('\n', es_stderr); es_fputs (_("Need one component argument"), es_stderr); es_putc ('\n', es_stderr); exit (2); } else { /* Launch/Kill a given component. */ int idx; idx = gc_component_find (fname); if (idx < 0) { es_fputs (_("Component not found"), es_stderr); es_putc ('\n', es_stderr); exit (1); } else if (cmd == aLaunch) { if (gc_component_launch (idx)) exit (1); } else { /* We don't error out if the kill failed because this command should do nothing if the component is not running. */ gc_component_kill (idx); } } break; case aReload: if (!fname) { /* Reload all. */ gc_component_reload (-1); } else { /* Reload given component. */ int idx; idx = gc_component_find (fname); if (idx < 0) { es_fputs (_("Component not found"), es_stderr); es_putc ('\n', es_stderr); exit (1); } else { gc_component_reload (idx); } } break; case aListConfig: if (gc_process_gpgconf_conf (fname, 0, 0, get_outfp (&outfp))) exit (1); break; case aCheckConfig: if (gc_process_gpgconf_conf (fname, 0, 0, NULL)) exit (1); break; case aApplyDefaults: if (fname) { es_fprintf (es_stderr, _("usage: %s [options] "), GPGCONF_NAME); es_putc ('\n', es_stderr); es_fputs (_("No argument allowed"), es_stderr); es_putc ('\n', es_stderr); exit (2); } gc_component_retrieve_options (-1); if (gc_process_gpgconf_conf (NULL, 1, 1, NULL)) exit (1); break; case aListDirs: /* Show the system configuration directories for gpgconf. */ get_outfp (&outfp); es_fprintf (outfp, "sysconfdir:%s\n", gc_percent_escape (gnupg_sysconfdir ())); es_fprintf (outfp, "bindir:%s\n", gc_percent_escape (gnupg_bindir ())); es_fprintf (outfp, "libexecdir:%s\n", gc_percent_escape (gnupg_libexecdir ())); es_fprintf (outfp, "libdir:%s\n", gc_percent_escape (gnupg_libdir ())); es_fprintf (outfp, "datadir:%s\n", gc_percent_escape (gnupg_datadir ())); es_fprintf (outfp, "localedir:%s\n", gc_percent_escape (gnupg_localedir ())); if (dirmngr_user_socket_name ()) { es_fprintf (outfp, "dirmngr-socket:%s\n", gc_percent_escape (dirmngr_user_socket_name ())); es_fprintf (outfp, "dirmngr-sys-socket:%s\n", gc_percent_escape (dirmngr_sys_socket_name ())); } else { es_fprintf (outfp, "dirmngr-socket:%s\n", gc_percent_escape (dirmngr_sys_socket_name ())); } { char *tmp = make_filename (default_homedir (), GPG_AGENT_SOCK_NAME, NULL); es_fprintf (outfp, "agent-socket:%s\n", gc_percent_escape (tmp)); xfree (tmp); } { /* We need to use make_filename to expand a possible "~/". */ char *tmp = make_filename (default_homedir (), NULL); es_fprintf (outfp, "homedir:%s\n", gc_percent_escape (tmp)); xfree (tmp); } break; } if (outfp != es_stdout) if (es_fclose (outfp)) gc_error (1, errno, "error closing '%s'", opt.outfile); return 0; }