int assuan_init_pipe_server (assuan_context_t *r_ctx, int filedes[2]) { int rc; rc = _assuan_new_context (r_ctx); if (!rc) { assuan_context_t ctx = *r_ctx; const char *s; unsigned long ul; ctx->is_server = 1; #ifdef HAVE_W32_SYSTEM /* MS Windows has so many different types of handle that one needs to tranlsate them at many place forth and back. Also make sure that the file descriptors are in binary mode. */ setmode (filedes[0], O_BINARY); setmode (filedes[1], O_BINARY); ctx->inbound.fd = (void*)_get_osfhandle (filedes[0]); ctx->outbound.fd = (void*)_get_osfhandle (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. */ ctx->inbound.fd = ctx->outbound.fd = atoi (s); _assuan_init_uds_io (ctx); ctx->deinit_handler = _assuan_uds_deinit; } else if (filedes && filedes[0] != ASSUAN_INVALID_FD && filedes[1] != ASSUAN_INVALID_FD ) { /* Standard pipe server. */ ctx->inbound.fd = filedes[0]; ctx->outbound.fd = filedes[1]; } else { _assuan_release_context (*r_ctx); *r_ctx = NULL; return ASSUAN_Problem_Starting_Server; } #endif ctx->pipe_mode = 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; } return rc; }
/* Flag bits: 0 - use sendmsg/recvmsg to allow descriptor passing 1 - FD has already been accepted. */ int assuan_init_socket_server_ext (assuan_context_t *r_ctx, assuan_fd_t fd, unsigned int flags) { assuan_context_t ctx; int rc; *r_ctx = NULL; ctx = xtrycalloc (1, sizeof *ctx); if (!ctx) return _assuan_error (ASSUAN_Out_Of_Core); ctx->is_server = 1; if ((flags & 2)) ctx->pipe_mode = 1; /* We want a second accept to indicate EOF. */ ctx->input_fd = ASSUAN_INVALID_FD; ctx->output_fd = ASSUAN_INVALID_FD; ctx->inbound.fd = ASSUAN_INVALID_FD; ctx->outbound.fd = ASSUAN_INVALID_FD; if ((flags & 2)) { ctx->listen_fd = ASSUAN_INVALID_FD; ctx->connected_fd = fd; } else { ctx->listen_fd = fd; ctx->connected_fd = ASSUAN_INVALID_FD; } ctx->deinit_handler = (flags & 1)? _assuan_uds_deinit:deinit_socket_server; ctx->accept_handler = ((flags & 2) ? accept_connection_bottom : accept_connection); ctx->finish_handler = finish_connection; ctx->io = &io; if ((flags & 1)) _assuan_init_uds_io (ctx); rc = _assuan_register_std_commands (ctx); if (rc) xfree (ctx); else *r_ctx = ctx; return rc; }
static gpg_error_t _assuan_connect_finalize (assuan_context_t ctx, assuan_fd_t fd, unsigned int flags) { gpg_error_t err; ctx->engine.release = _assuan_client_release; ctx->engine.readfnc = _assuan_simple_read; ctx->engine.writefnc = _assuan_simple_write; ctx->engine.sendfd = NULL; ctx->engine.receivefd = NULL; ctx->finish_handler = _assuan_client_finish; ctx->inbound.fd = fd; ctx->outbound.fd = fd; ctx->max_accepts = -1; if (flags & ASSUAN_SOCKET_CONNECT_FDPASSING) _assuan_init_uds_io (ctx); /* initial handshake */ { assuan_response_t response; int off; err = _assuan_read_from_server (ctx, &response, &off, 0); if (err) TRACE1 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect", ctx, "can't connect to server: %s\n", gpg_strerror (err)); else if (response != ASSUAN_RESPONSE_OK) { char *sname = _assuan_encode_c_string (ctx, ctx->inbound.line); if (sname) { TRACE1 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect", ctx, "can't connect to server: %s", sname); _assuan_free (ctx, sname); } err = _assuan_error (ctx, GPG_ERR_ASS_CONNECT_FAILED); } } return err; }
/* 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; }
/* Make a connection to the Unix domain socket NAME and return a new Assuan context in CTX. SERVER_PID is currently not used but may become handy in the future. With flags set to 1 sendmsg and recvmesg are used. */ assuan_error_t assuan_socket_connect_ext(assuan_context_t *r_ctx, const char *name, pid_t server_pid, unsigned int flags) { static struct assuan_io io = { _assuan_simple_read, _assuan_simple_write }; assuan_error_t err; assuan_context_t ctx; int fd; struct sockaddr_un srvr_addr; size_t len; const char *s; if(!r_ctx || !name) return _assuan_error(ASSUAN_Invalid_Value); *r_ctx = NULL; /* We require that the name starts with a slash, so that we eventually can reuse this function for other socket types. To make things easier we allow an optional dirver prefix. */ s = name; if(*s && s[1] == ':') s += 2; if(*s != DIRSEP_C && *s != '/') return _assuan_error(ASSUAN_Invalid_Value); if(strlen(name) + 1 >= sizeof srvr_addr.sun_path) return _assuan_error(ASSUAN_Invalid_Value); err = _assuan_new_context(&ctx); if(err) return err; ctx->deinit_handler = ((flags & 1)) ? _assuan_uds_deinit : do_deinit; ctx->finish_handler = do_finish; fd = _assuan_sock_new(PF_LOCAL, SOCK_STREAM, 0); if(fd == -1) { _assuan_log_printf("can't create socket: %s\n", strerror(errno)); _assuan_release_context(ctx); return _assuan_error(ASSUAN_General_Error); } memset(&srvr_addr, 0, sizeof srvr_addr); srvr_addr.sun_family = AF_LOCAL; strncpy(srvr_addr.sun_path, name, sizeof(srvr_addr.sun_path) - 1); srvr_addr.sun_path[sizeof(srvr_addr.sun_path) - 1] = 0; len = SUN_LEN(&srvr_addr); if(_assuan_sock_connect(fd, (struct sockaddr *) &srvr_addr, len) == -1) { _assuan_log_printf("can't connect to `%s': %s\n", name, strerror(errno)); _assuan_release_context(ctx); _assuan_close(fd); return _assuan_error(ASSUAN_Connect_Failed); } ctx->inbound.fd = fd; ctx->outbound.fd = fd; ctx->io = &io; if((flags & 1)) _assuan_init_uds_io(ctx); /* initial handshake */ { int okay, off; err = _assuan_read_from_server(ctx, &okay, &off); if(err) _assuan_log_printf("can't connect to server: %s\n", assuan_strerror(err)); else if(okay != 1) { /*LOG ("can't connect to server: `");*/ _assuan_log_sanitized_string(ctx->inbound.line); fprintf(assuan_get_assuan_log_stream(), "'\n"); err = _assuan_error(ASSUAN_Connect_Failed); } } if(err) { assuan_disconnect(ctx); } else *r_ctx = ctx; return 0; }
/* 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(); }