diff options
Diffstat (limited to '')
-rw-r--r-- | src/ChangeLog | 22 | ||||
-rw-r--r-- | src/assuan-buffer.c | 20 | ||||
-rw-r--r-- | src/assuan-defs.h | 8 | ||||
-rw-r--r-- | src/assuan-domain-connect.c | 121 | ||||
-rw-r--r-- | src/assuan-handler.c | 35 | ||||
-rw-r--r-- | src/assuan-pipe-server.c | 3 | ||||
-rw-r--r-- | src/assuan.h | 6 |
7 files changed, 194 insertions, 21 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index eeb286d..c88d884 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,25 @@ +2002-11-24 Neal H. Walfield <[email protected]> + + * assuan.h (assuan_sendfd): New prototype. + (assuan_receivefd): New prototype. + * assuan-buffer.c (assuan_sendfd): New function. + (assuan_receivefd): New function. + * assuan-handler.c (parse_cmd_input_output): Recognize incoming + file descriptors and act appropriately. + * assuan-defs.h (struct assuan_io): Add fields sendfd and + receivefd. + (struct assuan_context_s): Add fields pendingfds and + pendingfdscount. + * assuan-pipe-server.c (_assuan_new_context): Update IO to reflect + new features. + * assuan-domain-connect.c (do_deinit): Cleanup any unreceived file + descriptors. + (domain_reader): Receive file descriptors. + (domain_sendfd): New function. + (domain_receivefd): New function. + (_assuan_domain_init): Update initialization code to reflect new + features. + 2002-11-24 Neal H. Walfield <[email protected]> * assuan-domain-connect.c (do_finish): Remove. diff --git a/src/assuan-buffer.c b/src/assuan-buffer.c index 8ccd3bd..bbe3990 100644 --- a/src/assuan-buffer.c +++ b/src/assuan-buffer.c @@ -437,3 +437,23 @@ assuan_send_data (ASSUAN_CONTEXT ctx, const void *buffer, size_t length) return 0; } + +AssuanError +assuan_sendfd (ASSUAN_CONTEXT ctx, int fd) +{ + if (! ctx->io->sendfd) + return set_error (ctx, Not_Implemented, + "server does not support sending and receiving " + "of file descriptors"); + return ctx->io->sendfd (ctx, fd); +} + +AssuanError +assuan_receivefd (ASSUAN_CONTEXT ctx, int *fd) +{ + if (! ctx->io->receivefd) + return set_error (ctx, Not_Implemented, + "server does not support sending and receiving " + "of file descriptors"); + return ctx->io->receivefd (ctx, fd); +} diff --git a/src/assuan-defs.h b/src/assuan-defs.h index 6e11bbb..5766024 100644 --- a/src/assuan-defs.h +++ b/src/assuan-defs.h @@ -43,6 +43,10 @@ struct assuan_io ssize_t (*read) (ASSUAN_CONTEXT, void *, size_t); /* Routine to write to output_fd. */ ssize_t (*write) (ASSUAN_CONTEXT, const void *, size_t); + /* Send a file descriptor. */ + AssuanError (*sendfd) (ASSUAN_CONTEXT, int); + /* Receive a file descriptor. */ + AssuanError (*receivefd) (ASSUAN_CONTEXT, int *); }; struct assuan_context_s @@ -109,6 +113,9 @@ struct assuan_context_s /* Memory allocated. */ int domainbufferallocated; + int *pendingfds; + int pendingfdscount; + void (*deinit_handler)(ASSUAN_CONTEXT); int (*accept_handler)(ASSUAN_CONTEXT); int (*finish_handler)(ASSUAN_CONTEXT); @@ -176,6 +183,5 @@ ssize_t _assuan_simple_read (ASSUAN_CONTEXT ctx, void *buffer, size_t size); ssize_t _assuan_simple_write (ASSUAN_CONTEXT ctx, const void *buffer, size_t size); - #endif /*ASSUAN_DEFS_H*/ diff --git a/src/assuan-domain-connect.c b/src/assuan-domain-connect.c index d50ba1e..b4ce519 100644 --- a/src/assuan-domain-connect.c +++ b/src/assuan-domain-connect.c @@ -63,6 +63,17 @@ do_deinit (ASSUAN_CONTEXT ctx) free (ctx->domainbuffer); } + if (ctx->pendingfds) + { + int i; + + assert (ctx->pendingfdscount > 0); + for (i = 0; i < ctx->pendingfdscount; i ++) + close (ctx->pendingfds[i]); + + free (ctx->pendingfds); + } + unlink (ctx->myaddr.sun_path); } @@ -80,6 +91,11 @@ domain_reader (ASSUAN_CONTEXT ctx, void *buf, size_t buflen) struct msghdr msg; struct iovec iovec; struct sockaddr_un sender; + struct + { + struct cmsghdr hdr; + int fd; + } cmsg; memset (&msg, 0, sizeof (msg)); @@ -91,8 +107,8 @@ domain_reader (ASSUAN_CONTEXT ctx, void *buf, size_t buflen) msg.msg_iovlen = 1; iovec.iov_base = ctx->domainbuffer; iovec.iov_len = ctx->domainbufferallocated; - msg.msg_control = 0; - msg.msg_controllen = 0; + msg.msg_control = &cmsg; + msg.msg_controllen = sizeof cmsg; /* Peek first: if the buffer we have is too small then it will be truncated. */ @@ -144,8 +160,8 @@ domain_reader (ASSUAN_CONTEXT ctx, void *buf, size_t buflen) msg.msg_iovlen = 1; iovec.iov_base = ctx->domainbuffer; iovec.iov_len = ctx->domainbufferallocated; - msg.msg_control = 0; - msg.msg_controllen = 0; + msg.msg_control = &cmsg; + msg.msg_controllen = sizeof cmsg; if (strcmp (ctx->serveraddr.sun_path, ((struct sockaddr_un *) msg.msg_name)->sun_path) != 0) @@ -167,6 +183,30 @@ domain_reader (ASSUAN_CONTEXT ctx, void *buf, size_t buflen) ctx->domainbuffersize = len; ctx->domainbufferoffset = 0; + + if (sizeof (cmsg) == msg.msg_controllen) + /* We received a file descriptor. */ + { + void *tmp; + + tmp = realloc (ctx->pendingfds, + sizeof (int) * (ctx->pendingfdscount + 1)); + if (! tmp) + { + LOGERROR1 ("domain_reader: %s\n", strerror (errno)); + return -1; + } + + ctx->pendingfds = tmp; + ctx->pendingfds[ctx->pendingfdscount ++] + = * (int *) CMSG_DATA (&cmsg.hdr); + + LOGERROR1 ("Received file descriptor %d from peer.\n", + ctx->pendingfds[ctx->pendingfdscount - 1]); + } + + if (len == 0) + goto start; } /* Return some data to the user. */ @@ -212,6 +252,74 @@ domain_writer (ASSUAN_CONTEXT ctx, const void *buf, size_t buflen) return len; } +static AssuanError +domain_sendfd (ASSUAN_CONTEXT ctx, int fd) +{ + struct msghdr msg; + struct + { + struct cmsghdr hdr; + int fd; + } cmsg; + int len; + + memset (&msg, 0, sizeof (msg)); + + msg.msg_name = &ctx->serveraddr; + msg.msg_namelen = offsetof (struct sockaddr_un, sun_path) + + strlen (ctx->serveraddr.sun_path) + 1; + + msg.msg_iovlen = 0; + msg.msg_iov = 0; + + cmsg.hdr.cmsg_level = SOL_SOCKET; + cmsg.hdr.cmsg_type = SCM_RIGHTS; + cmsg.hdr.cmsg_len = sizeof (cmsg); + + msg.msg_control = &cmsg; + msg.msg_controllen = sizeof (cmsg); + + * (int *) CMSG_DATA (&cmsg.hdr) = fd; + + len = sendmsg (ctx->outbound.fd, &msg, 0); + if (len < 0) + { + LOGERROR1 ("domain_sendfd: %s\n", strerror (errno)); + return ASSUAN_General_Error; + } + else + return 0; +} + +static AssuanError +domain_receivefd (ASSUAN_CONTEXT ctx, int *fd) +{ + if (ctx->pendingfds == 0) + { + LOGERROR ("No pending file descriptors!\n"); + return ASSUAN_General_Error; + } + + *fd = ctx->pendingfds[0]; + if (-- ctx->pendingfdscount == 0) + { + free (ctx->pendingfds); + ctx->pendingfds = 0; + } + else + /* Fix the array. */ + { + memmove (ctx->pendingfds, ctx->pendingfds + 1, + ctx->pendingfdscount * sizeof (int)); + ctx->pendingfds = realloc (ctx->pendingfds, + ctx->pendingfdscount * sizeof (int)); + } + + return 0; +} + + + /* 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. */ @@ -220,7 +328,8 @@ _assuan_domain_init (ASSUAN_CONTEXT *r_ctx, int rendezvousfd, pid_t peer) { - static struct assuan_io io = { domain_reader, domain_writer }; + static struct assuan_io io = { domain_reader, domain_writer, + domain_sendfd, domain_receivefd }; AssuanError err; ASSUAN_CONTEXT ctx; @@ -262,6 +371,8 @@ _assuan_domain_init (ASSUAN_CONTEXT *r_ctx, ctx->domainbufferoffset = 0; ctx->domainbuffersize = 0; ctx->domainbufferallocated = 0; + ctx->pendingfds = 0; + ctx->pendingfdscount = 0; /* Get usable name and bind to it. */ diff --git a/src/assuan-handler.c b/src/assuan-handler.c index 6ddfe88..16838b2 100644 --- a/src/assuan-handler.c +++ b/src/assuan-handler.c @@ -154,20 +154,27 @@ parse_cmd_input_output (ASSUAN_CONTEXT ctx, char *line, int *rfd) { char *endp; - if (strncmp (line, "FD=", 3)) - return set_error (ctx, Syntax_Error, "FD=<n> expected"); - line += 3; - if (!digitp (*line)) - return set_error (ctx, Syntax_Error, "number required"); - *rfd = strtoul (line, &endp, 10); - /* remove that argument so that a notify handler won't see it */ - memset (line, ' ', endp? (endp-line):strlen(line)); - - if (*rfd == ctx->inbound.fd) - return set_error (ctx, Parameter_Conflict, "fd same as inbound fd"); - if (*rfd == ctx->outbound.fd) - return set_error (ctx, Parameter_Conflict, "fd same as outbound fd"); - return 0; + if (strncmp (line, "FD", 2) != 0 || (line[2] != '=' && line[2] != '\0')) + return set_error (ctx, Syntax_Error, "FD[=<n>] expected"); + line += 2; + if (*line == '=') + { + line ++; + if (!digitp (*line)) + return set_error (ctx, Syntax_Error, "number required"); + *rfd = strtoul (line, &endp, 10); + /* remove that argument so that a notify handler won't see it */ + memset (line, ' ', endp? (endp-line):strlen(line)); + + if (*rfd == ctx->inbound.fd) + return set_error (ctx, Parameter_Conflict, "fd same as inbound fd"); + if (*rfd == ctx->outbound.fd) + return set_error (ctx, Parameter_Conflict, "fd same as outbound fd"); + return 0; + } + else + /* Our peer has sent the file descriptor. */ + return assuan_receivefd (ctx, rfd); } /* Format is INPUT FD=<n> */ diff --git a/src/assuan-pipe-server.c b/src/assuan-pipe-server.c index a0bb3bd..ba269b0 100644 --- a/src/assuan-pipe-server.c +++ b/src/assuan-pipe-server.c @@ -51,7 +51,8 @@ int _assuan_new_context (ASSUAN_CONTEXT *r_ctx) { static struct assuan_io io = { _assuan_simple_read, - _assuan_simple_write }; + _assuan_simple_write, + 0, 0 }; ASSUAN_CONTEXT ctx; int rc; diff --git a/src/assuan.h b/src/assuan.h index 1972702..59cb153 100644 --- a/src/assuan.h +++ b/src/assuan.h @@ -229,6 +229,12 @@ AssuanError assuan_write_line (ASSUAN_CONTEXT ctx, const char *line ); AssuanError assuan_send_data (ASSUAN_CONTEXT ctx, const void *buffer, size_t length); +/* The file descriptor must be pending before assuan_receivefd is + call. This means that assuan_sendfd should be called *before* the + trigger is sent (normally via assuan_send_data ("I sent you a + descriptor")). */ +AssuanError assuan_sendfd (ASSUAN_CONTEXT ctx, int fd); +AssuanError assuan_receivefd (ASSUAN_CONTEXT ctx, int *fd); /*-- assuan-util.c --*/ void assuan_set_malloc_hooks ( void *(*new_alloc_func)(size_t n), |