/* Pop up the PINentry, display the text DESC and a button with the text OK_BTN (which may be NULL to use the default of "OK") and wait for the user to hit this button. The return value is not relevant. */ int agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn) { int rc; char line[ASSUAN_LINELENGTH]; if (ctrl->pinentry_mode != PINENTRY_MODE_ASK) return gpg_error (GPG_ERR_CANCELED); rc = start_pinentry (ctrl); if (rc) return rc; if (desc) snprintf (line, DIM(line)-1, "SETDESC %s", desc); else snprintf (line, DIM(line)-1, "RESET"); line[DIM(line)-1] = 0; rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); /* Most pinentries out in the wild return the old Assuan error code for canceled which gets translated to an assuan Cancel error and not to the code for a user cancel. Fix this here. */ if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED) rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); if (rc) return unlock_pinentry (rc); if (ok_btn) { snprintf (line, DIM(line)-1, "SETOK %s", ok_btn); line[DIM(line)-1] = 0; rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return unlock_pinentry (rc); } rc = assuan_transact (entry_ctx, "CONFIRM --one-button", NULL, NULL, NULL, NULL, NULL, NULL); if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED) rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); return unlock_pinentry (rc); }
static void first_half_done_cb (GpaContext *context, gpg_error_t err, GpaKeyTable *keytable) { if (keytable->did_first_half || !cms_hack) { /* We are here for the second time and thus we continue with the real done handler. We do this also if the CMS_HACK has not been enabled. We reset the protocol to OpenPGP because some old code might assume that it is in OpenPGP mode. */ keytable->fpr = NULL; /* Not needed anymore. */ gpgme_set_protocol (keytable->context->ctx, GPGME_PROTOCOL_OpenPGP); done_cb (context, err, keytable); return; } /* Now continue with a key listing for X.509 keys but save the error of the the PGP key listing. */ keytable->first_half_err = err; keytable->did_first_half = 1; gpgme_set_protocol (context->ctx, GPGME_PROTOCOL_CMS); err = gpgme_op_keylist_start (keytable->context->ctx, keytable->fpr, keytable->secret); keytable->fpr = NULL; /* Not needed anymore. */ if (err) { if (keytable->first_half_err) gpa_gpgme_warning (keytable->first_half_err); if ((gpg_err_code (err) == GPG_ERR_INV_ENGINE || gpg_err_code (err) == GPG_ERR_UNSUPPORTED_PROTOCOL) && gpg_err_source (err) == GPG_ERR_SOURCE_GPGME) { if (gpg_err_code (err) == GPG_ERR_UNSUPPORTED_PROTOCOL) g_message ("Note: Please check libgpgme has " "been build with support for CMS"); gpa_window_error (_("It seems that no CMS engine is installed.\n\n" "Temporary disabling support for X.509.\n\n" "Please install a CMS engine or invoke this program\n" "with the option --disable-x509 ."), NULL); cms_hack = 0; err = 0; } else gpa_gpgme_warning (err); if (keytable->end) { keytable->end (keytable->data); } } }
/* The main processing function as used by the runner. */ static gpg_error_t encfs_handler (void *opaque, runner_t runner, const char *status_line) { encfs_parm_t parm = opaque; gpg_error_t err; if (!parm || !runner) return gpg_error (GPG_ERR_BUG); if (!status_line) { /* Runner requested internal flushing - nothing to do here. */ return 0; } err = handle_status_line (runner, status_line, parm->cmd, parm->tuples); if (gpg_err_code (err) == GPG_ERR_UNFINISHED && gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT) { err = 0; /* No more need for the tuples. */ destroy_tupledesc (parm->tuples); parm->tuples = NULL; if (parm->cmd == ENCFS_CMD_CREATE) { /* The encfs tool keeps on running after creation of the container. We don't want that and thus need to stop the encfs process. */ run_umount_helper (parm->mountpoint); /* In case the umount helper does not work we try to kill the engine. FIXME: We should figure out how to make fusermount work. */ runner_cancel (runner); } } return err; }
int main (int argc, char *argv[]) { int i = 1; int listmode = 0; const char *source_sym; const char *error_sym; gpg_error_t err; #ifndef GPG_ERR_INITIALIZED gpg_err_init (); #endif i18n_init (); if (argc == 1) { fprintf (stderr, _("Usage: %s GPG-ERROR [...]\n"), strrchr (argv[0],'/')? (strrchr (argv[0], '/')+1): argv[0]); exit (1); } else if (argc == 2 && !strcmp (argv[1], "--version")) { fputs ("gpg-error (" PACKAGE_NAME ") " PACKAGE_VERSION "\n", stdout); exit (0); } else if (argc == 2 && !strcmp (argv[1], "--list")) { listmode = 1; } if (listmode) { for (i=0; i < GPG_ERR_SOURCE_DIM; i++) { /* We use error code 1 because gpg_err_make requires a non-zero error code. */ err = gpg_err_make (i, 1); err -= 1; source_sym = gpg_strsource_sym (err); if (source_sym) printf ("%u = (%u, -) = (%s, -) = (%s, -)\n", err, gpg_err_source (err), source_sym, gpg_strsource (err)); } for (i=0; i < GPG_ERR_CODE_DIM; i++) { err = gpg_err_make (GPG_ERR_SOURCE_UNKNOWN, i); error_sym = gpg_strerror_sym (err); if (error_sym) printf ("%u = (-, %u) = (-, %s) = (-, %s)\n", err, gpg_err_code (err), error_sym, gpg_strerror (err)); } i = argc; /* Don't run the usual stuff. */ } while (i < argc) { if (get_err_from_number (argv[i], &err) || get_err_from_symbol (argv[i], &err) || get_err_from_str (argv[i], &err)) { source_sym = gpg_strsource_sym (err); error_sym = gpg_strerror_sym (err); printf ("%u = (%u, %u) = (%s, %s) = (%s, %s)\n", err, gpg_err_source (err), gpg_err_code (err), source_sym ? source_sym : "-", error_sym ? error_sym : "-", gpg_strsource (err), gpg_strerror (err)); } else fprintf (stderr, _("%s: warning: could not recognize %s\n"), argv[0], argv[i]); i++; } exit (0); }
int _keybox_dump_file (const char *filename, int stats_only, FILE *outfp) { FILE *fp; KEYBOXBLOB blob; int rc; unsigned long count = 0; struct file_stats_s stats; memset (&stats, 0, sizeof stats); if (!(fp = open_file (&filename, outfp))) return gpg_error_from_syserror (); for (;;) { rc = _keybox_read_blob (&blob, fp); if (gpg_err_code (rc) == GPG_ERR_TOO_LARGE && gpg_err_source (rc) == GPG_ERR_SOURCE_KEYBOX) { if (stats_only) stats.skipped_long_blobs++; else { fprintf (outfp, "BEGIN-RECORD: %lu\n", count ); fprintf (outfp, "# Record too large\nEND-RECORD\n"); } count++; continue; } if (rc) break; if (stats_only) { update_stats (blob, &stats); } else { fprintf (outfp, "BEGIN-RECORD: %lu\n", count ); _keybox_dump_blob (blob, outfp); fprintf (outfp, "END-RECORD\n"); } _keybox_release_blob (blob); count++; } if (rc == -1) rc = 0; if (rc) fprintf (outfp, "# error reading '%s': %s\n", filename, gpg_strerror (rc)); if (fp != stdin) fclose (fp); if (stats_only) { fprintf (outfp, "Total number of blobs: %8lu\n" " header: %8lu\n" " empty: %8lu\n" " openpgp: %8lu\n" " x509: %8lu\n" " non flagged: %8lu\n" " secret flagged: %8lu\n" " ephemeral flagged: %8lu\n", stats.total_blob_count, stats.header_blob_count, stats.empty_blob_count, stats.pgp_blob_count, stats.x509_blob_count, stats.non_flagged, stats.secret_flagged, stats.ephemeral_flagged); if (stats.skipped_long_blobs) fprintf (outfp, " skipped long blobs: %8lu\n", stats.skipped_long_blobs); if (stats.unknown_blob_count) fprintf (outfp, " unknown blob types: %8lu\n", stats.unknown_blob_count); if (stats.too_short_blobs) fprintf (outfp, " too short blobs: %8lu (error)\n", stats.too_short_blobs); if (stats.too_large_blobs) fprintf (outfp, " too large blobs: %8lu (error)\n", stats.too_large_blobs); } return rc; }
static gpgme_error_t map_assuan_error(gpg_error_t err) { if(!err) return 0; if(err == -1) return gpg_error(GPG_ERR_INV_ENGINE); /* New code will use gpg_error_t values. */ if(gpg_err_source(err)) return (gpgme_error_t) err; /* Legacy code will use old values. */ switch(err) { case ASSUAN_No_Error: return gpg_error(GPG_ERR_NO_ERROR); case ASSUAN_General_Error: return gpg_error(GPG_ERR_GENERAL); case ASSUAN_Out_Of_Core: return gpg_error(GPG_ERR_ENOMEM); case ASSUAN_Invalid_Value: return gpg_error(GPG_ERR_INV_VALUE); case ASSUAN_Timeout: return gpg_error(GPG_ERR_ETIMEDOUT); case ASSUAN_Read_Error: return gpg_error(GPG_ERR_GENERAL); case ASSUAN_Write_Error: return gpg_error(GPG_ERR_GENERAL); case ASSUAN_Problem_Starting_Server: case ASSUAN_Not_A_Server: case ASSUAN_Not_A_Client: case ASSUAN_Nested_Commands: case ASSUAN_No_Data_Callback: case ASSUAN_No_Inquire_Callback: case ASSUAN_Connect_Failed: case ASSUAN_Accept_Failed: case ASSUAN_Invalid_Command: case ASSUAN_Unknown_Command: case ASSUAN_Syntax_Error: case ASSUAN_Parameter_Error: case ASSUAN_Parameter_Conflict: case ASSUAN_No_Input: case ASSUAN_No_Output: case ASSUAN_No_Data_Available: case ASSUAN_Too_Much_Data: case ASSUAN_Inquire_Unknown: case ASSUAN_Inquire_Error: case ASSUAN_Invalid_Option: case ASSUAN_Unexpected_Status: case ASSUAN_Unexpected_Data: case ASSUAN_Invalid_Status: return gpg_error(GPG_ERR_ASSUAN); case ASSUAN_Invalid_Response: return gpg_error(GPG_ERR_INV_RESPONSE); case ASSUAN_Not_Implemented: return gpg_error(GPG_ERR_NOT_IMPLEMENTED); case ASSUAN_Line_Too_Long: return gpg_error(GPG_ERR_LINE_TOO_LONG); case ASSUAN_Line_Not_Terminated: return gpg_error(GPG_ERR_INCOMPLETE_LINE); case ASSUAN_Canceled: return gpg_error(GPG_ERR_CANCELED); case ASSUAN_Unsupported_Algorithm: return gpg_error(GPG_ERR_UNSUPPORTED_ALGORITHM); case ASSUAN_Server_Resource_Problem: return gpg_error(GPG_ERR_RESOURCE_LIMIT); case ASSUAN_Server_IO_Error: return gpg_error(GPG_ERR_GENERAL); case ASSUAN_Server_Bug: return gpg_error(GPG_ERR_BUG); case ASSUAN_Invalid_Data: return gpg_error(GPG_ERR_INV_DATA); case ASSUAN_Invalid_Index: return gpg_error(GPG_ERR_INV_INDEX); case ASSUAN_Not_Confirmed: return gpg_error(GPG_ERR_NOT_CONFIRMED); case ASSUAN_Bad_Certificate: return gpg_error(GPG_ERR_BAD_CERT); case ASSUAN_Bad_Certificate_Chain: return gpg_error(GPG_ERR_BAD_CERT_CHAIN); case ASSUAN_Missing_Certificate: return gpg_error(GPG_ERR_MISSING_CERT); case ASSUAN_Bad_Signature: return gpg_error(GPG_ERR_BAD_SIGNATURE); case ASSUAN_No_Agent: return gpg_error(GPG_ERR_NO_AGENT); case ASSUAN_Agent_Error: return gpg_error(GPG_ERR_AGENT); case ASSUAN_No_Public_Key: return gpg_error(GPG_ERR_NO_PUBKEY); case ASSUAN_No_Secret_Key: return gpg_error(GPG_ERR_NO_SECKEY); case ASSUAN_Invalid_Name: return gpg_error(GPG_ERR_INV_NAME); case ASSUAN_Cert_Revoked: return gpg_error(GPG_ERR_CERT_REVOKED); case ASSUAN_No_CRL_For_Cert: return gpg_error(GPG_ERR_NO_CRL_KNOWN); case ASSUAN_CRL_Too_Old: return gpg_error(GPG_ERR_CRL_TOO_OLD); case ASSUAN_Not_Trusted: return gpg_error(GPG_ERR_NOT_TRUSTED); case ASSUAN_Card_Error: return gpg_error(GPG_ERR_CARD); case ASSUAN_Invalid_Card: return gpg_error(GPG_ERR_INV_CARD); case ASSUAN_No_PKCS15_App: return gpg_error(GPG_ERR_NO_PKCS15_APP); case ASSUAN_Card_Not_Present: return gpg_error(GPG_ERR_CARD_NOT_PRESENT); case ASSUAN_Invalid_Id: return gpg_error(GPG_ERR_INV_ID); default: return gpg_error(GPG_ERR_GENERAL); } }
/* Handle one line of the encfs tool's output. This function is allowed to modify the content of BUFFER. */ static gpg_error_t handle_status_line (runner_t runner, const char *line, enum encfs_cmds cmd, tupledesc_t tuples) { gpg_error_t err; /* Check that encfs understands our new options. */ if (!strncmp (line, "$STATUS$", 8)) { for (line +=8; *line && spacep (line); line++) ; log_info ("got status '%s'\n", line); if (!strcmp (line, "fuse_main_start")) { /* Send a special error code back to let the caller know that everything has been setup by encfs. */ err = gpg_error (GPG_ERR_UNFINISHED); } else err = 0; } else if (!strncmp (line, "$PROMPT$", 8)) { for (line +=8; *line && spacep (line); line++) ; log_info ("got prompt '%s'\n", line); if (!strcmp (line, "create_root_dir")) err = send_cmd (runner, cmd == ENCFS_CMD_CREATE? "y":"n"); else if (!strcmp (line, "create_mount_point")) err = send_cmd (runner, "y"); else if (!strcmp (line, "passwd") || !strcmp (line, "new_passwd")) { if (tuples) { size_t n; const void *value; value = find_tuple (tuples, KEYBLOB_TAG_ENCKEY, &n); if (!value) err = gpg_error (GPG_ERR_INV_SESSION_KEY); else if ((err = send_cmd_bin (runner, value, n))) { if (gpg_err_code (err) == GPG_ERR_BUG && gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT) err = gpg_error (GPG_ERR_INV_SESSION_KEY); } } else err = gpg_error (GPG_ERR_NO_DATA); } else err = send_cmd (runner, ""); /* Default to send an empty line. */ } else if (strstr (line, "encfs: unrecognized option '")) err = gpg_error (GPG_ERR_INV_ENGINE); else err = 0; return err; }
/* Ask for the passphrase using the supplied arguments. The returned passphrase needs to be freed by the caller. */ int agent_get_passphrase (ctrl_t ctrl, char **retpass, const char *desc, const char *prompt, const char *errtext, int with_qualitybar) { int rc; char line[ASSUAN_LINELENGTH]; struct entry_parm_s parm; int saveflag; int close_button; *retpass = NULL; if (opt.batch) return gpg_error (GPG_ERR_BAD_PASSPHRASE); if (ctrl->pinentry_mode != PINENTRY_MODE_ASK) { if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL) return gpg_error (GPG_ERR_CANCELED); if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK) { size_t size; size_t len = ASSUAN_LINELENGTH/2; unsigned char *buffer = gcry_malloc_secure (len); rc = pinentry_loopback(ctrl, "PASSPHRASE", &buffer, &size, len); if (rc) xfree(buffer); else { buffer[size] = 0; *retpass = buffer; } return rc; } return gpg_error (GPG_ERR_NO_PIN_ENTRY); } rc = start_pinentry (ctrl); if (rc) return rc; if (!prompt) prompt = desc && strstr (desc, "PIN")? "PIN": _("Passphrase"); if (desc) snprintf (line, DIM(line)-1, "SETDESC %s", desc); else snprintf (line, DIM(line)-1, "RESET"); line[DIM(line)-1] = 0; rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return unlock_pinentry (rc); snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt); line[DIM(line)-1] = 0; rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return unlock_pinentry (rc); if (with_qualitybar && opt.min_passphrase_len) { rc = setup_qualitybar (); if (rc) return unlock_pinentry (rc); } if (errtext) { snprintf (line, DIM(line)-1, "SETERROR %s", errtext); line[DIM(line)-1] = 0; rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return unlock_pinentry (rc); } memset (&parm, 0, sizeof parm); parm.size = ASSUAN_LINELENGTH/2 - 5; parm.buffer = gcry_malloc_secure (parm.size+10); if (!parm.buffer) return unlock_pinentry (out_of_core ()); saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL); assuan_begin_confidential (entry_ctx); close_button = 0; rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, inq_quality, entry_ctx, close_button_status_cb, &close_button); assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag); /* Most pinentries out in the wild return the old Assuan error code for canceled which gets translated to an assuan Cancel error and not to the code for a user cancel. Fix this here. */ if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED) rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); /* Change error code in case the window close button was clicked to cancel the operation. */ if (close_button && gpg_err_code (rc) == GPG_ERR_CANCELED) rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED); if (rc) xfree (parm.buffer); else *retpass = parm.buffer; return unlock_pinentry (rc); }
/* Call the Entry and ask for the PIN. We do check for a valid PIN number here and repeat it as long as we have invalid formed numbers. */ int agent_askpin (ctrl_t ctrl, const char *desc_text, const char *prompt_text, const char *initial_errtext, struct pin_entry_info_s *pininfo) { int rc; char line[ASSUAN_LINELENGTH]; struct entry_parm_s parm; const char *errtext = NULL; int is_pin = 0; int saveflag; int close_button; if (opt.batch) return 0; /* fixme: we should return BAD PIN */ if (ctrl->pinentry_mode != PINENTRY_MODE_ASK) { if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL) return gpg_error (GPG_ERR_CANCELED); if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK) { unsigned char *passphrase; size_t size; *pininfo->pin = 0; /* Reset the PIN. */ rc = pinentry_loopback(ctrl, "PASSPHRASE", &passphrase, &size, pininfo->max_length); if (rc) return rc; memcpy(&pininfo->pin, passphrase, size); xfree(passphrase); pininfo->pin[size] = 0; if (pininfo->check_cb) { /* More checks by utilizing the optional callback. */ pininfo->cb_errtext = NULL; rc = pininfo->check_cb (pininfo); } return rc; } return gpg_error(GPG_ERR_NO_PIN_ENTRY); } if (!pininfo || pininfo->max_length < 1) return gpg_error (GPG_ERR_INV_VALUE); if (!desc_text && pininfo->min_digits) desc_text = _("Please enter your PIN, so that the secret key " "can be unlocked for this session"); else if (!desc_text) desc_text = _("Please enter your passphrase, so that the secret key " "can be unlocked for this session"); if (prompt_text) is_pin = !!strstr (prompt_text, "PIN"); else is_pin = desc_text && strstr (desc_text, "PIN"); rc = start_pinentry (ctrl); if (rc) return rc; snprintf (line, DIM(line)-1, "SETDESC %s", desc_text); line[DIM(line)-1] = 0; rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return unlock_pinentry (rc); snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt_text? prompt_text : is_pin? "PIN:" : "Passphrase:"); line[DIM(line)-1] = 0; rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return unlock_pinentry (rc); /* If a passphrase quality indicator has been requested and a minimum passphrase length has not been disabled, send the command to the pinentry. */ if (pininfo->with_qualitybar && opt.min_passphrase_len ) { rc = setup_qualitybar (); if (rc) return unlock_pinentry (rc); } if (initial_errtext) { snprintf (line, DIM(line)-1, "SETERROR %s", initial_errtext); line[DIM(line)-1] = 0; rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return unlock_pinentry (rc); } for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++) { memset (&parm, 0, sizeof parm); parm.size = pininfo->max_length; *pininfo->pin = 0; /* Reset the PIN. */ parm.buffer = (unsigned char*)pininfo->pin; if (errtext) { /* TRANSLATORS: The string is appended to an error message in the pinentry. The %s is the actual error message, the two %d give the current and maximum number of tries. */ snprintf (line, DIM(line)-1, _("SETERROR %s (try %d of %d)"), errtext, pininfo->failed_tries+1, pininfo->max_tries); line[DIM(line)-1] = 0; rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return unlock_pinentry (rc); errtext = NULL; } saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL); assuan_begin_confidential (entry_ctx); close_button = 0; rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, inq_quality, entry_ctx, close_button_status_cb, &close_button); assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag); /* Most pinentries out in the wild return the old Assuan error code for canceled which gets translated to an assuan Cancel error and not to the code for a user cancel. Fix this here. */ if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED) rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); /* Change error code in case the window close button was clicked to cancel the operation. */ if (close_button && gpg_err_code (rc) == GPG_ERR_CANCELED) rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED); if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA) errtext = is_pin? _("PIN too long") : _("Passphrase too long"); else if (rc) return unlock_pinentry (rc); if (!errtext && pininfo->min_digits) { /* do some basic checks on the entered PIN. */ if (!all_digitsp (pininfo->pin)) errtext = _("Invalid characters in PIN"); else if (pininfo->max_digits && strlen (pininfo->pin) > pininfo->max_digits) errtext = _("PIN too long"); else if (strlen (pininfo->pin) < pininfo->min_digits) errtext = _("PIN too short"); } if (!errtext && pininfo->check_cb) { /* More checks by utilizing the optional callback. */ pininfo->cb_errtext = NULL; rc = pininfo->check_cb (pininfo); if (rc == -1 && pininfo->cb_errtext) errtext = pininfo->cb_errtext; else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE || gpg_err_code (rc) == GPG_ERR_BAD_PIN) errtext = (is_pin? _("Bad PIN") : _("Bad Passphrase")); else if (rc) return unlock_pinentry (rc); } if (!errtext) return unlock_pinentry (0); /* okay, got a PIN or passphrase */ } return unlock_pinentry (gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN : GPG_ERR_BAD_PASSPHRASE)); }
/* Ask for a passphrase via gpg-agent. On success the caller needs to free the string stored at R_PASSPHRASE. On error NULL will be stored at R_PASSPHRASE and an appropriate gpg error code is returned. With REPEAT set to 1, gpg-agent will ask the user to repeat the just entered passphrase. CACHE_ID is a gpg-agent style passphrase cache id or NULL. ERR_MSG is a error message to be presented to the user (e.g. "bad passphrase - try again") or NULL. PROMPT is the prompt string to label the entry box, it may be NULL for a default one. DESC_MSG is a longer description to be displayed above the entry box, if may be NULL for a default one. If USE_SECMEM is true, the returned passphrase is retruned in secure memory. The length of all these strings is limited; they need to fit in their encoded form into a standard Assuan line (i.e less then about 950 characters). All strings shall be UTF-8. */ gpg_error_t gnupg_get_passphrase (const char *cache_id, const char *err_msg, const char *prompt, const char *desc_msg, int repeat, int check_quality, int use_secmem, char **r_passphrase) { gpg_error_t err; char line[ASSUAN_LINELENGTH]; const char *arg1 = NULL; char *arg2 = NULL; char *arg3 = NULL; char *arg4 = NULL; membuf_t data; *r_passphrase = NULL; err = start_agent (); if (err) return err; /* Check that the gpg-agent understands the repeat option. */ if (assuan_transact (agent_ctx, "GETINFO cmd_has_option GET_PASSPHRASE repeat", NULL, NULL, NULL, NULL, NULL, NULL)) return gpg_error (GPG_ERR_NOT_SUPPORTED); arg1 = cache_id && *cache_id? cache_id:NULL; if (err_msg && *err_msg) if (!(arg2 = percent_plus_escape (err_msg))) goto no_mem; if (prompt && *prompt) if (!(arg3 = percent_plus_escape (prompt))) goto no_mem; if (desc_msg && *desc_msg) if (!(arg4 = percent_plus_escape (desc_msg))) goto no_mem; snprintf (line, DIM(line)-1, "GET_PASSPHRASE --data %s--repeat=%d -- %s %s %s %s", check_quality? "--check ":"", repeat, arg1? arg1:"X", arg2? arg2:"X", arg3? arg3:"X", arg4? arg4:"X"); line[DIM(line)-1] = 0; xfree (arg2); xfree (arg3); xfree (arg4); if (use_secmem) init_membuf_secure (&data, 64); else init_membuf (&data, 64); err = assuan_transact (agent_ctx, line, membuf_data_cb, &data, default_inq_cb, NULL, NULL, NULL); /* Older Pinentries return the old assuan error code for canceled which gets translated bt libassuan to GPG_ERR_ASS_CANCELED and not to the code for a user cancel. Fix this here. */ if (err && gpg_err_source (err) && gpg_err_code (err) == GPG_ERR_ASS_CANCELED) err = gpg_err_make (gpg_err_source (err), GPG_ERR_CANCELED); if (err) { void *p; size_t n; p = get_membuf (&data, &n); if (p) wipememory (p, n); xfree (p); } else { put_membuf (&data, "", 1); *r_passphrase = get_membuf (&data, NULL); if (!*r_passphrase) err = gpg_error_from_syserror (); } return err; no_mem: err = gpg_error_from_syserror (); xfree (arg2); xfree (arg3); xfree (arg4); return err; }
/* Pop up the PIN-entry, display the text and the prompt and ask the user to confirm this. We return 0 for success, ie. the user confirmed it, GPG_ERR_NOT_CONFIRMED for what the text says or an other error. If WITH_CANCEL it true an extra cancel button is displayed to allow the user to easily return a GPG_ERR_CANCELED. if the Pinentry does not support this, the user can still cancel by closing the Pinentry window. */ int agent_get_confirmation (ctrl_t ctrl, const char *desc, const char *ok, const char *notok, int with_cancel) { int rc; char line[ASSUAN_LINELENGTH]; if (ctrl->pinentry_mode != PINENTRY_MODE_ASK) { if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL) return gpg_error (GPG_ERR_CANCELED); return gpg_error (GPG_ERR_NO_PIN_ENTRY); } rc = start_pinentry (ctrl); if (rc) return rc; if (desc) snprintf (line, DIM(line)-1, "SETDESC %s", desc); else snprintf (line, DIM(line)-1, "RESET"); line[DIM(line)-1] = 0; rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); /* Most pinentries out in the wild return the old Assuan error code for canceled which gets translated to an assuan Cancel error and not to the code for a user cancel. Fix this here. */ if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED) rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); if (rc) return unlock_pinentry (rc); if (ok) { snprintf (line, DIM(line)-1, "SETOK %s", ok); line[DIM(line)-1] = 0; rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return unlock_pinentry (rc); } if (notok) { /* Try to use the newer NOTOK feature if a cancel button is requested. If no cancel button is requested we keep on using the standard cancel. */ if (with_cancel) { snprintf (line, DIM(line)-1, "SETNOTOK %s", notok); line[DIM(line)-1] = 0; rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); } else rc = GPG_ERR_ASS_UNKNOWN_CMD; if (gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD) { snprintf (line, DIM(line)-1, "SETCANCEL %s", notok); line[DIM(line)-1] = 0; rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); } if (rc) return unlock_pinentry (rc); } rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL); if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED) rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); return unlock_pinentry (rc); }
/* Return a pointer to a string containing a description of the error source in the error value ERR. */ const char * gpg_strsource (gpg_error_t err) { gpg_err_source_t source = gpg_err_source (err); return dgettext (PACKAGE, msgstr + msgidx[msgidxof (source)]); }
/* Ask for the passphrase using the supplied arguments. The returned passphrase needs to be freed by the caller. */ int agent_get_passphrase (ctrl_t ctrl, char **retpass, const char *desc, const char *prompt, const char *errtext, int with_qualitybar) { int rc; char line[ASSUAN_LINELENGTH]; struct entry_parm_s parm; int saveflag; *retpass = NULL; if (opt.batch) return gpg_error (GPG_ERR_BAD_PASSPHRASE); rc = start_pinentry (ctrl); if (rc) return rc; if (!prompt) prompt = desc && strstr (desc, "PIN")? "PIN": _("Passphrase"); if (desc) snprintf (line, DIM(line)-1, "SETDESC %s", desc); else snprintf (line, DIM(line)-1, "RESET"); line[DIM(line)-1] = 0; rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return unlock_pinentry (rc); snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt); line[DIM(line)-1] = 0; rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return unlock_pinentry (rc); if (with_qualitybar && opt.min_passphrase_len) { rc = setup_qualitybar (); if (rc) return unlock_pinentry (rc); } if (errtext) { snprintf (line, DIM(line)-1, "SETERROR %s", errtext); line[DIM(line)-1] = 0; rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return unlock_pinentry (rc); } memset (&parm, 0, sizeof parm); parm.size = ASSUAN_LINELENGTH/2 - 5; parm.buffer = gcry_malloc_secure (parm.size+10); if (!parm.buffer) return unlock_pinentry (out_of_core ()); saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL); assuan_begin_confidential (entry_ctx); rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, inq_quality, entry_ctx, NULL, NULL); assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag); /* Most pinentries out in the wild return the old Assuan error code for canceled which gets translated to an assuan Cancel error and not to the code for a user cancel. Fix this here. */ if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED) rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); if (rc) xfree (parm.buffer); else *retpass = parm.buffer; return unlock_pinentry (rc); }
int main (int argc, char *argv[]) { int i = 1; int listmode = 0; const char *source_sym; const char *error_sym; gpg_error_t err; gpgrt_init (); i18n_init (); if (argc == 1) { fprintf (stderr, _("Usage: %s GPG-ERROR [...]\n"), strrchr (argv[0],'/')? (strrchr (argv[0], '/')+1): argv[0]); exit (1); } else if (argc == 2 && !strcmp (argv[1], "--version")) { fputs ("gpg-error (" PACKAGE_NAME ") " PACKAGE_VERSION "\n", stdout); exit (0); } else if (argc == 2 && !strcmp (argv[1], "--help")) { fputs ("gpg-error (" PACKAGE_NAME ") " PACKAGE_VERSION "\n", stdout); fputs ("Options:\n" " --version Print version\n" " --lib-version Print library version\n" " --help Print this help\n" " --list Print all error codes\n" " --defines Print all error codes as #define lines\n" , stdout); exit (0); } else if (argc == 2 && !strcmp (argv[1], "--lib-version")) { printf ("Version from header: %s (0x%06x)\n", GPG_ERROR_VERSION, GPG_ERROR_VERSION_NUMBER); printf ("Version from binary: %s\n", gpg_error_check_version (NULL)); printf ("Copyright blurb ...:%s\n", gpg_error_check_version ("\x01\x01")); exit (0); } else if (argc == 2 && !strcmp (argv[1], "--list")) { listmode = 1; } else if (argc == 2 && !strcmp (argv[1], "--defines")) { listmode = 2; } if (listmode == 1) { for (i=0; i < GPG_ERR_SOURCE_DIM; i++) { /* We use error code 1 because gpg_err_make requires a non-zero error code. */ err = gpg_err_make (i, 1); err -= 1; source_sym = gpg_strsource_sym (err); if (source_sym) printf ("%u = (%u, -) = (%s, -) = (%s, -)\n", err, gpg_err_source (err), source_sym, gpg_strsource (err)); } for (i=0; i < GPG_ERR_CODE_DIM; i++) { err = gpg_err_make (GPG_ERR_SOURCE_UNKNOWN, i); error_sym = gpg_strerror_sym (err); if (error_sym) printf ("%u = (-, %u) = (-, %s) = (-, %s)\n", err, gpg_err_code (err), error_sym, gpg_strerror (err)); } } else if (listmode == 2) { int n, nmax; for (i=0, nmax=0; i < GPG_ERR_SOURCE_DIM; i++) { err = gpg_err_make (i, 1); source_sym = gpg_strsource_sym (err); if (source_sym) { n = strlen (source_sym); if (n > nmax) nmax = n; } } for (i=0; i < GPG_ERR_SOURCE_DIM; i++) { err = gpg_err_make (i, 1); source_sym = gpg_strsource_sym (err); if (source_sym) printf ("#define %-*s %3u\n", nmax,source_sym,gpg_err_source (err)); } for (i=0, nmax = 0; i < GPG_ERR_CODE_DIM; i++) { err = gpg_err_make (GPG_ERR_SOURCE_UNKNOWN, i); error_sym = gpg_strerror_sym (err); if (error_sym) { n = strlen (error_sym); if (n > nmax) nmax = n; } } for (i=0; i < GPG_ERR_CODE_DIM; i++) { err = gpg_err_make (GPG_ERR_SOURCE_UNKNOWN, i); error_sym = gpg_strerror_sym (err); if (error_sym) printf ("#define %-*s %5u\n", nmax, error_sym, gpg_err_code (err)); } } else /* Standard mode. */ { while (i < argc) { if (get_err_from_number (argv[i], &err) || get_err_from_symbol (argv[i], &err) || get_err_from_str (argv[i], &err)) { source_sym = gpg_strsource_sym (err); error_sym = gpg_strerror_sym (err); printf ("%u = (%u, %u) = (%s, %s) = (%s, %s)\n", err, gpg_err_source (err), gpg_err_code (err), source_sym ? source_sym : "-", error_sym ? error_sym:"-", gpg_strsource (err), gpg_strerror (err)); } else fprintf (stderr, _("%s: warning: could not recognize %s\n"), argv[0], argv[i]); i++; } } exit (0); }
/* This function is called to trigger a card-reload. */ static void card_reload (GpaCardManager *cardman) { gpg_error_t err, operr; const char *application; char *command_buf = NULL; const char *command; const char *err_desc = NULL; char *err_desc_buffer = NULL; int auto_app; if (!cardman->gpgagent) return; /* No support for GPGME_PROTOCOL_ASSUAN. */ /* Start the ticker if not yet done. */ start_ticker (cardman); if (!cardman->in_card_reload) { cardman->in_card_reload++; update_info_visibility (cardman); cardman->cardtype = G_TYPE_NONE; cardman->cardtypename = "Unknown"; /* The first thing we need to do is to issue the SERIALNO command; this makes sure that scdaemon initalizes the card if that has not yet been done. */ command = "SCD SERIALNO"; if (cardman->app_selector && (gtk_combo_box_get_active (GTK_COMBO_BOX (cardman->app_selector)) > 0) && (application = gtk_combo_box_get_active_text (GTK_COMBO_BOX (cardman->app_selector)))) { command_buf = g_strdup_printf ("%s %s", command, application); command = command_buf; auto_app = 0; } else auto_app = 1; err = gpgme_op_assuan_transact_ext (cardman->gpgagent, command, scd_data_cb, NULL, scd_inq_cb, NULL, scd_status_cb, cardman, &operr); if (!err) { err = operr; if (!auto_app && gpg_err_source (err) == GPG_ERR_SOURCE_SCD && gpg_err_code (err) == GPG_ERR_CONFLICT) { /* Not in auto select mode and the scdaemon told us about a conflicting use. We now do a restart and try again to display an application selection conflict error only if it is not due to our own connection to the scdaemon. */ if (!gpgme_op_assuan_transact_ext (cardman->gpgagent, "SCD RESTART", NULL, NULL, NULL, NULL, NULL, NULL, &operr) && !operr) { err = gpgme_op_assuan_transact_ext (cardman->gpgagent, command, scd_data_cb, NULL, scd_inq_cb, NULL, scd_status_cb, cardman, &operr); if (!err) err = operr; } } } if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT || gpg_err_code (err) == GPG_ERR_CARD_REMOVED) { err_desc = _("No card found."); } else if (gpg_err_source (err) == GPG_ERR_SOURCE_SCD && gpg_err_code (err) == GPG_ERR_CONFLICT) { err_desc = auto_app ? _("The selected card application is currently not available.") : _("Another process is using a different card application " "than the selected one.\n\n" "You may change the application selection mode to " "\"Auto\" to select the active application."); } else if (!auto_app && gpg_err_source (err) == GPG_ERR_SOURCE_SCD && gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED) { err_desc = _("The selected card application is not available."); } else if (err) { g_debug ("assuan command `%s' failed: %s <%s>\n", command, gpg_strerror (err), gpg_strsource (err)); if (!gpgme_op_assuan_transact_ext (cardman->gpgagent, "SCD SERIALNO undefined", NULL, NULL, NULL, NULL, NULL, NULL, &operr) && !operr) err = 0; else { err_desc = _("Error accessing the card."); statusbar_update (cardman, _("Error accessing card")); } } g_free (command_buf); if (!err) { /* Get the event counter to avoid a duplicate reload due to the ticker. */ gpgme_op_assuan_transact_ext (cardman->gpgagent, "GETEVENTCOUNTER", NULL, NULL, NULL, NULL, scd_status_cb, cardman, NULL); /* Now we need to get the APPTYPE of the card so that the correct GpaCM* object can can act on the data. */ command = "SCD GETATTR APPTYPE"; err = gpgme_op_assuan_transact_ext (cardman->gpgagent, command, scd_data_cb, NULL, scd_inq_cb, NULL, scd_status_cb, cardman, &operr); if (!err) err = operr; if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT || gpg_err_code (err) == GPG_ERR_CARD_REMOVED) statusbar_update (cardman, _("No card")); else if (err) { g_debug ("assuan command `%s' failed: %s <%s>\n", command, gpg_strerror (err), gpg_strsource (err)); statusbar_update (cardman, _("Error accessing card")); } } update_card_widget (cardman, err_desc); g_free (err_desc_buffer); err_desc_buffer = NULL; err_desc = NULL; update_title (cardman); update_info_visibility (cardman); /* We decrement our lock using a idle handler with lo priority. This gives us a better chance not to do a reload a second time on behalf of the file watcher or ticker. */ g_object_ref (cardman); g_idle_add_full (G_PRIORITY_LOW, card_reload_finish_idle_cb, cardman, NULL); } }
QByteArray GPGME::decryptFile(const QString & filename, QString & keyId, QWidget * parent) { setError(GPG_ERR_NO_ERROR); // clear error CallbackData cbData; cbData.parent = parent; qDebug() << "ERERR" << gpg_err_source(GPG_ERR_CODE_DIM+1); gpgme_set_passphrase_cb(p->context, passphraseCallback, &cbData); qDebug() << "decrypting file" << filename; gpgme_data_t data; gpgme_error_t err; QFile file(filename); if (!file.exists()) { setError(GPGME_WRAPPER_ERR_FILE_NOT_FOUND, true); return QByteArray(); } if (!file.open(QIODevice::ReadOnly)) { setError(GPGME_WRAPPER_ERR_CANNOT_OPEN_FILE, true); return QByteArray(); } if (file.size() > FILESIZE_HARD_LIMIT) { setError(GPGME_WRAPPER_ERR_FILE_TOO_LARGE, true); return QByteArray(); } err = gpgme_data_new_from_fd(&data, file.handle()); if (err != GPG_ERR_NO_ERROR) { setError(err); return QByteArray(); } // process data (it's cipher) gpgme_data_t plain; gpgme_data_new(&plain); err = gpgme_op_decrypt(p->context, data, plain); // unset passphrase callback gpgme_set_passphrase_cb(p->context, 0, 0); if (err != GPG_ERR_NO_ERROR) { gpgme_data_release(data); gpgme_data_release(plain); setError(err); return QByteArray(); } // decryption is successful so load plain data QByteArray resBytes; const int bufSize = 1000; int read; char buf[bufSize]; gpgme_data_seek(plain, 0, SEEK_SET); while (true) { read = gpgme_data_read(plain, (void*)buf, bufSize); if (read == 0) { break; } if (read == -1) { // error, ignore for now break; } resBytes.append(buf, read); } gpgme_decrypt_result_t decrypt_res = gpgme_op_decrypt_result(p->context); gpgme_recipient_t recipient; if (decrypt_res) { recipient = decrypt_res->recipients; while (recipient) { keyId = recipient->keyid; recipient = recipient->next; break; // just ignore the other recipients } } return resBytes; }