aboutsummaryrefslogtreecommitdiffstats
path: root/assuan/assuan-socket.c
diff options
context:
space:
mode:
authorMarcus Brinkmann <[email protected]>2009-03-06 22:29:49 +0000
committerMarcus Brinkmann <[email protected]>2009-03-06 22:29:49 +0000
commit9ace1d56423f849b23fecdb77dd7ad6854975460 (patch)
tree212cfbddf9a9a640d597f2b39c993b166852e811 /assuan/assuan-socket.c
parentChnaged the op-assuan interface. (diff)
downloadgpgme-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.c407
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);
+}