/* Lock the reader SLOT. This function shall be used right before calling any of the actual application functions to serialize access to the reader. We do this always even if the reader is not actually used. This allows an actual connection to assume that it never shares a reader (while performing one command). Returns 0 on success; only then the unlock_reader function must be called after returning from the handler. */ static gpg_error_t lock_reader (int slot, ctrl_t ctrl) { int res; if (slot < 0 || slot >= DIM (lock_table)) return gpg_error (slot<0? GPG_ERR_INV_VALUE : GPG_ERR_RESOURCE_LIMIT); if (!lock_table[slot].initialized) { res = npth_mutex_init (&lock_table[slot].lock, NULL); if (res) { log_error ("error initializing mutex: %s\n", strerror (res)); return gpg_error_from_errno (res); } lock_table[slot].initialized = 1; lock_table[slot].app = NULL; lock_table[slot].last_app = NULL; } res = npth_mutex_lock (&lock_table[slot].lock); if (res) { log_error ("failed to acquire APP lock for slot %d: %s\n", slot, strerror (res)); return gpg_error_from_errno (res); } apdu_set_progress_cb (slot, print_progress_line, ctrl); return 0; }
static gpgme_error_t gpgsm_keylist(void *engine, const char *pattern, int secret_only, gpgme_keylist_mode_t mode) { engine_gpgsm_t gpgsm = engine; char *line; gpgme_error_t err; int list_mode = 0; if(mode & GPGME_KEYLIST_MODE_LOCAL) list_mode |= 1; if(mode & GPGME_KEYLIST_MODE_EXTERN) list_mode |= 2; if(!pattern) pattern = ""; /* Always send list-mode option because RESET does not reset it. */ if(asprintf(&line, "OPTION list-mode=%d", (list_mode & 3)) < 0) return gpg_error_from_errno(errno); err = gpgsm_assuan_simple_command(gpgsm->assuan_ctx, line, NULL, NULL); free(line); if(err) return err; /* Always send key validation because RESET does not reset it. */ /* Use the validation mode if required. We don't check for an error yet because this is a pretty fresh gpgsm features. */ gpgsm_assuan_simple_command(gpgsm->assuan_ctx, (mode & GPGME_KEYLIST_MODE_VALIDATE) ? "OPTION with-validation=1" : "OPTION with-validation=0" , NULL, NULL); /* Length is "LISTSECRETKEYS " + p + '\0'. */ line = malloc(15 + strlen(pattern) + 1); if(!line) return gpg_error_from_errno(errno); if(secret_only) { strcpy(line, "LISTSECRETKEYS "); strcpy(&line[15], pattern); } else { strcpy(line, "LISTKEYS "); strcpy(&line[9], pattern); } gpgsm_clear_fd(gpgsm, INPUT_FD); gpgsm_clear_fd(gpgsm, OUTPUT_FD); gpgsm_clear_fd(gpgsm, MESSAGE_FD); err = start(gpgsm, line); free(line); return err; }
gpgme_error_t _gpgme_data_inbound_handler(void *opaque, int fd) { gpgme_data_t dh = (gpgme_data_t) opaque; char buffer[BUFFER_SIZE]; char *bufp = buffer; ssize_t buflen; buflen = _gpgme_io_read(fd, buffer, BUFFER_SIZE); if(buflen < 0) return gpg_error_from_errno(errno); if(buflen == 0) { _gpgme_io_close(fd); return 0; } do { ssize_t amt = gpgme_data_write(dh, bufp, buflen); if(amt == 0 || (amt < 0 && errno != EINTR)) return gpg_error_from_errno(errno); bufp += amt; buflen -= amt; } while(buflen > 0); return 0; }
/* Create a LDAP URL from DN and FILTER and return it in URL. We don't need the host and port because this will be specified using the override options. */ static gpg_error_t make_url (char **url, const char *dn, const char *filter) { gpg_error_t err; char *u_dn, *u_filter; char const attrs[] = (USERCERTIFICATE "," /* USERSMIMECERTIFICATE "," */ CACERTIFICATE "," X509CACERT ); *url = NULL; u_dn = escape4url (dn); if (!u_dn) return gpg_error_from_errno (errno); u_filter = escape4url (filter); if (!u_filter) { err = gpg_error_from_errno (errno); xfree (u_dn); return err; } *url = strconcat ("ldap:///", u_dn, "?", attrs, "?sub?", u_filter, NULL); if (!*url) err = gpg_error_from_syserror (); else err = 0; xfree (u_dn); xfree (u_filter); return err; }
static gpgme_error_t set_recipients(engine_gpgsm_t gpgsm, gpgme_key_t recp[]) { gpgme_error_t err = 0; assuan_context_t ctx = gpgsm->assuan_ctx; char *line; int linelen; int invalid_recipients = 0; int i = 0; linelen = 10 + 40 + 1; /* "RECIPIENT " + guess + '\0'. */ line = malloc(10 + 40 + 1); if(!line) return gpg_error_from_errno(errno); strcpy(line, "RECIPIENT "); while(!err && recp[i]) { char *fpr; int newlen; if(!recp[i]->subkeys || !recp[i]->subkeys->fpr) { invalid_recipients++; continue; } fpr = recp[i]->subkeys->fpr; newlen = 11 + strlen(fpr); if(linelen < newlen) { char *newline = realloc(line, newlen); if(! newline) { int saved_errno = errno; free(line); return gpg_error_from_errno(saved_errno); } line = newline; linelen = newlen; } strcpy(&line[10], fpr); err = gpgsm_assuan_simple_command(ctx, line, gpgsm->status.fnc, gpgsm->status.fnc_value); /* FIXME: This requires more work. */ if(gpg_err_code(err) == GPG_ERR_NO_PUBKEY) invalid_recipients++; else if(err) { free(line); return err; } i++; } free(line); return gpg_error(invalid_recipients ? GPG_ERR_UNUSABLE_PUBKEY : GPG_ERR_NO_ERROR); }
static gpgme_error_t set_recipients (engine_uiserver_t uiserver, gpgme_key_t recp[]) { gpgme_error_t err = 0; assuan_context_t ctx = uiserver->assuan_ctx; char *line; int linelen; int invalid_recipients = 0; int i; linelen = 10 + 40 + 1; /* "RECIPIENT " + guess + '\0'. */ line = malloc (10 + 40 + 1); if (!line) return gpg_error_from_errno (errno); strcpy (line, "RECIPIENT "); for (i=0; !err && recp[i]; i++) { char *uid; int newlen; /* We use only the first user ID of the key. */ if (!recp[i]->uids || !(uid=recp[i]->uids->uid) || !*uid) { invalid_recipients++; continue; } newlen = 11 + strlen (uid); if (linelen < newlen) { char *newline = realloc (line, newlen); if (! newline) { int saved_errno = errno; free (line); return gpg_error_from_errno (saved_errno); } line = newline; linelen = newlen; } /* FIXME: need to do proper escaping */ strcpy (&line[10], uid); err = uiserver_assuan_simple_command (ctx, line, uiserver->status.fnc, uiserver->status.fnc_value); /* FIXME: This might requires more work. */ if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY) invalid_recipients++; else if (err) { free (line); return err; } } free (line); return gpg_error (invalid_recipients ? GPG_ERR_UNUSABLE_PUBKEY : GPG_ERR_NO_ERROR); }
/* Pop up a message window similar to the confirm one but keep it open until agent_popup_message_stop has been called. It is crucial for the caller to make sure that the stop function gets called as soon as the message is not anymore required because the message is system modal and all other attempts to use the pinentry will fail (after a timeout). */ int agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn) { int rc; char line[ASSUAN_LINELENGTH]; npth_attr_t tattr; int err; 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); 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); } err = npth_attr_init (&tattr); if (err) return unlock_pinentry (gpg_error_from_errno (err)); npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE); popup_finished = 0; err = npth_create (&popup_tid, &tattr, popup_message_thread, NULL); npth_attr_destroy (&tattr); if (err) { rc = gpg_error_from_errno (err); log_error ("error spawning popup message handler: %s\n", strerror (err) ); return unlock_pinentry (rc); } npth_setname_np (popup_tid, "popup-message"); return 0; }
/* Register the file descriptor FD with the handler FNC (which gets FNC_DATA as its first argument) for the direction DIR. DATA should be the context for which the fd is added. R_TAG will hold the tag that can be used to remove the fd. */ gpgme_error_t _gpgme_add_io_cb (void *data, int fd, int dir, gpgme_io_cb_t fnc, void *fnc_data, void **r_tag) { gpgme_error_t err; gpgme_ctx_t ctx = (gpgme_ctx_t) data; fd_table_t fdt; struct wait_item_s *item; struct tag *tag; assert (fnc); assert (ctx); fdt = &ctx->fdt; assert (fdt); tag = malloc (sizeof *tag); if (!tag) return gpg_error_from_errno (errno); tag->ctx = ctx; /* Allocate a structure to hold information about the handler. */ item = calloc (1, sizeof *item); if (!item) { int saved_errno = errno; free (tag); return gpg_error_from_errno (saved_errno); } item->ctx = ctx; item->dir = dir; item->handler = fnc; item->handler_value = fnc_data; err = fd_table_put (fdt, fd, dir, item, &tag->idx); if (err) { free (tag); free (item); return err; } TRACE3 (DEBUG_CTX, "_gpgme_add_io_cb", ctx, "fd %d, dir=%d -> tag=%p", fd, dir, tag); *r_tag = tag; return 0; }
static gpgme_error_t gpgsm_export(void *engine, const char *pattern, unsigned int reserved, gpgme_data_t keydata, int use_armor) { engine_gpgsm_t gpgsm = engine; gpgme_error_t err = 0; char *cmd; if(!gpgsm || reserved) return gpg_error(GPG_ERR_INV_VALUE); if(!pattern) pattern = ""; cmd = malloc(7 + strlen(pattern) + 1); if(!cmd) return gpg_error_from_errno(errno); strcpy(cmd, "EXPORT "); strcpy(&cmd[7], pattern); gpgsm->output_cb.data = keydata; err = gpgsm_set_fd(gpgsm, OUTPUT_FD, use_armor ? "--armor" : 0); if(err) return err; gpgsm_clear_fd(gpgsm, INPUT_FD); gpgsm_clear_fd(gpgsm, MESSAGE_FD); err = start(gpgsm, cmd); free(cmd); return err; }
/* Generic function to add an extension to a certificate request. The extension must be provided readily encoded in the buffer DER of length DERLEN bytes; the OID is to be given in OID and IS_CRIT should be set to true if that extension shall be marked critical. */ gpg_error_t ksba_certreq_add_extension (ksba_certreq_t cr, const char *oid, int is_crit, const void *der, size_t derlen) { size_t oidlen; struct extn_list_s *e; if (!cr || !oid|| !*oid || !der || !derlen) return gpg_error (GPG_ERR_INV_VALUE); oidlen = strlen (oid); e = xtrymalloc (sizeof *e + derlen + oidlen); if (!e) return gpg_error_from_errno (errno); e->critical = is_crit; e->derlen = derlen; memcpy (e->der, der, derlen); strcpy (e->der+derlen, oid); e->oid = e->der + derlen; e->next = cr->extn_list; cr->extn_list = e; return 0; }
static gpgme_error_t gpgconf_new (void **engine, const char *file_name, const char *home_dir) { gpgme_error_t err = 0; engine_gpgconf_t gpgconf; gpgconf = calloc (1, sizeof *gpgconf); if (!gpgconf) return gpg_error_from_errno (errno); gpgconf->file_name = strdup (file_name ? file_name : _gpgme_get_gpgconf_path ()); if (!gpgconf->file_name) err = gpg_error_from_syserror (); if (!err && home_dir) { gpgconf->home_dir = strdup (home_dir); if (!gpgconf->home_dir) err = gpg_error_from_syserror (); } if (err) gpgconf_release (gpgconf); else *engine = gpgconf; return err; }
/* Add KEY to list of signers in CTX. */ gpgme_error_t gpgme_signers_add (gpgme_ctx_t ctx, const gpgme_key_t key) { TRACE_BEG2 (DEBUG_CTX, "gpgme_signers_add", ctx, "key=%p (%s)", key, (key->subkeys && key->subkeys->fpr) ? key->subkeys->fpr : "invalid"); if (!ctx || !key) return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); if (ctx->signers_len == ctx->signers_size) { gpgme_key_t *newarr; int n = ctx->signers_size + 5; int j; newarr = realloc (ctx->signers, n * sizeof (*newarr)); if (!newarr) return TRACE_ERR (gpg_error_from_errno (errno)); for (j = ctx->signers_size; j < n; j++) newarr[j] = NULL; ctx->signers = newarr; ctx->signers_size = n; } gpgme_key_ref (key); ctx->signers[ctx->signers_len++] = key; return TRACE_SUC (); }
/* Clear the error and eof indicators for READER, so that it can be continued to use. Also dicards any unread bytes. This is usually required if the upper layer want to send to send an EOF to indicate the logical end of one part of a file. If BUFFER and BUFLEN are not NULL, possible unread data is copied to a newly allocated buffer and this buffer is assigned to BUFFER, BUFLEN will be set to the length of the unread bytes. */ gpg_error_t ksba_reader_clear (ksba_reader_t r, unsigned char **buffer, size_t *buflen) { size_t n; if (!r) return gpg_error (GPG_ERR_INV_VALUE); r->eof = 0; r->error = 0; r->nread = 0; n = r->unread.length; r->unread.length = 0; if (buffer && buflen) { *buffer = NULL; *buflen = 0; if (n) { *buffer = xtrymalloc (n); if (!*buffer) return gpg_error_from_errno (errno); memcpy (*buffer, r->unread.buf, n); *buflen = n; } } return 0; }
/* XXX We should keep a marker and roll over for speed. */ static gpgme_error_t fd_table_put(fd_table_t fdt, int fd, int dir, void *opaque, int *idx) { unsigned int i, j; struct io_select_fd_s *new_fds; for(i = 0; i < fdt->size; i++) { if(fdt->fds[i].fd == -1) break; } if(i == fdt->size) { #define FDT_ALLOCSIZE 10 new_fds = realloc(fdt->fds, (fdt->size + FDT_ALLOCSIZE) * sizeof(*new_fds)); if(!new_fds) return gpg_error_from_errno(errno); fdt->fds = new_fds; fdt->size += FDT_ALLOCSIZE; for(j = 0; j < FDT_ALLOCSIZE; j++) fdt->fds[i + j].fd = -1; } fdt->fds[i].fd = fd; fdt->fds[i].for_read = (dir == 1); fdt->fds[i].for_write = (dir == 0); fdt->fds[i].frozen = 0; fdt->fds[i].signaled = 0; fdt->fds[i].opaque = opaque; *idx = i; return 0; }
static gpgme_error_t prepare_new_sig (op_data_t opd) { gpgme_signature_t sig; if (opd->only_newsig_seen && opd->current_sig) { /* We have only seen the NEWSIG status and nothing else - we better skip this signature therefore and reuse it for the next possible signature. */ sig = opd->current_sig; memset (sig, 0, sizeof *sig); assert (opd->result.signatures == sig); } else { sig = calloc (1, sizeof (*sig)); if (!sig) return gpg_error_from_errno (errno); if (!opd->result.signatures) opd->result.signatures = sig; if (opd->current_sig) opd->current_sig->next = sig; opd->current_sig = sig; } opd->did_prepare_new_sig = 1; opd->only_newsig_seen = 0; return 0; }
gpgme_error_t _gpgme_op_data_lookup (gpgme_ctx_t ctx, ctx_op_data_id_t type, void **hook, int size, void (*cleanup) (void *)) { struct ctx_op_data *data = ctx->op_data; while (data && data->type != type) data = data->next; if (!data) { if (size < 0) { *hook = NULL; return 0; } data = calloc (1, sizeof (struct ctx_op_data) + size); if (!data) return gpg_error_from_errno (errno); data->next = ctx->op_data; data->type = type; data->cleanup = cleanup; data->hook = (void *) (((char *) data) + sizeof (struct ctx_op_data)); ctx->op_data = data; } *hook = data->hook; return 0; }
/** * ksba_reader_new: * * Create a new but uninitialized ksba_reader_t Object. Using this * reader object in unitialized state does always yield eof. * * Return value: ksba_reader_t object or an error code. **/ gpg_error_t ksba_reader_new (ksba_reader_t *r_r) { *r_r = xtrycalloc (1, sizeof **r_r); if (!*r_r) return gpg_error_from_errno (errno); return 0; }
/** * ksba_cms_new: * * Create a new and empty CMS object * * Return value: A CMS object or an error code. **/ gpg_error_t ksba_certreq_new (ksba_certreq_t *r_cr) { *r_cr = xtrycalloc (1, sizeof **r_cr); if (!*r_cr) return gpg_error_from_errno (errno); return 0; }
/* This handler is used to parse the output of --list-trust-path: Format: level:keyid:type:recno:ot:val:mc:cc:name: With TYPE = U for a user ID K for a key The RECNO is either the one of the dir record or the one of the uid record. OT is the the usual trust letter and only availabel on K lines. VAL is the calcualted validity MC is the marginal trust counter and only available on U lines CC is the same for the complete count NAME ist the username and only printed on U lines. */ static gpgme_error_t trustlist_colon_handler (void *priv, char *line) { gpgme_ctx_t ctx = (gpgme_ctx_t) priv; gpgme_error_t err; char *p, *pend; int field = 0; gpgme_trust_item_t item = NULL; if (!line) return 0; /* EOF */ for (p = line; p; p = pend) { field++; pend = strchr (p, ':'); if (pend) *pend++ = 0; switch (field) { case 1: /* level */ err = _gpgme_trust_item_new (&item); if (err) return err; item->level = atoi (p); break; case 2: /* long keyid */ if (strlen (p) == DIM(item->keyid) - 1) strcpy (item->keyid, p); break; case 3: /* type */ item->type = *p == 'K'? 1 : *p == 'U'? 2 : 0; break; case 5: /* owner trust */ item->_owner_trust[0] = *p; break; case 6: /* validity */ item->_validity[0] = *p; break; case 9: /* user ID */ item->name = strdup (p); if (!item->name) { int saved_errno = errno; gpgme_trust_item_unref (item); return gpg_error_from_errno (saved_errno); } break; } } if (item) _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_TRUSTITEM, item); return 0; }
/* Spawn a new thread to let RUNNER work as a coprocess. */ gpg_error_t runner_spawn (runner_t runner) { gpg_error_t err; npth_attr_t tattr; npth_t thread; int ret; if (check_already_spawned (runner, "runner_spawn")) return gpg_error (GPG_ERR_BUG); /* In case we have an input fd, open it as an estream so that the Pth scheduling will work. The stdio functions don't work with Pth because they don't call the pth counterparts of read and write unless linker tricks are used. */ if (runner->in_fd != -1) { estream_t fp; fp = es_fdopen (runner->in_fd, "r"); if (!fp) { err = gpg_error_from_syserror (); log_error ("can't fdopen pipe for reading: %s\n", gpg_strerror (err)); return err; } runner->status_fp = fp; runner->in_fd = -1; /* Now owned by status_fp. */ } npth_attr_init (&tattr); npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED); ret = npth_create (&thread, &tattr, runner_thread, runner); if (ret) { err = gpg_error_from_errno (ret); log_error ("error spawning runner thread: %s\n", gpg_strerror (err)); return err; } npth_setname_np (thread, runner->name); /* The scheduler has not yet kicked in, thus we can safely set the spawned flag and the tid. */ runner->spawned = 1; runner->thread = thread; runner->next_running = running_threads; running_threads = runner; npth_attr_destroy (&tattr); /* The runner thread is now runnable. */ return 0; }
gpgme_error_t gpgme_data_rewind (gpgme_data_t dh) { gpgme_error_t err; TRACE_BEG (DEBUG_DATA, "gpgme_data_rewind", dh); err = (gpgme_data_seek (dh, 0, SEEK_SET) == -1) ? gpg_error_from_errno (errno) : 0; return TRACE_ERR (err); }
gpgme_error_t cm_gpgme_data_rewind(gpgme_data_t dh) { #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 if (gpgme_data_seek(dh, (off_t)0, SEEK_SET) == -1) return gpg_error_from_errno(errno); else return 0; #else return gpgme_data_rewind(dh); #endif }
gpgme_error_t _gpgme_data_outbound_handler(void *opaque, int fd) { gpgme_data_t dh = (gpgme_data_t) opaque; ssize_t nwritten; if(!dh->pending_len) { ssize_t amt = gpgme_data_read(dh, dh->pending, BUFFER_SIZE); if(amt < 0) return gpg_error_from_errno(errno); if(amt == 0) { _gpgme_io_close(fd); return 0; } dh->pending_len = amt; } nwritten = _gpgme_io_write(fd, dh->pending, dh->pending_len); if(nwritten == -1 && errno == EAGAIN) return 0; if(nwritten == -1 && errno == EPIPE) { /* Not much we can do. The other end closed the pipe, but we still have data. This should only ever happen if the other end is going to tell us what happened on some other channel. Silently close our end. */ _gpgme_io_close(fd); return 0; } if(nwritten <= 0) return gpg_error_from_errno(errno); if(nwritten < dh->pending_len) memmove(dh->pending, dh->pending + nwritten, dh->pending_len - nwritten); dh->pending_len -= nwritten; return 0; }
/* Create new, empty Poldi context. Return proper error code. */ static gpg_error_t create_context (poldi_ctx_t *context, pam_handle_t *pam_handle) { gpg_error_t err; poldi_ctx_t ctx; err = 0; /* Allocate. */ ctx = xtrymalloc (sizeof (*ctx)); if (!ctx) { err = gpg_error_from_errno (errno); goto out; } /* Initialize. */ *ctx = poldi_ctx_NULL; ctx->auth_method = -1; ctx->cardinfo = scd_cardinfo_null; ctx->pam_handle = pam_handle; err = log_create (&ctx->loghandle); if (err) goto out; err = simpleparse_create (&ctx->parsehandle); if (err) goto out; simpleparse_set_loghandle (ctx->parsehandle, ctx->loghandle); simpleparse_set_parse_cb (ctx->parsehandle, pam_poldi_options_cb, ctx); simpleparse_set_specs (ctx->parsehandle, opt_specs); simpleparse_set_i18n_cb (ctx->parsehandle, i18n_cb, NULL); *context = ctx; out: if (err) { if (ctx) { simpleparse_destroy (ctx->parsehandle); log_destroy (ctx->loghandle); xfree (ctx); } } return err; }
static gpgme_error_t parse_enc_to (char *args, gpgme_recipient_t *recp) { gpgme_recipient_t rec; char *tail; int i; rec = malloc (sizeof (*rec)); if (!rec) return gpg_error_from_errno (errno); rec->next = NULL; rec->keyid = rec->_keyid; rec->status = 0; for (i = 0; i < sizeof (rec->_keyid) - 1; i++) { if (args[i] == '\0' || args[i] == ' ') break; rec->_keyid[i] = args[i]; } rec->_keyid[i] = '\0'; args = &args[i]; if (*args != '\0' && *args != ' ') { free (rec); return gpg_error (GPG_ERR_INV_ENGINE); } while (*args == ' ') args++; if (*args) { errno = 0; rec->pubkey_algo = strtol (args, &tail, 0); if (errno || args == tail || *tail != ' ') { /* The crypto backend does not behave. */ free (rec); return gpg_error (GPG_ERR_INV_ENGINE); } } /* FIXME: The key length is always 0 right now, so no need to parse it. */ *recp = rec; return 0; }
/* Create a new data buffer filled with the content of file FNAME. COPY must be non-zero (delayed reads are not supported yet). */ gpgme_error_t gpgme_data_new_from_file (gpgme_data_t *dh, const char *fname, int copy) { struct stat statbuf; if (!fname || !copy) return gpg_error (GPG_ERR_INV_VALUE); if (stat (fname, &statbuf) < 0) return gpg_error_from_errno (errno); return gpgme_data_new_from_filepart (dh, fname, NULL, 0, statbuf.st_size); }
/* FIXME: Missing a way to specify --silent. */ static gpgme_error_t uiserver_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text, gpgme_data_t plaintext) { engine_uiserver_t uiserver = engine; gpgme_error_t err; const char *protocol; char *cmd; if (!uiserver) return gpg_error (GPG_ERR_INV_VALUE); if (uiserver->protocol == GPGME_PROTOCOL_DEFAULT) protocol = ""; else if (uiserver->protocol == GPGME_PROTOCOL_OpenPGP) protocol = " --protocol=OpenPGP"; else if (uiserver->protocol == GPGME_PROTOCOL_CMS) protocol = " --protocol=CMS"; else return gpgme_error (GPG_ERR_UNSUPPORTED_PROTOCOL); if (asprintf (&cmd, "VERIFY%s", protocol) < 0) return gpg_error_from_errno (errno); uiserver->input_cb.data = sig; err = uiserver_set_fd (uiserver, INPUT_FD, map_data_enc (uiserver->input_cb.data)); if (err) { free (cmd); return err; } if (plaintext) { /* Normal or cleartext signature. */ uiserver->output_cb.data = plaintext; err = uiserver_set_fd (uiserver, OUTPUT_FD, 0); } else { /* Detached signature. */ uiserver->message_cb.data = signed_text; err = uiserver_set_fd (uiserver, MESSAGE_FD, 0); } uiserver->inline_data = NULL; if (!err) err = start (uiserver, cmd); free (cmd); return err; }
static gpgme_error_t genkey_status_handler(void *priv, gpgme_status_code_t code, char *args) { gpgme_ctx_t ctx = (gpgme_ctx_t) priv; gpgme_error_t err; void *hook; op_data_t opd; /* Pipe the status code through the progress status handler. */ err = _gpgme_progress_status_handler(ctx, code, args); if(err) return err; err = _gpgme_op_data_lookup(ctx, OPDATA_GENKEY, &hook, -1, NULL); opd = hook; if(err) return err; switch(code) { case GPGME_STATUS_KEY_CREATED: if(args && *args) { if(*args == 'B' || *args == 'P') opd->result.primary = 1; if(*args == 'B' || *args == 'S') opd->result.sub = 1; if(args[1] == ' ') { if(opd->result.fpr) free(opd->result.fpr); opd->result.fpr = strdup(&args[2]); if(!opd->result.fpr) return gpg_error_from_errno(errno); } } break; case GPGME_STATUS_EOF: /* FIXME: Should return some more useful error value. */ if(!opd->result.primary && !opd->result.sub) return gpg_error(GPG_ERR_GENERAL); break; default: break; } return 0; }
static gpgme_error_t uiserver_set_locale (void *engine, int category, const char *value) { engine_uiserver_t uiserver = engine; gpgme_error_t err; char *optstr; char *catstr; /* FIXME: If value is NULL, we need to reset the option to default. But we can't do this. So we error out here. UISERVER needs support for this. */ if (category == LC_CTYPE) { catstr = "lc-ctype"; if (!value && uiserver->lc_ctype_set) return gpg_error (GPG_ERR_INV_VALUE); if (value) uiserver->lc_ctype_set = 1; } #ifdef LC_MESSAGES else if (category == LC_MESSAGES) { catstr = "lc-messages"; if (!value && uiserver->lc_messages_set) return gpg_error (GPG_ERR_INV_VALUE); if (value) uiserver->lc_messages_set = 1; } #endif /* LC_MESSAGES */ else return gpg_error (GPG_ERR_INV_VALUE); /* FIXME: Reset value to default. */ if (!value) return 0; if (asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0) err = gpg_error_from_errno (errno); else { err = assuan_transact (uiserver->assuan_ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL); free (optstr); } return err; }
/* Create a new data buffer filled with the content of file FNAME. COPY must be non-zero (delayed reads are not supported yet). */ gpgme_error_t gpgme_data_new_from_file (gpgme_data_t *r_dh, const char *fname, int copy) { gpgme_error_t err; struct stat statbuf; TRACE_BEG3 (DEBUG_DATA, "gpgme_data_new_from_filepart", r_dh, "file_name=%s, copy=%i (%s)", fname, copy, copy ? "yes" : "no"); if (!fname || !copy) return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); if (stat (fname, &statbuf) < 0) return TRACE_ERR (gpg_error_from_errno (errno)); err = gpgme_data_new_from_filepart (r_dh, fname, NULL, 0, statbuf.st_size); return TRACE_ERR (err); }