int main (int argc, char *argv[]) { int rc; npth_attr_t tattr; int state; npth_t tid1, tid2; void *retval; if (argc >= 2 && !strcmp (argv[1], "--verbose")) opt_verbose = 1; rc = npth_init (); fail_if_err (rc); rc = npth_mutex_init (&counter_mutex, NULL); fail_if_err (rc); rc = npth_attr_init (&tattr); fail_if_err (rc); rc = npth_attr_getdetachstate (&tattr, &state); fail_if_err (rc); if ( state != NPTH_CREATE_JOINABLE ) fail_msg ("new tattr is not joinable"); info_msg ("creating thread-one"); rc = npth_create (&tid1, &tattr, thread_one, NULL); fail_if_err (rc); npth_setname_np (tid1, "thread-one"); info_msg ("creating thread-two"); rc = npth_create (&tid2, &tattr, thread_two, NULL); fail_if_err (rc); npth_setname_np (tid2, "thread-two"); rc = npth_attr_destroy (&tattr); fail_if_err (rc); info_msg ("waiting for thread-one to terminate"); rc = npth_join (tid1, &retval); fail_if_err (rc); if (retval != (void*)4711) fail_msg ("thread-one returned an unexpected value"); info_msg ("waiting for thread-two to terminate"); rc = npth_join (tid2, &retval); fail_if_err (rc); if (retval != (void*)4722) fail_msg ("thread-two returned an unexpected value"); if (counter != 100) fail_msg ("counter value not as expected"); return 0; }
/* Close a popup window. */ void agent_popup_message_stop (ctrl_t ctrl) { int rc; pid_t pid; (void)ctrl; if (!popup_tid || !entry_ctx) { log_debug ("agent_popup_message_stop called with no active popup\n"); return; } pid = assuan_get_pid (entry_ctx); if (pid == (pid_t)(-1)) ; /* No pid available can't send a kill. */ else if (popup_finished) ; /* Already finished and ready for joining. */ #ifdef HAVE_W32_SYSTEM /* Older versions of assuan set PID to 0 on Windows to indicate an invalid value. */ else if (pid != (pid_t) INVALID_HANDLE_VALUE && pid != 0) { HANDLE process = (HANDLE) pid; /* Arbitrary error code. */ TerminateProcess (process, 1); } #else else if (pid && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) ) { /* The daemon already died. No need to send a kill. However because we already waited for the process, we need to tell assuan that it should not wait again (done by unlock_pinentry). */ if (rc == pid) assuan_set_flag (entry_ctx, ASSUAN_NO_WAITPID, 1); } else if (pid > 0) kill (pid, SIGINT); #endif /* Now wait for the thread to terminate. */ rc = npth_join (popup_tid, NULL); if (rc) log_debug ("agent_popup_message_stop: pth_join failed: %s\n", strerror (rc)); /* Thread IDs are opaque, but we try our best here by resetting it to the same content that a static global variable has. */ memset (&popup_tid, '\0', sizeof (popup_tid)); entry_owner = NULL; /* Now we can close the connection. */ unlock_pinentry (0); }
/* Call GPG to decrypt a block of data. */ static gpg_error_t _gpg_decrypt (ctrl_t ctrl, const char *gpg_program, strlist_t gpg_arguments, const void *ciph, size_t ciphlen, estream_t cipher_stream, membuf_t *reader_mb, estream_t plain_stream) { gpg_error_t err; assuan_context_t ctx = NULL; int outbound_fds[2] = { -1, -1 }; int inbound_fds[2] = { -1, -1 }; npth_t writer_thread = (npth_t)0; npth_t reader_thread = (npth_t)0; gpg_error_t writer_err, reader_err; int ret; /* Make sure that either the stream interface xor the buffer interface is used. */ assert ((ciph == NULL) != (cipher_stream == NULL)); assert ((reader_mb == NULL) != (plain_stream == NULL)); /* Create two pipes. */ err = gnupg_create_outbound_pipe (outbound_fds, NULL, 0); if (!err) err = gnupg_create_inbound_pipe (inbound_fds, NULL, 0); if (err) { log_error (_("error creating a pipe: %s\n"), gpg_strerror (err)); goto leave; } /* Start GPG and send the INPUT and OUTPUT commands. */ err = start_gpg (ctrl, gpg_program, gpg_arguments, outbound_fds[0], inbound_fds[1], &ctx); if (err) goto leave; close (outbound_fds[0]); outbound_fds[0] = -1; close (inbound_fds[1]); inbound_fds[1] = -1; /* Start a writer thread to feed the INPUT command of the server. */ err = start_writer (outbound_fds[1], ciph, ciphlen, cipher_stream, &writer_thread, &writer_err); if (err) return err; outbound_fds[1] = -1; /* The thread owns the FD now. */ /* Start a reader thread to eat from the OUTPUT command of the server. */ err = start_reader (inbound_fds[0], reader_mb, plain_stream, &reader_thread, &reader_err); if (err) return err; outbound_fds[0] = -1; /* The thread owns the FD now. */ /* Run the decryption. */ err = assuan_transact (ctx, "DECRYPT", NULL, NULL, NULL, NULL, NULL, NULL); if (err) { log_error ("the engine's DECRYPT command failed: %s <%s>\n", gpg_strerror (err), gpg_strsource (err)); goto leave; } /* Wait for reader and return the data. */ ret = npth_join (reader_thread, NULL); if (ret) { err = my_error_from_errno (ret); log_error ("waiting for reader thread failed: %s\n", gpg_strerror (err)); goto leave; } memset (&reader_thread, '\0', sizeof (reader_thread)); if (reader_err) { err = reader_err; log_error ("read error in reader thread: %s\n", gpg_strerror (err)); goto leave; } /* Wait for the writer to catch a writer error. */ ret = npth_join (writer_thread, NULL); if (ret) { err = my_error_from_errno (ret); log_error ("waiting for writer thread failed: %s\n", gpg_strerror (err)); goto leave; } memset (&writer_thread, '\0', sizeof (writer_thread)); if (writer_err) { err = writer_err; log_error ("write error in writer thread: %s\n", gpg_strerror (err)); goto leave; } leave: if (reader_thread) npth_detach (reader_thread); if (writer_thread) npth_detach (writer_thread); if (outbound_fds[0] != -1) close (outbound_fds[0]); if (outbound_fds[1] != -1) close (outbound_fds[1]); if (inbound_fds[0] != -1) close (inbound_fds[0]); if (inbound_fds[1] != -1) close (inbound_fds[1]); release_gpg (ctx); return err; }
/* Call GPG to encrypt a block of data. */ static gpg_error_t _gpg_encrypt (ctrl_t ctrl, const char *gpg_program, strlist_t gpg_arguments, const void *plain, size_t plainlen, estream_t plain_stream, strlist_t keys, membuf_t *reader_mb, estream_t cipher_stream) { gpg_error_t err; assuan_context_t ctx = NULL; int outbound_fds[2] = { -1, -1 }; int inbound_fds[2] = { -1, -1 }; npth_t writer_thread = (npth_t)0; npth_t reader_thread = (npth_t)0; gpg_error_t writer_err, reader_err; char line[ASSUAN_LINELENGTH]; strlist_t sl; int ret; /* Make sure that either the stream interface xor the buffer interface is used. */ assert ((plain == NULL) != (plain_stream == NULL)); assert ((reader_mb == NULL) != (cipher_stream == NULL)); /* Create two pipes. */ err = gnupg_create_outbound_pipe (outbound_fds, NULL, 0); if (!err) err = gnupg_create_inbound_pipe (inbound_fds, NULL, 0); if (err) { log_error (_("error creating a pipe: %s\n"), gpg_strerror (err)); goto leave; } /* Start GPG and send the INPUT and OUTPUT commands. */ err = start_gpg (ctrl, gpg_program, gpg_arguments, outbound_fds[0], inbound_fds[1], &ctx); if (err) goto leave; close (outbound_fds[0]); outbound_fds[0] = -1; close (inbound_fds[1]); inbound_fds[1] = -1; /* Start a writer thread to feed the INPUT command of the server. */ err = start_writer (outbound_fds[1], plain, plainlen, plain_stream, &writer_thread, &writer_err); if (err) return err; outbound_fds[1] = -1; /* The thread owns the FD now. */ /* Start a reader thread to eat from the OUTPUT command of the server. */ err = start_reader (inbound_fds[0], reader_mb, cipher_stream, &reader_thread, &reader_err); if (err) return err; outbound_fds[0] = -1; /* The thread owns the FD now. */ /* Run the encryption. */ for (sl = keys; sl; sl = sl->next) { snprintf (line, sizeof line, "RECIPIENT -- %s", sl->d); err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (err) { log_error ("the engine's RECIPIENT command failed: %s <%s>\n", gpg_strerror (err), gpg_strsource (err)); goto leave; } } err = assuan_transact (ctx, "ENCRYPT", NULL, NULL, NULL, NULL, NULL, NULL); if (err) { log_error ("the engine's ENCRYPT command failed: %s <%s>\n", gpg_strerror (err), gpg_strsource (err)); goto leave; } /* Wait for reader and return the data. */ ret = npth_join (reader_thread, NULL); if (ret) { err = my_error_from_errno (ret); log_error ("waiting for reader thread failed: %s\n", gpg_strerror (err)); goto leave; } /* FIXME: Not really valid, as npth_t is an opaque type. */ memset (&reader_thread, '\0', sizeof (reader_thread)); if (reader_err) { err = reader_err; log_error ("read error in reader thread: %s\n", gpg_strerror (err)); goto leave; } /* Wait for the writer to catch a writer error. */ ret = npth_join (writer_thread, NULL); if (ret) { err = my_error_from_errno (ret); log_error ("waiting for writer thread failed: %s\n", gpg_strerror (err)); goto leave; } memset (&writer_thread, '\0', sizeof (writer_thread)); if (writer_err) { err = writer_err; log_error ("write error in writer thread: %s\n", gpg_strerror (err)); goto leave; } leave: /* FIXME: Not valid, as npth_t is an opaque type. */ if (reader_thread) npth_detach (reader_thread); if (writer_thread) npth_detach (writer_thread); if (outbound_fds[0] != -1) close (outbound_fds[0]); if (outbound_fds[1] != -1) close (outbound_fds[1]); if (inbound_fds[0] != -1) close (inbound_fds[0]); if (inbound_fds[1] != -1) close (inbound_fds[1]); release_gpg (ctx); return err; }
/* Call GPG to decrypt a block of data. */ gpg_error_t gpg_decrypt_blob (ctrl_t ctrl, const void *ciph, size_t ciphlen, void **r_plain, size_t *r_plainlen) { gpg_error_t err; assuan_context_t ctx = NULL; int outbound_fds[2] = { -1, -1 }; int inbound_fds[2] = { -1, -1 }; npth_t writer_thread = (npth_t)0; npth_t reader_thread = (npth_t)0; gpg_error_t writer_err, reader_err; membuf_t reader_mb; int ret; *r_plain = NULL; *r_plainlen = 0; /* Init the memory buffer to receive the encrypted stuff. */ init_membuf_secure (&reader_mb, 1024); /* Create two pipes. */ err = gnupg_create_outbound_pipe (outbound_fds); if (!err) err = gnupg_create_inbound_pipe (inbound_fds); if (err) { log_error (_("error creating a pipe: %s\n"), gpg_strerror (err)); goto leave; } /* Start GPG and send the INPUT and OUTPUT commands. */ err = start_gpg (ctrl, outbound_fds[0], inbound_fds[1], &ctx); if (err) goto leave; close (outbound_fds[0]); outbound_fds[0] = -1; close (inbound_fds[1]); inbound_fds[1] = -1; /* Start a writer thread to feed the INPUT command of the server. */ err = start_writer (outbound_fds[1], ciph, ciphlen, &writer_thread, &writer_err); if (err) return err; outbound_fds[1] = -1; /* The thread owns the FD now. */ /* Start a reader thread to eat from the OUTPUT command of the server. */ err = start_reader (inbound_fds[0], &reader_mb, &reader_thread, &reader_err); if (err) return err; outbound_fds[0] = -1; /* The thread owns the FD now. */ /* Run the decryption. */ err = assuan_transact (ctx, "DECRYPT", NULL, NULL, NULL, NULL, NULL, NULL); if (err) { log_error ("the engine's DECRYPT command failed: %s <%s>\n", gpg_strerror (err), gpg_strsource (err)); goto leave; } /* Wait for reader and return the data. */ ret = npth_join (reader_thread, NULL); if (ret) { err = gpg_error_from_errno (ret); log_error ("waiting for reader thread failed: %s\n", gpg_strerror (err)); goto leave; } memset (&reader_thread, '\0', sizeof (reader_thread)); if (reader_err) { err = reader_err; log_error ("read error in reader thread: %s\n", gpg_strerror (err)); goto leave; } /* Wait for the writer to catch a writer error. */ ret = npth_join (writer_thread, NULL); if (ret) { err = gpg_error_from_errno (ret); log_error ("waiting for writer thread failed: %s\n", gpg_strerror (err)); goto leave; } memset (&writer_thread, '\0', sizeof (writer_thread)); if (writer_err) { err = writer_err; log_error ("write error in writer thread: %s\n", gpg_strerror (err)); goto leave; } /* Return the data. */ *r_plain = get_membuf (&reader_mb, r_plainlen); if (!*r_plain) { err = gpg_error_from_syserror (); log_error ("error while storing the data in the reader thread: %s\n", gpg_strerror (err)); goto leave; } leave: if (reader_thread) npth_detach (reader_thread); if (writer_thread) npth_detach (writer_thread); if (outbound_fds[0] != -1) close (outbound_fds[0]); if (outbound_fds[1] != -1) close (outbound_fds[1]); if (inbound_fds[0] != -1) close (inbound_fds[0]); if (inbound_fds[1] != -1) close (inbound_fds[1]); release_gpg (ctx); xfree (get_membuf (&reader_mb, NULL)); return err; }
/* Call GPG to encrypt a block of data. */ gpg_error_t gpg_encrypt_blob (ctrl_t ctrl, const void *plain, size_t plainlen, strlist_t keys, void **r_ciph, size_t *r_ciphlen) { gpg_error_t err; assuan_context_t ctx = NULL; int outbound_fds[2] = { -1, -1 }; int inbound_fds[2] = { -1, -1 }; npth_t writer_thread = (npth_t)0; npth_t reader_thread = (npth_t)0; gpg_error_t writer_err, reader_err; membuf_t reader_mb; char line[ASSUAN_LINELENGTH]; strlist_t sl; int ret; *r_ciph = NULL; *r_ciphlen = 0; /* Init the memory buffer to receive the encrypted stuff. */ init_membuf (&reader_mb, 4096); /* Create two pipes. */ err = gnupg_create_outbound_pipe (outbound_fds); if (!err) err = gnupg_create_inbound_pipe (inbound_fds); if (err) { log_error (_("error creating a pipe: %s\n"), gpg_strerror (err)); goto leave; } /* Start GPG and send the INPUT and OUTPUT commands. */ err = start_gpg (ctrl, outbound_fds[0], inbound_fds[1], &ctx); if (err) goto leave; close (outbound_fds[0]); outbound_fds[0] = -1; close (inbound_fds[1]); inbound_fds[1] = -1; /* Start a writer thread to feed the INPUT command of the server. */ err = start_writer (outbound_fds[1], plain, plainlen, &writer_thread, &writer_err); if (err) return err; outbound_fds[1] = -1; /* The thread owns the FD now. */ /* Start a reader thread to eat from the OUTPUT command of the server. */ err = start_reader (inbound_fds[0], &reader_mb, &reader_thread, &reader_err); if (err) return err; outbound_fds[0] = -1; /* The thread owns the FD now. */ /* Run the encryption. */ for (sl = keys; sl; sl = sl->next) { snprintf (line, sizeof line, "RECIPIENT -- %s", sl->d); err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (err) { log_error ("the engine's RECIPIENT command failed: %s <%s>\n", gpg_strerror (err), gpg_strsource (err)); goto leave; } } err = assuan_transact (ctx, "ENCRYPT", NULL, NULL, NULL, NULL, NULL, NULL); if (err) { log_error ("the engine's ENCRYPT command failed: %s <%s>\n", gpg_strerror (err), gpg_strsource (err)); goto leave; } /* Wait for reader and return the data. */ ret = npth_join (reader_thread, NULL); if (ret) { err = gpg_error_from_errno (ret); log_error ("waiting for reader thread failed: %s\n", gpg_strerror (err)); goto leave; } /* FIXME: Not really valid, as npth_t is an opaque type. */ memset (&reader_thread, '\0', sizeof (reader_thread)); if (reader_err) { err = reader_err; log_error ("read error in reader thread: %s\n", gpg_strerror (err)); goto leave; } /* Wait for the writer to catch a writer error. */ ret = npth_join (writer_thread, NULL); if (ret) { err = gpg_error_from_errno (ret); log_error ("waiting for writer thread failed: %s\n", gpg_strerror (err)); goto leave; } memset (&writer_thread, '\0', sizeof (writer_thread)); if (writer_err) { err = writer_err; log_error ("write error in writer thread: %s\n", gpg_strerror (err)); goto leave; } /* Return the data. */ *r_ciph = get_membuf (&reader_mb, r_ciphlen); if (!*r_ciph) { err = gpg_error_from_syserror (); log_error ("error while storing the data in the reader thread: %s\n", gpg_strerror (err)); goto leave; } leave: /* FIXME: Not valid, as npth_t is an opaque type. */ if (reader_thread) npth_detach (reader_thread); if (writer_thread) npth_detach (writer_thread); if (outbound_fds[0] != -1) close (outbound_fds[0]); if (outbound_fds[1] != -1) close (outbound_fds[1]); if (inbound_fds[0] != -1) close (inbound_fds[0]); if (inbound_fds[1] != -1) close (inbound_fds[1]); release_gpg (ctx); xfree (get_membuf (&reader_mb, NULL)); return err; }