diff options
author | Marcus Brinkmann <[email protected]> | 2009-03-06 22:29:49 +0000 |
---|---|---|
committer | Marcus Brinkmann <[email protected]> | 2009-03-06 22:29:49 +0000 |
commit | 9ace1d56423f849b23fecdb77dd7ad6854975460 (patch) | |
tree | 212cfbddf9a9a640d597f2b39c993b166852e811 /assuan/assuan-socket.c | |
parent | Chnaged the op-assuan interface. (diff) | |
download | gpgme-9ace1d56423f849b23fecdb77dd7ad6854975460.tar.gz gpgme-9ace1d56423f849b23fecdb77dd7ad6854975460.zip |
assuan/
2009-03-06 Marcus Brinkmann <[email protected]>
* assuan/: Update to libassuan SVN 2009-03-06.
src/
2009-03-06 Marcus Brinkmann <[email protected]>
* version.c (do_subsystem_inits): Do not set assuan log level.
* debug.c (debug_init): Likewise.
Diffstat (limited to 'assuan/assuan-socket.c')
-rw-r--r-- | assuan/assuan-socket.c | 407 |
1 files changed, 349 insertions, 58 deletions
diff --git a/assuan/assuan-socket.c b/assuan/assuan-socket.c index 5566fdea..02a62253 100644 --- a/assuan/assuan-socket.c +++ b/assuan/assuan-socket.c @@ -14,20 +14,26 @@ * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. + * License along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <config.h> #include <stdio.h> +#include <stdlib.h> #ifdef HAVE_W32_SYSTEM +#define WIN32_LEAN_AND_MEAN #include <windows.h> +#include <wincrypt.h> #include <io.h> #else #include <sys/types.h> #include <sys/socket.h> #endif +#include <errno.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <assert.h> + #include "assuan-defs.h" /* Hacks for Slowaris. */ @@ -42,13 +48,114 @@ # define AF_LOCAL AF_UNIX #endif +#ifdef HAVE_W32_SYSTEM +#ifndef S_IRGRP +# define S_IRGRP 0 +# define S_IWGRP 0 +#endif +#endif + + +#ifdef HAVE_W32_SYSTEM +int +_assuan_sock_wsa2errno (int err) +{ + switch (err) + { + case WSAENOTSOCK: + return EINVAL; + case WSAEWOULDBLOCK: + return EAGAIN; + case ERROR_BROKEN_PIPE: + return EPIPE; + case WSANOTINITIALISED: + return ENOSYS; + default: + return EIO; + } +} + + +/* W32: Fill BUFFER with LENGTH bytes of random. Returns -1 on + failure, 0 on success. Sets errno on failure. */ +static int +get_nonce (char *buffer, size_t nbytes) +{ + HCRYPTPROV prov; + int ret = -1; + + if (!CryptAcquireContext (&prov, NULL, NULL, PROV_RSA_FULL, + (CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) ) + errno = ENODEV; + else + { + if (!CryptGenRandom (prov, nbytes, buffer)) + errno = ENODEV; + else + ret = 0; + CryptReleaseContext (prov, 0); + } + return ret; +} + + +/* W32: The buffer for NONCE needs to be at least 16 bytes. Returns 0 on + success and sets errno on failure. */ +static int +read_port_and_nonce (const char *fname, unsigned short *port, char *nonce) +{ + FILE *fp; + char buffer[50], *p; + size_t nread; + int aval; + + fp = fopen (fname, "rb"); + if (!fp) + return -1; + nread = fread (buffer, 1, sizeof buffer - 1, fp); + fclose (fp); + if (!nread) + { + errno = ENOFILE; + return -1; + } + buffer[nread] = 0; + aval = atoi (buffer); + if (aval < 1 || aval > 65535) + { + errno = EINVAL; + return -1; + } + *port = (unsigned int)aval; + for (p=buffer; nread && *p != '\n'; p++, nread--) + ; + if (*p != '\n' || nread != 17) + { + errno = EINVAL; + return -1; + } + p++; nread--; + memcpy (nonce, p, 16); + return 0; +} +#endif /*HAVE_W32_SYSTEM*/ + + + int -_assuan_close (int fd) +_assuan_close (assuan_fd_t fd) { #if defined (HAVE_W32_SYSTEM) && !defined(_ASSUAN_IN_GPGME_BUILD_ASSUAN) - int rc = closesocket (fd); + int rc = closesocket (HANDLE2SOCKET(fd)); + if (rc) + errno = _assuan_sock_wsa2errno (WSAGetLastError ()); if (rc && WSAGetLastError () == WSAENOTSOCK) - rc = CloseHandle (fd); + { + rc = CloseHandle (fd); + if (rc) + /* FIXME. */ + errno = EIO; + } return rc; #else return close (fd); @@ -56,93 +163,277 @@ _assuan_close (int fd) } -int +/* Return a new socket. Note that under W32 we consider a socket the + same as an System Handle; all functions using such a handle know + about this dual use and act accordingly. */ +assuan_fd_t _assuan_sock_new (int domain, int type, int proto) { -#ifndef HAVE_W32_SYSTEM - return socket (domain, type, proto); -#else +#ifdef HAVE_W32_SYSTEM + assuan_fd_t res; if (domain == AF_UNIX || domain == AF_LOCAL) domain = AF_INET; + res = SOCKET2HANDLE(socket (domain, type, proto)); + if (res == ASSUAN_INVALID_FD) + errno = _assuan_sock_wsa2errno (WSAGetLastError ()); + return res; +#else return socket (domain, type, proto); #endif } int -_assuan_sock_connect (int sockfd, struct sockaddr * addr, int addrlen) +_assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen) { -#ifndef HAVE_W32_SYSTEM - return connect (sockfd, addr, addrlen); -#else - struct sockaddr_in myaddr; - struct sockaddr_un * unaddr; - FILE * fp; - int port = 0; - - unaddr = (struct sockaddr_un *)addr; - fp = fopen (unaddr->sun_path, "rb"); - if (!fp) - return -1; - fscanf (fp, "%d", &port); - fclose (fp); - /* XXX: set errno in this case */ - if (port < 0 || port > 65535) - return -1; +#ifdef HAVE_W32_SYSTEM + if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX) + { + struct sockaddr_in myaddr; + struct sockaddr_un *unaddr; + unsigned short port; + char nonce[16]; + int ret; + + unaddr = (struct sockaddr_un *)addr; + if (read_port_and_nonce (unaddr->sun_path, &port, nonce)) + return -1; + + myaddr.sin_family = AF_INET; + myaddr.sin_port = htons (port); + myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - myaddr.sin_family = AF_INET; - myaddr.sin_port = port; - myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - - /* we need this later. */ - unaddr->sun_family = myaddr.sin_family; - unaddr->sun_port = myaddr.sin_port; - unaddr->sun_addr.s_addr = myaddr.sin_addr.s_addr; + /* Set return values. */ + unaddr->sun_family = myaddr.sin_family; + unaddr->sun_port = myaddr.sin_port; + unaddr->sun_addr.s_addr = myaddr.sin_addr.s_addr; - return connect (sockfd, (struct sockaddr *)&myaddr, sizeof myaddr); + ret = connect (HANDLE2SOCKET(sockfd), + (struct sockaddr *)&myaddr, sizeof myaddr); + if (!ret) + { + /* Send the nonce. */ + ret = _assuan_io_write (sockfd, nonce, 16); + if (ret >= 0 && ret != 16) + { + errno = EIO; + ret = -1; + } + } + return ret; + } + else + { + int res; + res = connect (HANDLE2SOCKET (sockfd), addr, addrlen); + if (res < 0) + errno = _assuan_sock_wsa2errno (WSAGetLastError ()); + return res; + } +#else + return connect (sockfd, addr, addrlen); #endif } int -_assuan_sock_bind (int sockfd, struct sockaddr * addr, int addrlen) +_assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen) { -#ifndef HAVE_W32_SYSTEM - return bind (sockfd, addr, addrlen); -#else +#ifdef HAVE_W32_SYSTEM if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX) { struct sockaddr_in myaddr; - struct sockaddr_un * unaddr; - FILE * fp; + struct sockaddr_un *unaddr; + int filefd; + FILE *fp; int len = sizeof myaddr; int rc; + char nonce[16]; + + if (get_nonce (nonce, 16)) + return -1; + + unaddr = (struct sockaddr_un *)addr; myaddr.sin_port = 0; myaddr.sin_family = AF_INET; myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - rc = bind (sockfd, (struct sockaddr *)&myaddr, len); - if (rc) - return rc; - rc = getsockname (sockfd, (struct sockaddr *)&myaddr, &len); - if (rc) - return rc; - unaddr = (struct sockaddr_un *)addr; - fp = fopen (unaddr->sun_path, "wb"); + filefd = open (unaddr->sun_path, + (O_WRONLY|O_CREAT|O_EXCL|O_BINARY), + (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)); + if (filefd == -1) + { + if (errno == EEXIST) + errno = WSAEADDRINUSE; + return -1; + } + fp = fdopen (filefd, "wb"); if (!fp) - return -1; - fprintf (fp, "%d", myaddr.sin_port); + { + int save_e = errno; + close (filefd); + errno = save_e; + return -1; + } + + rc = bind (HANDLE2SOCKET (sockfd), (struct sockaddr *)&myaddr, len); + if (!rc) + rc = getsockname (HANDLE2SOCKET (sockfd), + (struct sockaddr *)&myaddr, &len); + if (rc) + { + int save_e = errno; + fclose (fp); + remove (unaddr->sun_path); + errno = save_e; + return rc; + } + fprintf (fp, "%d\n", ntohs (myaddr.sin_port)); + fwrite (nonce, 16, 1, fp); fclose (fp); - /* we need this later. */ - unaddr->sun_family = myaddr.sin_family; - unaddr->sun_port = myaddr.sin_port; - unaddr->sun_addr.s_addr = myaddr.sin_addr.s_addr; - return 0; } + else + { + int res = bind (HANDLE2SOCKET(sockfd), addr, addrlen); + if (res < 0) + errno = _assuan_sock_wsa2errno (WSAGetLastError ()); + return res; + } +#else return bind (sockfd, addr, addrlen); #endif } + +int +_assuan_sock_get_nonce (struct sockaddr *addr, int addrlen, + assuan_sock_nonce_t *nonce) +{ +#ifdef HAVE_W32_SYSTEM + if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX) + { + struct sockaddr_un *unaddr; + unsigned short port; + + if (sizeof nonce->nonce != 16) + { + errno = EINVAL; + return -1; + } + nonce->length = 16; + unaddr = (struct sockaddr_un *)addr; + if (read_port_and_nonce (unaddr->sun_path, &port, nonce->nonce)) + return -1; + } + else + { + nonce->length = 42; /* Arbitrary valuie to detect unitialized nonce. */ + nonce->nonce[0] = 42; + } +#else + (void)addr; + (void)addrlen; + nonce->length = 0; +#endif + return 0; +} + + +int +_assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce) +{ +#ifdef HAVE_W32_SYSTEM + char buffer[16], *p; + size_t nleft; + int n; + + if (sizeof nonce->nonce != 16) + { + errno = EINVAL; + return -1; + } + + if (nonce->length == 42 && nonce->nonce[0] == 42) + return 0; /* Not a Unix domain socket. */ + + if (nonce->length != 16) + { + errno = EINVAL; + return -1; + } + + p = buffer; + nleft = 16; + while (nleft) + { + n = _assuan_io_read (SOCKET2HANDLE(fd), p, nleft); + if (n < 0 && errno == EINTR) + ; + else if (n < 0 && errno == EAGAIN) + Sleep (100); + else if (n < 0) + return -1; + else if (!n) + { + errno = EIO; + return -1; + } + else + { + p += n; + nleft -= n; + } + } + if (memcmp (buffer, nonce->nonce, 16)) + { + errno = EACCES; + return -1; + } +#else + (void)fd; + (void)nonce; +#endif + return 0; +} + + +/* Public API. */ +int +assuan_sock_close (assuan_fd_t fd) +{ + return _assuan_close (fd); +} + +assuan_fd_t +assuan_sock_new (int domain, int type, int proto) +{ + return _assuan_sock_new (domain, type, proto); +} + +int +assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen) +{ + return _assuan_sock_connect (sockfd, addr, addrlen); +} + +int +assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen) +{ + return _assuan_sock_bind (sockfd, addr, addrlen); +} + +int +assuan_sock_get_nonce (struct sockaddr *addr, int addrlen, + assuan_sock_nonce_t *nonce) +{ + return _assuan_sock_get_nonce (addr, addrlen, nonce); +} + +int +assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce) +{ + return _assuan_sock_check_nonce (fd, nonce); +} |