diff --git a/src/assuan-defs.h b/src/assuan-defs.h index b9a0e8b..37a50af 100644 --- a/src/assuan-defs.h +++ b/src/assuan-defs.h @@ -1,440 +1,442 @@ /* assuan-defs.h - Internal definitions to Assuan * Copyright (C) 2001, 2002, 2004, 2005, 2007, 2008, * 2009, 2010 Free Software Foundation, Inc. * * This file is part of Assuan. * * Assuan is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Assuan is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ */ #ifndef ASSUAN_DEFS_H #define ASSUAN_DEFS_H #ifdef HAVE_SYS_TYPES_H # include #endif #ifndef HAVE_W32_SYSTEM # include # include #else # ifdef HAVE_WINSOCK2_H # /* Avoid inclusion of winsock.h via windows.h. */ # include # endif # include #endif #ifdef HAVE_UNISTD_H # include #endif #include "assuan.h" #if __GNUC__ > 2 # define ASSUAN_GCC_A_PURE __attribute__ ((__pure__)) #else # define ASSUAN_GCC_A_PURE #endif #ifndef HAVE_W32_SYSTEM #define DIRSEP_C '/' #else #define DIRSEP_C '\\' #endif #define LINELENGTH ASSUAN_LINELENGTH struct cmdtbl_s { const char *name; assuan_handler_t handler; const char *helpstr; }; /* The context we use with most functions. */ struct assuan_context_s { /* Members managed by the generic routines in assuan.c. */ /* The error source for errors generated from this context. */ gpg_err_source_t err_source; #ifdef HAVE_W32_SYSTEM /* The per-context w32 error string. */ char w32_strerror[256]; #endif /* The allocation hooks. */ struct assuan_malloc_hooks malloc_hooks; /* Logging callback handler. */ assuan_log_cb_t log_cb; void *log_cb_data; void *user_pointer; /* Context specific flags (cf. assuan_flag_t). */ struct { unsigned int no_waitpid : 1; unsigned int confidential : 1; unsigned int no_fixsignals : 1; unsigned int convey_comments : 1; unsigned int no_logging : 1; unsigned int force_close : 1; /* From here, we have internal flags, not defined by assuan_flag_t. */ unsigned int is_socket : 1; - unsigned int is_server : 1; /* Set if this is context belongs to a server */ - unsigned int in_inquire : 1; + unsigned int is_server : 1; /* Set if this is context belongs to a server */ + unsigned int in_inquire : 1; /* Server: inside assuan_inquire */ unsigned int in_process_next : 1; unsigned int process_complete : 1; unsigned int in_command : 1; + unsigned int in_inq_cb : 1; /* Client: inquire callback is active */ + unsigned int confidential_inquiry : 1; /* Client: inquiry is confidential */ } flags; /* If set, this is called right before logging an I/O line. */ assuan_io_monitor_t io_monitor; void *io_monitor_data; /* Callback handlers replacing system I/O functions. */ struct assuan_system_hooks system; int peercred_valid; /* Whether this structure has valid information. */ struct _assuan_peercred peercred; /* Now come the members specific to subsystems or engines. FIXME: This is not developed yet. See below for the legacy members. */ struct { void (*release) (assuan_context_t ctx); /* Routine to read from input_fd. Sets errno on failure. */ ssize_t (*readfnc) (assuan_context_t, void *, size_t); /* Routine to write to output_fd. Sets errno on failure. */ ssize_t (*writefnc) (assuan_context_t, const void *, size_t); /* Send a file descriptor. */ gpg_error_t (*sendfd) (assuan_context_t, assuan_fd_t); /* Receive a file descriptor. */ gpg_error_t (*receivefd) (assuan_context_t, assuan_fd_t *); } engine; /* Engine specific or other subsystem members. */ /* assuan-logging.c. Does not require deallocation from us. */ FILE *log_fp; /* assuan-util.c */ gpg_error_t err_no; const char *err_str; /* The following members are used by assuan_inquire_ext. */ gpg_error_t (*inquire_cb) (void *cb_data, gpg_error_t rc, unsigned char *buf, size_t len); void *inquire_cb_data; void *inquire_membuf; char *hello_line; char *okay_line; /* See assuan_set_okay_line() */ struct { assuan_fd_t fd; int eof; char line[LINELENGTH]; int linelen; /* w/o CR, LF - might not be the same as strlen(line) due to embedded nuls. However a nul is always written at this pos. */ struct { char line[LINELENGTH]; int linelen ; int pending; /* i.e. at least one line is available in the attic */ } attic; } inbound; struct { assuan_fd_t fd; struct { FILE *fp; char line[LINELENGTH]; int linelen; int error; } data; } outbound; int max_accepts; /* If we can not handle more than one connection, set this to 1, otherwise to -1. */ pid_t pid; /* The pid of the peer. */ assuan_fd_t listen_fd; /* The fd we are listening on (used by socket servers) */ assuan_sock_nonce_t listen_nonce; /* Used with LISTEN_FD. */ assuan_fd_t connected_fd; /* helper */ /* Used for Unix domain sockets. */ struct sockaddr_un myaddr; struct sockaddr_un serveraddr; /* Structure used for unix domain sockets. */ struct { assuan_fd_t pendingfds[5]; /* Array to save received descriptors. */ int pendingfdscount; /* Number of received descriptors. */ } uds; gpg_error_t (*accept_handler)(assuan_context_t); void (*finish_handler)(assuan_context_t); struct cmdtbl_s *cmdtbl; size_t cmdtbl_used; /* used entries */ size_t cmdtbl_size; /* allocated size of table */ /* The name of the command currently processed by a command handler. This is a pointer into CMDTBL. NULL if not in a command handler. */ const char *current_cmd_name; assuan_handler_t bye_notify_fnc; assuan_handler_t reset_notify_fnc; assuan_handler_t cancel_notify_fnc; gpg_error_t (*option_handler_fnc)(assuan_context_t,const char*, const char*); assuan_handler_t input_notify_fnc; assuan_handler_t output_notify_fnc; /* This function is called right before a command handler is called. */ gpg_error_t (*pre_cmd_notify_fnc)(assuan_context_t, const char *cmd); /* This function is called right after a command has been processed. It may be used to command related cleanup. */ void (*post_cmd_notify_fnc)(assuan_context_t, gpg_error_t); assuan_fd_t input_fd; /* Set by the INPUT command. */ assuan_fd_t output_fd; /* Set by the OUTPUT command. */ }; /* Generate an error code specific to a context. */ static GPG_ERR_INLINE gpg_error_t _assuan_error (assuan_context_t ctx, gpg_err_code_t errcode) { return gpg_err_make (ctx?ctx->err_source: GPG_ERR_SOURCE_ASSUAN, errcode); } /* Release all resources associated with an engine operation. */ void _assuan_reset (assuan_context_t ctx); /* Default log handler. */ int _assuan_log_handler (assuan_context_t ctx, void *hook, unsigned int cat, const char *msg); /* Manage memory specific to a context. */ void *_assuan_malloc (assuan_context_t ctx, size_t cnt); void *_assuan_realloc (assuan_context_t ctx, void *ptr, size_t cnt); void *_assuan_calloc (assuan_context_t ctx, size_t cnt, size_t elsize); void _assuan_free (assuan_context_t ctx, void *ptr); /* System hooks. */ void _assuan_usleep (assuan_context_t ctx, unsigned int usec); int _assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx); int _assuan_close (assuan_context_t ctx, assuan_fd_t fd); int _assuan_close_inheritable (assuan_context_t ctx, assuan_fd_t fd); ssize_t _assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size); ssize_t _assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer, size_t size); int _assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg, int flags); int _assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg, int flags); int _assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name, const char *argv[], assuan_fd_t fd_in, assuan_fd_t fd_out, assuan_fd_t *fd_child_list, void (*atfork) (void *opaque, int reserved), void *atforkvalue, unsigned int flags); pid_t _assuan_waitpid (assuan_context_t ctx, pid_t pid, int nowait, int *status, int options); int _assuan_socketpair (assuan_context_t ctx, int namespace, int style, int protocol, assuan_fd_t filedes[2]); assuan_fd_t _assuan_socket (assuan_context_t ctx, int namespace, int style, int protocol); int _assuan_connect (assuan_context_t ctx, assuan_fd_t sock, struct sockaddr *addr, socklen_t length); extern struct assuan_system_hooks _assuan_system_hooks; /* Copy the system hooks struct, paying attention to version differences. SRC is usually from the user, DST MUST be from the library. */ void _assuan_system_hooks_copy (assuan_system_hooks_t dst, assuan_system_hooks_t src); /*-- assuan-pipe-server.c --*/ void _assuan_release_context (assuan_context_t ctx); /*-- assuan-uds.c --*/ void _assuan_uds_close_fds (assuan_context_t ctx); void _assuan_uds_deinit (assuan_context_t ctx); void _assuan_init_uds_io (assuan_context_t ctx); /*-- assuan-handler.c --*/ gpg_error_t _assuan_register_std_commands (assuan_context_t ctx); /*-- assuan-buffer.c --*/ gpg_error_t _assuan_read_line (assuan_context_t ctx); int _assuan_cookie_write_data (void *cookie, const char *buffer, size_t size); int _assuan_cookie_write_flush (void *cookie); gpg_error_t _assuan_write_line (assuan_context_t ctx, const char *prefix, const char *line, size_t len); /*-- client.c --*/ gpg_error_t _assuan_read_from_server (assuan_context_t ctx, assuan_response_t *okay, int *off, int convey_comments); /*-- assuan-error.c --*/ /*-- assuan-inquire.c --*/ gpg_error_t _assuan_inquire_ext_cb (assuan_context_t ctx); void _assuan_inquire_release (assuan_context_t ctx); /* Check if ERR means EAGAIN. */ int _assuan_error_is_eagain (assuan_context_t ctx, gpg_error_t err); #define set_error(c,e,t) \ assuan_set_error ((c), _assuan_error (c,e), (t)) #ifdef HAVE_W32_SYSTEM char *_assuan_w32_strerror (assuan_context_t ctx, int ec); #endif /*HAVE_W32_SYSTEM*/ /*-- assuan-logging.c --*/ void _assuan_init_log_envvars (void); void _assuan_log_control_channel (assuan_context_t ctx, int outbound, const char *string, const void *buffer1, size_t length1, const void *buffer2, size_t length2); /*-- assuan-io.c --*/ ssize_t _assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size); ssize_t _assuan_simple_write (assuan_context_t ctx, const void *buffer, size_t size); /*-- assuan-socket.c --*/ assuan_fd_t _assuan_sock_new (assuan_context_t ctx, int domain, int type, int proto); int _assuan_sock_connect (assuan_context_t ctx, assuan_fd_t sockfd, struct sockaddr *addr, int addrlen); int _assuan_sock_bind (assuan_context_t ctx, assuan_fd_t sockfd, struct sockaddr *addr, int addrlen); int _assuan_sock_set_sockaddr_un (const char *fname, struct sockaddr *addr, int *r_redirected); int _assuan_sock_get_nonce (assuan_context_t ctx, struct sockaddr *addr, int addrlen, assuan_sock_nonce_t *nonce); int _assuan_sock_check_nonce (assuan_context_t ctx, assuan_fd_t fd, assuan_sock_nonce_t *nonce); #ifdef HAVE_W32_SYSTEM wchar_t *_assuan_utf8_to_wchar (const char *string); int _assuan_sock_wsa2errno (int err); #endif #ifdef HAVE_FOPENCOOKIE /* We have to implement funopen in terms of glibc's fopencookie. */ FILE *_assuan_funopen(void *cookie, cookie_read_function_t *readfn, cookie_write_function_t *writefn, cookie_seek_function_t *seekfn, cookie_close_function_t *closefn); #define funopen(a,r,w,s,c) _assuan_funopen ((a), (r), (w), (s), (c)) #endif /*HAVE_FOPENCOOKIE*/ /*-- sysutils.c --*/ const char *_assuan_sysutils_blurb (void); #ifdef HAVE_W32CE_SYSTEM #define getpid() GetCurrentProcessId () char *_assuan_getenv (const char *name); #define getenv(a) _assuan_getenv ((a)) #endif /*HAVE_W32CE_SYSTEM*/ /* Prototypes for replacement functions. */ #ifndef HAVE_MEMRCHR void *memrchr (const void *block, int c, size_t size); #endif #ifndef HAVE_STPCPY char *stpcpy (char *dest, const char *src); #endif #ifndef HAVE_SETENV #define setenv _assuan_setenv #define unsetenv _assuan_unsetenv #define clearenv _assuan_clearenv int setenv (const char *name, const char *value, int replace); #endif #ifndef HAVE_PUTC_UNLOCKED int putc_unlocked (int c, FILE *stream); #endif #define DIM(v) (sizeof(v)/sizeof((v)[0])) /* To avoid that a compiler optimizes memset calls away, these macros can be used. */ #define wipememory2(_ptr,_set,_len) do { \ volatile char *_vptr=(volatile char *)(_ptr); \ size_t _vlen=(_len); \ while(_vlen) { *_vptr=(_set); _vptr++; _vlen--; } \ } while(0) #define wipememory(_ptr,_len) wipememory2(_ptr,0,_len) #if HAVE_W64_SYSTEM # define SOCKET2HANDLE(s) ((void *)(s)) # define HANDLE2SOCKET(h) ((uintptr_t)(h)) #elif HAVE_W32_SYSTEM # define SOCKET2HANDLE(s) ((void *)(s)) # define HANDLE2SOCKET(h) ((unsigned int)(h)) #else # define SOCKET2HANDLE(s) (s) # define HANDLE2SOCKET(h) (h) #endif void _assuan_client_finish (assuan_context_t ctx); void _assuan_client_release (assuan_context_t ctx); void _assuan_server_finish (assuan_context_t ctx); void _assuan_server_release (assuan_context_t ctx); /* Encode the C formatted string SRC and return the malloc'ed result. */ char *_assuan_encode_c_string (assuan_context_t ctx, const char *src); void _assuan_pre_syscall (void); void _assuan_post_syscall (void); #endif /*ASSUAN_DEFS_H*/ diff --git a/src/client.c b/src/client.c index 24bf396..e0759f6 100644 --- a/src/client.c +++ b/src/client.c @@ -1,338 +1,348 @@ /* client.c - Functions common to all clients. * Copyright (C) 2009 Free Software Foundation, Inc. * * This file is part of Assuan. * * Assuan is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Assuan is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ */ #ifdef HAVE_CONFIG_H #include #endif #include #include "assuan-defs.h" #include "debug.h" #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) void _assuan_client_finish (assuan_context_t ctx) { if (ctx->inbound.fd != ASSUAN_INVALID_FD) { _assuan_close (ctx, ctx->inbound.fd); if (ctx->inbound.fd == ctx->outbound.fd) ctx->outbound.fd = ASSUAN_INVALID_FD; ctx->inbound.fd = ASSUAN_INVALID_FD; } if (ctx->outbound.fd != ASSUAN_INVALID_FD) { _assuan_close (ctx, ctx->outbound.fd); ctx->outbound.fd = ASSUAN_INVALID_FD; } if (ctx->pid != ASSUAN_INVALID_PID && ctx->pid) { _assuan_waitpid (ctx, ctx->pid, ctx->flags.no_waitpid, NULL, 0); ctx->pid = ASSUAN_INVALID_PID; } _assuan_uds_deinit (ctx); } /* Disconnect and release the context CTX. */ void _assuan_client_release (assuan_context_t ctx) { assuan_write_line (ctx, "BYE"); _assuan_client_finish (ctx); } /* This function also does deescaping for data lines. */ gpg_error_t assuan_client_read_response (assuan_context_t ctx, char **line_r, int *linelen_r) { gpg_error_t rc; char *line = NULL; int linelen = 0; *line_r = NULL; *linelen_r = 0; do { do { rc = _assuan_read_line (ctx); } while (_assuan_error_is_eagain (ctx, rc)); if (rc) return rc; line = ctx->inbound.line; linelen = ctx->inbound.linelen; } while (!linelen); /* For data lines, we deescape immediately. The user will never have to worry about it. */ if (linelen >= 1 && line[0] == 'D' && line[1] == ' ') { char *s, *d; for (s=d=line; linelen; linelen--) { if (*s == '%' && linelen > 2) { /* handle escaping */ s++; *d++ = xtoi_2 (s); s += 2; linelen -= 2; } else *d++ = *s++; } *d = 0; /* add a hidden string terminator */ linelen = d - line; ctx->inbound.linelen = linelen; } *line_r = line; *linelen_r = linelen; return 0; } gpg_error_t assuan_client_parse_response (assuan_context_t ctx, char *line, int linelen, assuan_response_t *response, int *off) { *response = ASSUAN_RESPONSE_ERROR; *off = 0; if (linelen >= 1 && line[0] == 'D' && line[1] == ' ') { *response = ASSUAN_RESPONSE_DATA; /* data line */ *off = 2; } else if (linelen >= 1 && line[0] == 'S' && (line[1] == '\0' || line[1] == ' ')) { *response = ASSUAN_RESPONSE_STATUS; *off = 1; while (line[*off] == ' ') ++*off; } else if (linelen >= 2 && line[0] == 'O' && line[1] == 'K' && (line[2] == '\0' || line[2] == ' ')) { *response = ASSUAN_RESPONSE_OK; *off = 2; while (line[*off] == ' ') ++*off; } else if (linelen >= 3 && line[0] == 'E' && line[1] == 'R' && line[2] == 'R' && (line[3] == '\0' || line[3] == ' ')) { *response = ASSUAN_RESPONSE_ERROR; *off = 3; while (line[*off] == ' ') ++*off; } else if (linelen >= 7 && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q' && line[3] == 'U' && line[4] == 'I' && line[5] == 'R' && line[6] == 'E' && (line[7] == '\0' || line[7] == ' ')) { *response = ASSUAN_RESPONSE_INQUIRE; *off = 7; while (line[*off] == ' ') ++*off; } else if (linelen >= 3 && line[0] == 'E' && line[1] == 'N' && line[2] == 'D' && (line[3] == '\0' || line[3] == ' ')) { *response = ASSUAN_RESPONSE_END; *off = 3; } else if (linelen >= 1 && line[0] == '#') { *response = ASSUAN_RESPONSE_COMMENT; *off = 1; } else return _assuan_error (ctx, GPG_ERR_ASS_INV_RESPONSE); return 0; } gpg_error_t _assuan_read_from_server (assuan_context_t ctx, assuan_response_t *response, int *off, int convey_comments) { gpg_error_t rc; char *line; int linelen; do { *response = ASSUAN_RESPONSE_ERROR; *off = 0; rc = assuan_client_read_response (ctx, &line, &linelen); if (!rc) rc = assuan_client_parse_response (ctx, line, linelen, response, off); } while (!rc && *response == ASSUAN_RESPONSE_COMMENT && !convey_comments); return rc; } /** * assuan_transact: * @ctx: The Assuan context * @command: Command line to be send to the server * @data_cb: Callback function for data lines * @data_cb_arg: first argument passed to @data_cb * @inquire_cb: Callback function for a inquire response * @inquire_cb_arg: first argument passed to @inquire_cb * @status_cb: Callback function for a status response * @status_cb_arg: first argument passed to @status_cb * * FIXME: Write documentation * * Return value: 0 on success or an error code. The error code may be * the one one returned by the server via error lines or from the * callback functions. Take care: If a callback returns an error * this function returns immediately with this error. **/ gpg_error_t assuan_transact (assuan_context_t ctx, const char *command, gpg_error_t (*data_cb)(void *, const void *, size_t), void *data_cb_arg, gpg_error_t (*inquire_cb)(void*, const char *), void *inquire_cb_arg, gpg_error_t (*status_cb)(void*, const char *), void *status_cb_arg) { gpg_error_t rc; assuan_response_t response; int off; char *line; int linelen; rc = assuan_write_line (ctx, command); if (rc) return rc; if (*command == '#' || !*command) return 0; /* Don't expect a response for a comment line. */ again: rc = _assuan_read_from_server (ctx, &response, &off, ctx->flags.convey_comments); if (rc) return rc; /* error reading from server */ line = ctx->inbound.line + off; linelen = ctx->inbound.linelen - off; if (response == ASSUAN_RESPONSE_ERROR) rc = atoi (line); else if (response == ASSUAN_RESPONSE_DATA) { if (!data_cb) rc = _assuan_error (ctx, GPG_ERR_ASS_NO_DATA_CB); else { rc = data_cb (data_cb_arg, line, linelen); if (ctx->flags.confidential) wipememory (ctx->inbound.line, LINELENGTH); if (!rc) goto again; } } else if (response == ASSUAN_RESPONSE_INQUIRE) { if (!inquire_cb) { assuan_write_line (ctx, "END"); /* get out of inquire mode */ _assuan_read_from_server (ctx, &response, &off, 0); /* dummy read */ rc = _assuan_error (ctx, GPG_ERR_ASS_NO_INQUIRE_CB); } else { + ctx->flags.confidential_inquiry = 0; + ctx->flags.in_inq_cb = 1; + rc = inquire_cb (inquire_cb_arg, line); if (!rc) rc = assuan_send_data (ctx, NULL, 0); /* flush and send END */ else { /* Flush and send CAN. */ /* Note that in this error case we don't want to return an error code from sending the cancel. The dummy read is to remove the response from the server which we are not interested in. */ assuan_send_data (ctx, NULL, 1); _assuan_read_from_server (ctx, &response, &off, 0); } + + if (ctx->flags.confidential_inquiry) + wipememory (ctx->outbound.data.line, LINELENGTH); + + ctx->flags.confidential_inquiry = 0; + ctx->flags.in_inq_cb = 0; + if (!rc) goto again; } } else if (response == ASSUAN_RESPONSE_STATUS) { if (status_cb) rc = status_cb (status_cb_arg, line); if (!rc) goto again; } else if (response == ASSUAN_RESPONSE_COMMENT && ctx->flags.convey_comments) { line -= off; /* Send line with the comment marker. */ if (status_cb) rc = status_cb (status_cb_arg, line); if (!rc) goto again; } else if (response == ASSUAN_RESPONSE_END) { if (!data_cb) rc = _assuan_error (ctx, GPG_ERR_ASS_NO_DATA_CB); else { rc = data_cb (data_cb_arg, NULL, 0); if (!rc) goto again; } } return rc; } diff --git a/src/context.c b/src/context.c index 82166bb..dd89de9 100644 --- a/src/context.c +++ b/src/context.c @@ -1,230 +1,232 @@ /* context.c - Context specific interface. * Copyright (C) 2009 Free Software Foundation, Inc. * * This file is part of Assuan. * * Assuan is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * Assuan is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . * SPDX-License-Identifier: LGPL-2.1+ */ #ifdef HAVE_CONFIG_H #include #endif #include "assuan-defs.h" #include "debug.h" /* Set user-data in a context. */ void assuan_set_pointer (assuan_context_t ctx, void *user_pointer) { TRACE1 (ctx, ASSUAN_LOG_CTX, "assuan_set_pointer", ctx, "user_pointer=%p", user_pointer); if (ctx) ctx->user_pointer = user_pointer; } /* Get user-data in a context. */ void * assuan_get_pointer (assuan_context_t ctx) { #if 0 /* This is called often. */ TRACE1 (ctx, ASSUAN_LOG_CTX, "assuan_get_pointer", ctx, "ctx->user_pointer=%p", ctx ? ctx->user_pointer : NULL); #endif if (! ctx) return NULL; return ctx->user_pointer; } /* For context CTX, set the flag FLAG to VALUE. Values for flags are usually 1 or 0 but certain flags might allow for other values; see the description of the type assuan_flag_t for details. */ void assuan_set_flag (assuan_context_t ctx, assuan_flag_t flag, int value) { TRACE2 (ctx, ASSUAN_LOG_CTX, "assuan_set_flag", ctx, "flag=%i,value=%i", flag, value); if (!ctx) return; switch (flag) { case ASSUAN_NO_WAITPID: ctx->flags.no_waitpid = value; break; case ASSUAN_CONFIDENTIAL: ctx->flags.confidential = value; + if (ctx->flags.in_inq_cb && value) + ctx->flags.confidential_inquiry = value; break; case ASSUAN_NO_FIXSIGNALS: ctx->flags.no_fixsignals = value; break; case ASSUAN_CONVEY_COMMENTS: ctx->flags.convey_comments = value; break; case ASSUAN_NO_LOGGING: ctx->flags.no_logging = value; break; case ASSUAN_FORCE_CLOSE: ctx->flags.force_close = 1; break; } } /* Return the VALUE of FLAG in context CTX. */ int assuan_get_flag (assuan_context_t ctx, assuan_flag_t flag) { int res = 0; TRACE_BEG1 (ctx, ASSUAN_LOG_CTX, "assuan_get_flag", ctx, "flag=%i", flag); if (! ctx) return 0; switch (flag) { case ASSUAN_NO_WAITPID: res = ctx->flags.no_waitpid; break; case ASSUAN_CONFIDENTIAL: res = ctx->flags.confidential; break; case ASSUAN_NO_FIXSIGNALS: res = ctx->flags.no_fixsignals; break; case ASSUAN_CONVEY_COMMENTS: res = ctx->flags.convey_comments; break; case ASSUAN_NO_LOGGING: res = ctx->flags.no_logging; break; case ASSUAN_FORCE_CLOSE: res = ctx->flags.force_close; break; } return TRACE_SUC1 ("flag_value=%i", res); } /* Same as assuan_set_flag (ctx, ASSUAN_CONFIDENTIAL, 1). */ void assuan_begin_confidential (assuan_context_t ctx) { assuan_set_flag (ctx, ASSUAN_CONFIDENTIAL, 1); } /* Same as assuan_set_flag (ctx, ASSUAN_CONFIDENTIAL, 0). */ void assuan_end_confidential (assuan_context_t ctx) { assuan_set_flag (ctx, ASSUAN_CONFIDENTIAL, 0); } /* Set the system callbacks. */ void assuan_ctx_set_system_hooks (assuan_context_t ctx, assuan_system_hooks_t system_hooks) { TRACE2 (ctx, ASSUAN_LOG_CTX, "assuan_set_system_hooks", ctx, "system_hooks=%p (version %i)", system_hooks, system_hooks->version); _assuan_system_hooks_copy (&ctx->system, system_hooks); } /* Set the IO monitor function. */ void assuan_set_io_monitor (assuan_context_t ctx, assuan_io_monitor_t io_monitor, void *hook_data) { TRACE2 (ctx, ASSUAN_LOG_CTX, "assuan_set_io_monitor", ctx, "io_monitor=%p,hook_data=%p", io_monitor, hook_data); if (! ctx) return; ctx->io_monitor = io_monitor; ctx->io_monitor_data = hook_data; } /* Store the error in the context so that the error sending function can take out a descriptive text. Inside the assuan code, use the macro set_error instead of this function. */ gpg_error_t assuan_set_error (assuan_context_t ctx, gpg_error_t err, const char *text) { TRACE4 (ctx, ASSUAN_LOG_CTX, "assuan_set_error", ctx, "err=%i (%s,%s),text=%s", err, gpg_strsource (err), gpg_strerror (err), text?text:"(none)"); ctx->err_no = err; ctx->err_str = text; return err; } /* Return the PID of the peer or ASSUAN_INVALID_PID if not known. This function works in some situations where assuan_get_ucred fails. */ pid_t assuan_get_pid (assuan_context_t ctx) { TRACE1 (ctx, ASSUAN_LOG_CTX, "assuan_get_pid", ctx, "pid=%i", ctx ? ctx->pid : -1); return (ctx && ctx->pid) ? ctx->pid : ASSUAN_INVALID_PID; } /* Return user credentials. For getting the pid of the peer the assuan_get_pid is usually better suited. */ gpg_error_t assuan_get_peercred (assuan_context_t ctx, assuan_peercred_t *peercred) { TRACE (ctx, ASSUAN_LOG_CTX, "assuan_get_peercred", ctx); if (!ctx) return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE); if (!ctx->peercred_valid) return _assuan_error (ctx, GPG_ERR_ASS_GENERAL); *peercred = &ctx->peercred; return 0; }