/* Add the human-readable notation data with name NAME and value VALUE to the context CTX, using the flags FLAGS. If NAME is NULL, then VALUE should be a policy URL. The flag GPGME_SIG_NOTATION_HUMAN_READABLE is forced to be true for notation data, and false for policy URLs. */ gpgme_error_t gpgme_sig_notation_add (gpgme_ctx_t ctx, const char *name, const char *value, gpgme_sig_notation_flags_t flags) { gpgme_error_t err; gpgme_sig_notation_t notation; gpgme_sig_notation_t *lastp; TRACE_BEG3 (DEBUG_CTX, "gpgme_sig_notation_add", ctx, "name=%s, value=%s, flags=0x%x", name ? name : "(null)", value ? value : "(null)", flags); if (!ctx) return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); if (name) flags |= GPGME_SIG_NOTATION_HUMAN_READABLE; else flags &= ~GPGME_SIG_NOTATION_HUMAN_READABLE; err = _gpgme_sig_notation_create (¬ation, name, name ? strlen (name) : 0, value, value ? strlen (value) : 0, flags); if (err) return TRACE_ERR (err); lastp = &ctx->sig_notations; while (*lastp) lastp = &(*lastp)->next; *lastp = notation; return TRACE_ERR (0); }
gpgme_error_t gpgme_op_vfs_create (gpgme_ctx_t ctx, gpgme_key_t recp[], const char *container_file, unsigned int flags, gpgme_error_t *op_err) { gpg_error_t err; TRACE_BEG3 (DEBUG_CTX, "gpgme_op_vfs_create", ctx, "container_file=%s, flags=0x%x, op_err=%p", container_file, flags, op_err); if (!ctx) return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); if (_gpgme_debug_trace () && recp) { int i = 0; while (recp[i]) { TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i], (recp[i]->subkeys && recp[i]->subkeys->fpr) ? recp[i]->subkeys->fpr : "invalid"); i++; } } err = _gpgme_op_vfs_create (ctx, recp, container_file, flags, op_err); return TRACE_ERR (err); }
/* Encrypt plaintext PLAIN within CTX for the recipients RECP and store the resulting ciphertext in CIPHER. Also sign the ciphertext with the signers in CTX. */ gpgme_error_t gpgme_op_encrypt_sign_start (gpgme_ctx_t ctx, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, gpgme_data_t plain, gpgme_data_t cipher) { gpgme_error_t err; TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_sign_start", ctx, "flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher); if (!ctx) return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); if (_gpgme_debug_trace () && recp) { int i = 0; while (recp[i]) { TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i], (recp[i]->subkeys && recp[i]->subkeys->fpr) ? recp[i]->subkeys->fpr : "invalid"); i++; } } err = encrypt_sign_start (ctx, 0, recp, flags, plain, cipher); return err; }
static ssize_t __assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer, size_t size) { /* Due to the peculiarities of the W32 API we can't use write for a network socket and thus we try to use send first and fallback to write if send detects that it is not a network socket. */ int res; TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "__assuan_write", ctx, "fd=0x%x, buffer=%p, size=%i", fd, buffer, size); #ifdef HAVE_W32CE_SYSTEM /* This is a bit of a hack to support stdout over ssh. Note that fread buffers fully while getchar is line buffered. Weird, but that's the way it is. ASSUAN_STDIN and ASSUAN_STDOUT are special handle values that shouldn't occur in the wild. */ if (fd == ASSUAN_STDOUT) { res = fwrite (buffer, 1, size, stdout); return TRACE_SYSRES (res); } #endif res = send ((int)fd, buffer, size, 0); if (res == -1 && WSAGetLastError () == WSAENOTSOCK) { DWORD nwrite; TRACE_LOG ("send call failed - trying WriteFile"); res = WriteFile (fd, buffer, size, &nwrite, NULL); if (! res) { TRACE_LOG1 ("WriteFile failed: rc=%d", (int)GetLastError ()); switch (GetLastError ()) { case ERROR_BROKEN_PIPE: case ERROR_NO_DATA: gpg_err_set_errno (EPIPE); break; case ERROR_PIPE_NOT_CONNECTED: case ERROR_BUSY: gpg_err_set_errno (EAGAIN); break; default: gpg_err_set_errno (EIO); break; } res = -1; } else res = (int) nwrite; } else if (res == -1) TRACE_LOG1 ("send call failed: rc=%d", (int)GetLastError ()); return TRACE_SYSRES (res); }
/* Export the keys listed in PATTERN into KEYDATA. */ gpgme_error_t gpgme_op_export_start (gpgme_ctx_t ctx, const char *pattern, gpgme_export_mode_t mode, gpgme_data_t keydata) { gpgme_error_t err; TRACE_BEG3 (DEBUG_CTX, "gpgme_op_export_start", ctx, "pattern=%s, mode=0x%x, keydata=%p", pattern, mode, keydata); err = export_start (ctx, 0, pattern, mode, keydata); return TRACE_ERR (err); }
/* Decrypt ciphertext CIPHER and make a signature verification within CTX and store the resulting plaintext in PLAIN. */ gpgme_error_t gpgme_op_verify_start (gpgme_ctx_t ctx, gpgme_data_t sig, gpgme_data_t signed_text, gpgme_data_t plaintext) { gpg_error_t err; TRACE_BEG3 (DEBUG_CTX, "gpgme_op_verify_start", ctx, "sig=%p, signed_text=%p, plaintext=%p", sig, signed_text, plaintext); err = verify_start (ctx, 0, sig, signed_text, plaintext); return TRACE_ERR (err); }
/* Delete KEY from the keyring. If ALLOW_SECRET is non-zero, secret keys are also deleted. */ gpgme_error_t gpgme_op_delete_start (gpgme_ctx_t ctx, const gpgme_key_t key, int allow_secret) { gpgme_error_t err; TRACE_BEG3 (DEBUG_CTX, "gpgme_op_delete", ctx, "key=%p (%s), allow_secret=%i", key, (key->subkeys && key->subkeys->fpr) ? key->subkeys->fpr : "invalid", allow_secret); err = delete_start (ctx, 0, key, allow_secret); return TRACE_ERR (err); }
/* Export the keys listed in PATTERN into KEYDATA. */ gpgme_error_t gpgme_op_export (gpgme_ctx_t ctx, const char *pattern, gpgme_export_mode_t mode, gpgme_data_t keydata) { gpgme_error_t err; TRACE_BEG3 (DEBUG_CTX, "gpgme_op_export", ctx, "pattern=%s, mode=0x%x, keydata=%p", pattern, mode, keydata); err = export_start (ctx, 1, pattern, mode, keydata); if (!err) err = _gpgme_wait_one (ctx); return err; }
/* Delete KEY from the keyring. If ALLOW_SECRET is non-zero, secret keys are also deleted. */ gpgme_error_t gpgme_op_delete (gpgme_ctx_t ctx, const gpgme_key_t key, int allow_secret) { gpgme_error_t err; TRACE_BEG3 (DEBUG_CTX, "gpgme_op_delete", ctx, "key=%p (%s), allow_secret=%i", key, (key->subkeys && key->subkeys->fpr) ? key->subkeys->fpr : "invalid", allow_secret); err = delete_start (ctx, 1, key, allow_secret); if (!err) err = _gpgme_wait_one (ctx); return err; }
/* Decrypt ciphertext CIPHER and make a signature verification within CTX and store the resulting plaintext in PLAIN. */ gpgme_error_t gpgme_op_verify (gpgme_ctx_t ctx, gpgme_data_t sig, gpgme_data_t signed_text, gpgme_data_t plaintext) { gpgme_error_t err; TRACE_BEG3 (DEBUG_CTX, "gpgme_op_verify", ctx, "sig=%p, signed_text=%p, plaintext=%p", sig, signed_text, plaintext); err = verify_start (ctx, 1, sig, signed_text, plaintext); if (!err) err = _gpgme_wait_one (ctx); return TRACE_ERR (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); }
/* 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) { #if defined (HAVE_W32CE_SYSTEM) && defined (_MSC_VER) return gpgme_error (GPG_ERR_NOT_IMPLEMENTED); #else 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); #endif }
/* This function is similar to pipe_connect but uses a socketpair and sets the I/O up to use sendmsg/recvmsg. */ static gpg_error_t socketpair_connect (assuan_context_t ctx, const char *name, const char **argv, assuan_fd_t *fd_child_list, void (*atfork) (void *opaque, int reserved), void *atforkvalue) { gpg_error_t err; int idx; int fds[2]; char mypidstr[50]; pid_t pid; int *child_fds = NULL; int child_fds_cnt = 0; struct at_socketpair_fork atp; int rc; TRACE_BEG3 (ctx, ASSUAN_LOG_CTX, "socketpair_connect", ctx, "name=%s,atfork=%p,atforkvalue=%p", name ? name : "(null)", atfork, atforkvalue); atp.user_atfork = atfork; atp.user_atforkvalue = atforkvalue; atp.parent_pid = getpid (); if (!ctx || (name && (!argv || !argv[0])) || (!name && !argv)) return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); if (! ctx->flags.no_fixsignals) fix_signals (); sprintf (mypidstr, "%lu", (unsigned long)getpid ()); if (fd_child_list) while (fd_child_list[child_fds_cnt] != ASSUAN_INVALID_FD) child_fds_cnt++; child_fds = _assuan_malloc (ctx, (child_fds_cnt + 2) * sizeof (int)); if (! child_fds) return TRACE_ERR (gpg_err_code_from_syserror ()); child_fds[1] = ASSUAN_INVALID_FD; if (fd_child_list) memcpy (&child_fds[1], fd_child_list, (child_fds_cnt + 1) * sizeof (int)); if (_assuan_socketpair (ctx, AF_LOCAL, SOCK_STREAM, 0, fds)) { TRACE_LOG1 ("socketpair failed: %s", strerror (errno)); _assuan_free (ctx, child_fds); return TRACE_ERR (GPG_ERR_ASS_GENERAL); } atp.peer_fd = fds[1]; child_fds[0] = fds[1]; rc = _assuan_spawn (ctx, &pid, name, argv, ASSUAN_INVALID_FD, ASSUAN_INVALID_FD, child_fds, at_socketpair_fork_cb, &atp, 0); if (rc < 0) { err = gpg_err_code_from_syserror (); _assuan_close (ctx, fds[0]); _assuan_close (ctx, fds[1]); _assuan_free (ctx, child_fds); return TRACE_ERR (err); } /* For W32, the user needs to know the server-local names of the inherited handles. Return them here. Note that the translation of the peer socketpair fd (fd_child_list[0]) must be done by the wrapper program based on the environment variable _assuan_connection_fd. */ if (fd_child_list) { for (idx = 0; fd_child_list[idx] != -1; idx++) /* We add 1 to skip over the socketpair end. */ fd_child_list[idx] = child_fds[idx + 1]; } _assuan_free (ctx, child_fds); /* If this is the server child process, exit early. */ if (! name && (*argv)[0] == 's') { _assuan_close (ctx, fds[0]); return 0; } _assuan_close (ctx, fds[1]); ctx->engine.release = _assuan_client_release; ctx->finish_handler = _assuan_client_finish; ctx->max_accepts = 1; ctx->inbound.fd = fds[0]; ctx->outbound.fd = fds[0]; _assuan_init_uds_io (ctx); err = initial_handshake (ctx); if (err) _assuan_reset (ctx); return err; }
static ssize_t __assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size) { /* Due to the peculiarities of the W32 API we can't use read for a network socket and thus we try to use recv first and fallback to read if recv detects that it is not a network socket. */ int res; TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "__assuan_read", ctx, "fd=0x%x, buffer=%p, size=%i", fd, buffer, size); #ifdef HAVE_W32CE_SYSTEM /* This is a bit of a hack to support stdin over ssh. Note that fread buffers fully while getchar is line buffered. Weird, but that's the way it is. ASSUAN_STDIN and ASSUAN_STDOUT are special handle values that shouldn't occur in the wild. */ if (fd == ASSUAN_STDIN) { int i = 0; int chr; while (i < size) { chr = getchar(); if (chr == EOF) break; ((char*)buffer)[i++] = (char) chr; if (chr == '\n') break; } return TRACE_SYSRES (i); } #endif res = recv (HANDLE2SOCKET (fd), buffer, size, 0); if (res == -1) { TRACE_LOG1 ("recv failed: rc=%d", (int)WSAGetLastError ()); switch (WSAGetLastError ()) { case WSAENOTSOCK: { DWORD nread = 0; res = ReadFile (fd, buffer, size, &nread, NULL); if (! res) { TRACE_LOG1 ("ReadFile failed: rc=%d", (int)GetLastError ()); switch (GetLastError ()) { case ERROR_BROKEN_PIPE: gpg_err_set_errno (EPIPE); break; case ERROR_PIPE_NOT_CONNECTED: case ERROR_BUSY: gpg_err_set_errno (EAGAIN); break; default: gpg_err_set_errno (EIO); } res = -1; } else res = (int) nread; } break; case WSAEWOULDBLOCK: gpg_err_set_errno (EAGAIN); break; case ERROR_BROKEN_PIPE: gpg_err_set_errno (EPIPE); break; default: gpg_err_set_errno (EIO); break; } } return TRACE_SYSRES (res); }