/* Lock a spawning process. The caller needs to provide the address of a variable to store the lock information and the name or the process. */ gpg_error_t gpgex_lock_spawning (lock_spawn_t *lock) { int waitrc; int timeout = 5; _TRACE (DEBUG_ASSUAN, "gpgex_lock_spawning", lock); *lock = CreateMutexW (NULL, FALSE, L"spawn_gnupg_uiserver_sentinel"); if (!*lock) { TRACE_LOG1 ("failed to create the spawn mutex: rc=%d", GetLastError ()); return gpg_error (GPG_ERR_GENERAL); } retry: waitrc = WaitForSingleObject (*lock, 1000); if (waitrc == WAIT_OBJECT_0) return 0; if (waitrc == WAIT_TIMEOUT && timeout) { timeout--; goto retry; } if (waitrc == WAIT_TIMEOUT) TRACE_LOG ("error waiting for the spawn mutex: timeout"); else TRACE_LOG2 ("error waiting for the spawn mutex: (code=%d) rc=%d", waitrc, GetLastError ()); return gpg_error (GPG_ERR_GENERAL); }
/* Export the keys listed in PATTERN into KEYDATA. */ gpgme_error_t gpgme_op_export_ext (gpgme_ctx_t ctx, const char *pattern[], gpgme_export_mode_t mode, gpgme_data_t keydata) { gpgme_error_t err; TRACE_BEG2 (DEBUG_CTX, "gpgme_op_export_ext_start", ctx, "mode=0x%x, keydata=%p", mode, keydata); if (_gpgme_debug_trace () && pattern) { int i = 0; while (pattern[i]) { TRACE_LOG2 ("pattern[%i] = %s", i, pattern[i]); i++; } } err = export_ext_start (ctx, 1, pattern, mode, keydata); if (!err) err = _gpgme_wait_one (ctx); return TRACE_ERR (err); }
gpgme_assuan_result_t gpgme_op_assuan_result (gpgme_ctx_t ctx) { gpgme_error_t err; void *hook; op_data_t opd; TRACE_BEG (DEBUG_CTX, "gpgme_op_assuan_result", ctx); err = _gpgme_op_data_lookup (ctx, OPDATA_ASSUAN, &hook, -1, NULL); opd = hook; /* Check in case this function is used without having run a command before. */ if (err || !opd) { TRACE_SUC0 ("result=(null)"); return NULL; } /* All of this is a hack for the old style interface. The new style interface returns op errors directly. */ opd->result.err = _gpgme_engine_assuan_last_op_err (ctx->engine->engine); if (opd->result.err) { TRACE_LOG1 ("err = %s", gpg_strerror (0)); } else { TRACE_LOG2 ("err = %s <%s>", gpg_strerror (opd->result.err), gpg_strsource (opd->result.err)); } TRACE_SUC1 ("result=%p", &opd->result); return &opd->result; }
gpgme_import_result_t gpgme_op_import_result (gpgme_ctx_t ctx) { void *hook; op_data_t opd; gpgme_error_t err; TRACE_BEG (DEBUG_CTX, "gpgme_op_import_result", ctx); err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, &hook, -1, NULL); opd = hook; if (err || !opd) { TRACE_SUC0 ("result=(null)"); return NULL; } if (_gpgme_debug_trace ()) { gpgme_import_status_t impstat; int i; TRACE_LOG5 ("%i considered, %i no UID, %i imported, %i imported RSA, " "%i unchanged", opd->result.considered, opd->result.no_user_id, opd->result.imported, opd->result.imported_rsa, opd->result.unchanged); TRACE_LOG4 ("%i new UIDs, %i new sub keys, %i new signatures, " "%i new revocations", opd->result.new_user_ids, opd->result.new_sub_keys, opd->result.new_signatures, opd->result.new_revocations); TRACE_LOG3 ("%i secret keys, %i imported, %i unchanged", opd->result.secret_read, opd->result.secret_imported, opd->result.secret_unchanged); TRACE_LOG2 ("%i skipped new keys, %i not imported", opd->result.skipped_new_keys, opd->result.not_imported); impstat = opd->result.imports; i = 0; while (impstat) { TRACE_LOG4 ("import[%i] for %s = 0x%x (%s)", i, impstat->fpr, impstat->status, impstat->result); impstat = impstat->next; i++; } } TRACE_SUC1 ("result=%p", &opd->result); return &opd->result; }
gpgme_verify_result_t gpgme_op_verify_result (gpgme_ctx_t ctx) { void *hook; op_data_t opd; gpgme_error_t err; TRACE_BEG (DEBUG_CTX, "gpgme_op_verify_result", ctx); err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL); opd = hook; if (err || !opd) { TRACE_SUC0 ("result=(null)"); return NULL; } if (_gpgme_debug_trace ()) { gpgme_signature_t sig = opd->result.signatures; int i = 0; while (sig) { TRACE_LOG4 ("sig[%i] = fpr %s, summary 0x%x, status %s", i, sig->fpr, sig->summary, gpg_strerror (sig->status)); TRACE_LOG6 ("sig[%i] = timestamps 0x%x/0x%x flags:%s%s%s", i, sig->timestamp, sig->exp_timestamp, sig->wrong_key_usage ? "wrong key usage" : "", sig->pka_trust == 1 ? "pka bad" : (sig->pka_trust == 2 ? "pka_okay" : "pka RFU"), sig->chain_model ? "chain model" : ""); TRACE_LOG5 ("sig[%i] = validity 0x%x (%s), algos %s/%s", i, sig->validity, gpg_strerror (sig->validity_reason), gpgme_pubkey_algo_name (sig->pubkey_algo), gpgme_hash_algo_name (sig->hash_algo)); if (sig->pka_address) { TRACE_LOG2 ("sig[%i] = PKA address %s", i, sig->pka_address); } if (sig->notations) { TRACE_LOG1 ("sig[%i] = has notations (not shown)", i); } sig = sig->next; i++; } } TRACE_SUC1 ("result=%p", &opd->result); return &opd->result; }
int _gpgme_io_read (int fd, void *buffer, size_t count) { int saved_errno = 0; gsize nread; GIOChannel *chan; GIOStatus status; TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd, "buffer=%p, count=%u", buffer, count); chan = find_channel (fd); if (!chan) { TRACE_LOG ("no channel registered"); errno = EINVAL; return TRACE_SYSRES (-1); } TRACE_LOG1 ("channel %p", chan); { GError *err = NULL; status = g_io_channel_read_chars (chan, (gchar *) buffer, count, &nread, &err); if (err) { TRACE_LOG2 ("status %i, err %s", status, err->message); g_error_free (err); } } if (status == G_IO_STATUS_EOF) nread = 0; else if (status == G_IO_STATUS_AGAIN) { nread = -1; saved_errno = EAGAIN; } else if (status != G_IO_STATUS_NORMAL) { TRACE_LOG1 ("status %d", status); nread = -1; saved_errno = EIO; } if (nread != 0 && nread != -1) TRACE_LOGBUF (buffer, nread); errno = saved_errno; return TRACE_SYSRES (nread); }
/* XXXX. This is the synchronous variant. */ gpgme_error_t gpgme_op_assuan_transact_ext (gpgme_ctx_t ctx, const char *command, gpgme_assuan_data_cb_t data_cb, void *data_cb_value, gpgme_assuan_inquire_cb_t inq_cb, void *inq_cb_value, gpgme_assuan_status_cb_t status_cb, void *status_cb_value, gpgme_error_t *op_err_p) { gpgme_error_t err; gpgme_error_t op_err; TRACE_BEG8 (DEBUG_CTX, "gpgme_op_assuan_transact", ctx, "command=%s, data_cb=%p/%p, inq_cb=%p/%p, status_cb=%p/%p, " "op_err=%p", command, data_cb, data_cb_value, inq_cb, inq_cb_value, status_cb, status_cb_value, op_err_p); if (!ctx) return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); err = opassuan_start (ctx, 1, command, data_cb, data_cb_value, inq_cb, inq_cb_value, status_cb, status_cb_value); if (err) goto out; err = _gpgme_wait_one_ext (ctx, &op_err); if (op_err) { TRACE_LOG2 ("op_err = %s <%s>", gpgme_strerror (op_err), gpgme_strsource (op_err)); if (! op_err_p) { TRACE_LOG ("warning: operational error ignored by user"); } } if (op_err_p) *op_err_p = op_err; out: return TRACE_ERR (err); }
int _gpgme_io_spawn (const char *path, char * const argv[], unsigned int flags, struct spawn_fd_item_s *fd_list, void (*atfork) (void *opaque, int reserved), void *atforkvalue, pid_t *r_pid) { SECURITY_ATTRIBUTES sec_attr; PROCESS_INFORMATION pi = { NULL, /* returns process handle */ 0, /* returns primary thread handle */ 0, /* returns pid */ 0 /* returns tid */ }; STARTUPINFO si; int cr_flags = (CREATE_DEFAULT_ERROR_MODE | GetPriorityClass (GetCurrentProcess ())); int i; char **args; char *arg_string; /* FIXME. */ int debug_me = 0; int tmp_fd; char *tmp_name; TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path, "path=%s", path); i = 0; while (argv[i]) { TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]); i++; } /* We do not inherit any handles by default, and just insert those handles we want the child to have afterwards. But some handle values occur on the command line, and we need to move stdin/out/err to the right location. So we use a wrapper program which gets the information from a temporary file. */ if (_gpgme_mkstemp (&tmp_fd, &tmp_name) < 0) { TRACE_LOG1 ("_gpgme_mkstemp failed: %s", strerror (errno)); return TRACE_SYSRES (-1); } TRACE_LOG1 ("tmp_name = %s", tmp_name); args = calloc (2 + i + 1, sizeof (*args)); args[0] = (char *) _gpgme_get_w32spawn_path (); args[1] = tmp_name; args[2] = path; memcpy (&args[3], &argv[1], i * sizeof (*args)); memset (&sec_attr, 0, sizeof sec_attr); sec_attr.nLength = sizeof sec_attr; sec_attr.bInheritHandle = FALSE; arg_string = build_commandline (args); free (args); if (!arg_string) { close (tmp_fd); DeleteFile (tmp_name); return TRACE_SYSRES (-1); } memset (&si, 0, sizeof si); si.cb = sizeof (si); si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE; si.hStdInput = INVALID_HANDLE_VALUE; si.hStdOutput = INVALID_HANDLE_VALUE; si.hStdError = INVALID_HANDLE_VALUE; cr_flags |= CREATE_SUSPENDED; cr_flags |= DETACHED_PROCESS; if (!CreateProcessA (_gpgme_get_w32spawn_path (), arg_string, &sec_attr, /* process security attributes */ &sec_attr, /* thread security attributes */ FALSE, /* inherit handles */ cr_flags, /* creation flags */ NULL, /* environment */ NULL, /* use current drive/directory */ &si, /* startup information */ &pi)) /* returns process information */ { TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ()); free (arg_string); close (tmp_fd); DeleteFile (tmp_name); /* FIXME: Should translate the error code. */ errno = EIO; return TRACE_SYSRES (-1); } free (arg_string); if (flags & IOSPAWN_FLAG_ALLOW_SET_FG) _gpgme_allow_set_foreground_window ((pid_t)pi.dwProcessId); /* Insert the inherited handles. */ for (i = 0; fd_list[i].fd != -1; i++) { HANDLE hd; /* Make it inheritable for the wrapper process. */ if (!DuplicateHandle (GetCurrentProcess(), _get_osfhandle (giochannel_table[fd_list[i].fd].fd), pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS)) { TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ()); TerminateProcess (pi.hProcess, 0); /* Just in case TerminateProcess didn't work, let the process fail on its own. */ ResumeThread (pi.hThread); CloseHandle (pi.hThread); CloseHandle (pi.hProcess); close (tmp_fd); DeleteFile (tmp_name); /* FIXME: Should translate the error code. */ errno = EIO; return TRACE_SYSRES (-1); } /* Return the child name of this handle. */ fd_list[i].peer_name = (int) hd; } /* Write the handle translation information to the temporary file. */ { /* Hold roughly MAX_TRANS quadruplets of 64 bit numbers in hex notation: "0xFEDCBA9876543210" with an extra white space after every quadruplet. 10*(19*4 + 1) - 1 = 769. This plans ahead for a time when a HANDLE is 64 bit. */ #define BUFFER_MAX 800 char line[BUFFER_MAX + 1]; int res; int written; size_t len; if ((flags & IOSPAWN_FLAG_ALLOW_SET_FG)) strcpy (line, "~1 \n"); else strcpy (line, "\n"); for (i = 0; fd_list[i].fd != -1; i++) { /* Strip the newline. */ len = strlen (line) - 1; /* Format is: Local name, stdin/stdout/stderr, peer name, argv idx. */ snprintf (&line[len], BUFFER_MAX - len, "0x%x %d 0x%x %d \n", fd_list[i].fd, fd_list[i].dup_to, fd_list[i].peer_name, fd_list[i].arg_loc); /* Rather safe than sorry. */ line[BUFFER_MAX - 1] = '\n'; line[BUFFER_MAX] = '\0'; } len = strlen (line); written = 0; do { res = write (tmp_fd, &line[written], len - written); if (res > 0) written += res; } while (res > 0 || (res < 0 && errno == EAGAIN)); } close (tmp_fd); /* The temporary file is deleted by the gpgme-w32spawn process (hopefully). */ TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, " "dwProcessID=%d, dwThreadId=%d", pi.hProcess, pi.hThread, (int) pi.dwProcessId, (int) pi.dwThreadId); if (r_pid) *r_pid = (pid_t)pi.dwProcessId; if (ResumeThread (pi.hThread) < 0) TRACE_LOG1 ("ResumeThread failed: ec=%d", (int) GetLastError ()); if (!CloseHandle (pi.hThread)) TRACE_LOG1 ("CloseHandle of thread failed: ec=%d", (int) GetLastError ()); TRACE_LOG1 ("process=%p", pi.hProcess); /* We don't need to wait for the process. */ if (!CloseHandle (pi.hProcess)) TRACE_LOG1 ("CloseHandle of process failed: ec=%d", (int) GetLastError ()); if (! (flags & IOSPAWN_FLAG_NOCLOSE)) { for (i = 0; fd_list[i].fd != -1; i++) _gpgme_io_close (fd_list[i].fd); } for (i = 0; fd_list[i].fd != -1; i++) if (fd_list[i].dup_to == -1) TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd, fd_list[i].peer_name); else TRACE_LOG4 ("fd[%i] = 0x%x -> 0x%x (std%s)", i, fd_list[i].fd, fd_list[i].peer_name, (fd_list[i].dup_to == 0) ? "in" : ((fd_list[i].dup_to == 1) ? "out" : "err")); return TRACE_SYSRES (0); }
int _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen) { GIOChannel *chan; int sockfd; int res; GIOFlags flags; GIOStatus status; GError *err = NULL; TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd, "addr=%p, addrlen=%i", addr, addrlen); chan = find_channel (fd); if (! chan) { errno = EINVAL; return TRACE_SYSRES (-1); } flags = g_io_channel_get_flags (chan); if (flags & G_IO_FLAG_NONBLOCK) { status = g_io_channel_set_flags (chan, flags & ~G_IO_FLAG_NONBLOCK, &err); if (err) { TRACE_LOG1 ("setting flags error: %s", err->message); g_error_free (err); err = NULL; } if (status != G_IO_STATUS_NORMAL) { errno = EIO; return TRACE_SYSRES (-1); } } sockfd = giochannel_table[fd].socket; if (sockfd == INVALID_SOCKET) { errno = EINVAL; return TRACE_SYSRES (-1); } TRACE_LOG1 ("connect sockfd=0x%x", sockfd); res = connect (sockfd, addr, addrlen); /* FIXME: Error ignored here. */ if (! (flags & G_IO_FLAG_NONBLOCK)) g_io_channel_set_flags (chan, flags, NULL); if (res) { TRACE_LOG2 ("connect failed: %i %i", res, WSAGetLastError ()); errno = wsa2errno (WSAGetLastError ()); return TRACE_SYSRES (-1); } return TRACE_SUC (); }
gpgme_verify_result_t gpgme_op_verify_result (gpgme_ctx_t ctx) { void *hook; op_data_t opd; gpgme_error_t err; gpgme_signature_t sig; TRACE_BEG (DEBUG_CTX, "gpgme_op_verify_result", ctx); err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL); opd = hook; if (err || !opd) { TRACE_SUC0 ("result=(null)"); return NULL; } /* It is possible that we saw a new signature only followed by an ERROR line for that. In particular a missing X.509 key triggers this. In this case it is surprising that the summary field has not been updated. We fix it here by explicitly looking for this case. The real fix would be to have GPGME emit ERRSIG. */ for (sig = opd->result.signatures; sig; sig = sig->next) { if (!sig->summary) { switch (gpg_err_code (sig->status)) { case GPG_ERR_KEY_EXPIRED: sig->summary |= GPGME_SIGSUM_KEY_EXPIRED; break; case GPG_ERR_NO_PUBKEY: sig->summary |= GPGME_SIGSUM_KEY_MISSING; break; default: break; } } } /* Now for some tracing stuff. */ if (_gpgme_debug_trace ()) { int i; for (sig = opd->result.signatures, i = 0; sig; sig = sig->next, i++) { TRACE_LOG4 ("sig[%i] = fpr %s, summary 0x%x, status %s", i, sig->fpr, sig->summary, gpg_strerror (sig->status)); TRACE_LOG6 ("sig[%i] = timestamps 0x%x/0x%x flags:%s%s%s", i, sig->timestamp, sig->exp_timestamp, sig->wrong_key_usage ? "wrong key usage" : "", sig->pka_trust == 1 ? "pka bad" : (sig->pka_trust == 2 ? "pka_okay" : "pka RFU"), sig->chain_model ? "chain model" : ""); TRACE_LOG5 ("sig[%i] = validity 0x%x (%s), algos %s/%s", i, sig->validity, gpg_strerror (sig->validity_reason), gpgme_pubkey_algo_name (sig->pubkey_algo), gpgme_hash_algo_name (sig->hash_algo)); if (sig->pka_address) { TRACE_LOG2 ("sig[%i] = PKA address %s", i, sig->pka_address); } if (sig->notations) { TRACE_LOG1 ("sig[%i] = has notations (not shown)", i); } } } TRACE_SUC1 ("result=%p", &opd->result); return &opd->result; }
int _gpgme_io_read (int fd, void *buffer, size_t count) { int nread; struct reader_context_s *ctx; TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd, "buffer=%p, count=%u", buffer, count); ctx = find_reader (fd, 1); if (!ctx) { errno = EBADF; return TRACE_SYSRES (-1); } if (ctx->eof_shortcut) return TRACE_SYSRES (0); LOCK (ctx->mutex); if (ctx->readpos == ctx->writepos && !ctx->error) { /* No data available. */ UNLOCK (ctx->mutex); TRACE_LOG1 ("waiting for data from thread %p", ctx->thread_hd); WaitForSingleObject (ctx->have_data_ev, INFINITE); TRACE_LOG1 ("data from thread %p available", ctx->thread_hd); LOCK (ctx->mutex); } if (ctx->readpos == ctx->writepos || ctx->error) { UNLOCK (ctx->mutex); ctx->eof_shortcut = 1; if (ctx->eof) return TRACE_SYSRES (0); if (!ctx->error) { TRACE_LOG ("EOF but ctx->eof flag not set"); return 0; } errno = ctx->error_code; return TRACE_SYSRES (-1); } nread = ctx->readpos < ctx->writepos ? ctx->writepos - ctx->readpos : READBUF_SIZE - ctx->readpos; if (nread > count) nread = count; memcpy (buffer, ctx->buffer + ctx->readpos, nread); ctx->readpos = (ctx->readpos + nread) % READBUF_SIZE; if (ctx->readpos == ctx->writepos && !ctx->eof) { if (!ResetEvent (ctx->have_data_ev)) { TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ()); UNLOCK (ctx->mutex); /* FIXME: Should translate the error code. */ errno = EIO; return TRACE_SYSRES (-1); } } if (!SetEvent (ctx->have_space_ev)) { TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_space_ev, (int) GetLastError ()); UNLOCK (ctx->mutex); /* FIXME: Should translate the error code. */ errno = EIO; return TRACE_SYSRES (-1); } UNLOCK (ctx->mutex); TRACE_LOGBUF (buffer, nread); return TRACE_SYSRES (nread); }
static DWORD CALLBACK reader (void *arg) { struct reader_context_s *ctx = arg; int nbytes; DWORD nread; TRACE_BEG1 (DEBUG_SYSIO, "gpgme:reader", ctx->file_hd, "thread=%p", ctx->thread_hd); for (;;) { LOCK (ctx->mutex); /* Leave a 1 byte gap so that we can see whether it is empty or full. */ if ((ctx->writepos + 1) % READBUF_SIZE == ctx->readpos) { /* Wait for space. */ if (!ResetEvent (ctx->have_space_ev)) TRACE_LOG1 ("ResetEvent failed: ec=%d", (int) GetLastError ()); UNLOCK (ctx->mutex); TRACE_LOG ("waiting for space"); WaitForSingleObject (ctx->have_space_ev, INFINITE); TRACE_LOG ("got space"); LOCK (ctx->mutex); } if (ctx->stop_me) { UNLOCK (ctx->mutex); break; } nbytes = (ctx->readpos + READBUF_SIZE - ctx->writepos - 1) % READBUF_SIZE; if (nbytes > READBUF_SIZE - ctx->writepos) nbytes = READBUF_SIZE - ctx->writepos; UNLOCK (ctx->mutex); TRACE_LOG1 ("reading %d bytes", nbytes); if (!ReadFile (ctx->file_hd, ctx->buffer + ctx->writepos, nbytes, &nread, NULL)) { ctx->error_code = (int) GetLastError (); if (ctx->error_code == ERROR_BROKEN_PIPE) { ctx->eof = 1; TRACE_LOG ("got EOF (broken pipe)"); } else { ctx->error = 1; TRACE_LOG1 ("read error: ec=%d", ctx->error_code); } break; } if (!nread) { ctx->eof = 1; TRACE_LOG ("got eof"); break; } TRACE_LOG1 ("got %u bytes", nread); LOCK (ctx->mutex); if (ctx->stop_me) { UNLOCK (ctx->mutex); break; } ctx->writepos = (ctx->writepos + nread) % READBUF_SIZE; if (!SetEvent (ctx->have_data_ev)) TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev, (int) GetLastError ()); UNLOCK (ctx->mutex); } /* Indicate that we have an error or EOF. */ if (!SetEvent (ctx->have_data_ev)) TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev, (int) GetLastError ()); SetEvent (ctx->stopped); return TRACE_SUC (); }
/* This actually is a int file descriptor (and not assuan_fd_t) as _get_osfhandle is called on W32 systems. */ gpg_error_t assuan_init_pipe_server (assuan_context_t ctx, assuan_fd_t filedes[2]) { const char *s; unsigned long ul; gpg_error_t rc; assuan_fd_t infd = ASSUAN_INVALID_FD; assuan_fd_t outfd = ASSUAN_INVALID_FD; int is_usd = 0; TRACE_BEG (ctx, ASSUAN_LOG_CTX, "assuan_init_pipe_server", ctx); if (filedes) { TRACE_LOG2 ("fd[0]=0x%x, fd[1]=0x%x", filedes[0], filedes[1]); } rc = _assuan_register_std_commands (ctx); if (rc) return TRACE_ERR (rc); #ifdef HAVE_W32_SYSTEM infd = filedes[0]; outfd = filedes[1]; #else s = getenv ("_assuan_connection_fd"); if (s && *s && is_valid_socket (s)) { /* Well, we are called with an bi-directional file descriptor. Prepare for using sendmsg/recvmsg. In this case we ignore the passed file descriptors. */ infd = atoi (s); outfd = atoi (s); is_usd = 1; } else if (filedes && filedes[0] != ASSUAN_INVALID_FD && filedes[1] != ASSUAN_INVALID_FD ) { /* Standard pipe server. */ infd = filedes[0]; outfd = filedes[1]; } else { rc = _assuan_error (ctx, GPG_ERR_ASS_SERVER_START); return TRACE_ERR (rc); } #endif ctx->is_server = 1; ctx->engine.release = _assuan_server_release; ctx->engine.readfnc = _assuan_simple_read; ctx->engine.writefnc = _assuan_simple_write; ctx->engine.sendfd = NULL; ctx->engine.receivefd = NULL; ctx->max_accepts = 1; s = getenv ("_assuan_pipe_connect_pid"); if (s && (ul=strtoul (s, NULL, 10)) && ul) ctx->pid = (pid_t)ul; else ctx->pid = (pid_t)-1; ctx->accept_handler = NULL; ctx->finish_handler = _assuan_server_finish; ctx->inbound.fd = infd; ctx->outbound.fd = outfd; if (is_usd) _assuan_init_uds_io (ctx); return TRACE_SUC(); }