Fixed a segfault during an SSH connection failure.
[libpwmd.git] / assuan / assuan-socket.c
blob044b1f1c565e3e6185f3e11f14ec664d6b3adafd
1 /* assuan-socket.c
2 * Copyright (C) 2004, 2005 Free Software Foundation, Inc.
4 * This file is part of Assuan.
6 * Assuan is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
11 * Assuan is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #ifdef HAVE_W32_SYSTEM
24 #define WIN32_LEAN_AND_MEAN
25 #include <windows.h>
26 #include <wincrypt.h>
27 #include <io.h>
28 #else
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #endif
32 #include <errno.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <assert.h>
37 #include "assuan-defs.h"
39 /* Hacks for Slowaris. */
40 #ifndef PF_LOCAL
41 # ifdef PF_UNIX
42 # define PF_LOCAL PF_UNIX
43 # else
44 # define PF_LOCAL AF_UNIX
45 # endif
46 #endif
47 #ifndef AF_LOCAL
48 # define AF_LOCAL AF_UNIX
49 #endif
51 #ifdef HAVE_W32_SYSTEM
52 #ifndef S_IRGRP
53 # define S_IRGRP 0
54 # define S_IWGRP 0
55 #endif
56 #endif
59 #ifdef HAVE_W32_SYSTEM
60 int
61 _assuan_sock_wsa2errno (int err)
63 switch (err)
65 case WSAENOTSOCK:
66 return EINVAL;
67 case WSAEWOULDBLOCK:
68 return EAGAIN;
69 case ERROR_BROKEN_PIPE:
70 return EPIPE;
71 case WSANOTINITIALISED:
72 return ENOSYS;
73 default:
74 return EIO;
79 /* W32: Fill BUFFER with LENGTH bytes of random. Returns -1 on
80 failure, 0 on success. Sets errno on failure. */
81 static int
82 get_nonce (char *buffer, size_t nbytes)
84 HCRYPTPROV prov;
85 int ret = -1;
87 if (!CryptAcquireContext (&prov, NULL, NULL, PROV_RSA_FULL,
88 (CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) )
89 errno = ENODEV;
90 else
92 if (!CryptGenRandom (prov, nbytes, buffer))
93 errno = ENODEV;
94 else
95 ret = 0;
96 CryptReleaseContext (prov, 0);
98 return ret;
102 /* W32: The buffer for NONCE needs to be at least 16 bytes. Returns 0 on
103 success and sets errno on failure. */
104 static int
105 read_port_and_nonce (const char *fname, unsigned short *port, char *nonce)
107 FILE *fp;
108 char buffer[50], *p;
109 size_t nread;
110 int aval;
112 fp = fopen (fname, "rb");
113 if (!fp)
114 return -1;
115 nread = fread (buffer, 1, sizeof buffer - 1, fp);
116 fclose (fp);
117 if (!nread)
119 errno = ENOFILE;
120 return -1;
122 buffer[nread] = 0;
123 aval = atoi (buffer);
124 if (aval < 1 || aval > 65535)
126 errno = EINVAL;
127 return -1;
129 *port = (unsigned int)aval;
130 for (p=buffer; nread && *p != '\n'; p++, nread--)
132 if (*p != '\n' || nread != 17)
134 errno = EINVAL;
135 return -1;
137 p++; nread--;
138 memcpy (nonce, p, 16);
139 return 0;
141 #endif /*HAVE_W32_SYSTEM*/
146 _assuan_close (assuan_fd_t fd)
148 #ifdef HAVE_W32_SYSTEM
149 int rc = closesocket (HANDLE2SOCKET(fd));
150 if (rc)
151 errno = _assuan_sock_wsa2errno (WSAGetLastError ());
152 if (rc && WSAGetLastError () == WSAENOTSOCK)
154 rc = CloseHandle (fd);
155 if (rc)
156 /* FIXME. */
157 errno = EIO;
159 return rc;
160 #else
161 return close (fd);
162 #endif
166 /* Return a new socket. Note that under W32 we consider a socket the
167 same as an System Handle; all functions using such a handle know
168 about this dual use and act accordingly. */
169 assuan_fd_t
170 _assuan_sock_new (int domain, int type, int proto)
172 #ifdef HAVE_W32_SYSTEM
173 assuan_fd_t res;
174 if (domain == AF_UNIX || domain == AF_LOCAL)
175 domain = AF_INET;
176 res = SOCKET2HANDLE(socket (domain, type, proto));
177 if (res == ASSUAN_INVALID_FD)
178 errno = _assuan_sock_wsa2errno (WSAGetLastError ());
179 return res;
180 #else
181 return socket (domain, type, proto);
182 #endif
187 _assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
189 #ifdef HAVE_W32_SYSTEM
190 if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX)
192 struct sockaddr_in myaddr;
193 struct sockaddr_un *unaddr;
194 unsigned short port;
195 char nonce[16];
196 int ret;
198 unaddr = (struct sockaddr_un *)addr;
199 if (read_port_and_nonce (unaddr->sun_path, &port, nonce))
200 return -1;
202 myaddr.sin_family = AF_INET;
203 myaddr.sin_port = htons (port);
204 myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
206 /* Set return values. */
207 unaddr->sun_family = myaddr.sin_family;
208 unaddr->sun_port = myaddr.sin_port;
209 unaddr->sun_addr.s_addr = myaddr.sin_addr.s_addr;
211 ret = connect (HANDLE2SOCKET(sockfd),
212 (struct sockaddr *)&myaddr, sizeof myaddr);
213 if (!ret)
215 /* Send the nonce. */
216 ret = _assuan_io_write (sockfd, nonce, 16);
217 if (ret >= 0 && ret != 16)
219 errno = EIO;
220 ret = -1;
223 return ret;
225 else
227 int res;
228 res = connect (HANDLE2SOCKET (sockfd), addr, addrlen);
229 if (res < 0)
230 errno = _assuan_sock_wsa2errno (WSAGetLastError ());
231 return res;
233 #else
234 return connect (sockfd, addr, addrlen);
235 #endif
240 _assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
242 #ifdef HAVE_W32_SYSTEM
243 if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX)
245 struct sockaddr_in myaddr;
246 struct sockaddr_un *unaddr;
247 int filefd;
248 FILE *fp;
249 int len = sizeof myaddr;
250 int rc;
251 char nonce[16];
253 if (get_nonce (nonce, 16))
254 return -1;
256 unaddr = (struct sockaddr_un *)addr;
258 myaddr.sin_port = 0;
259 myaddr.sin_family = AF_INET;
260 myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
262 filefd = open (unaddr->sun_path,
263 (O_WRONLY|O_CREAT|O_EXCL|O_BINARY),
264 (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP));
265 if (filefd == -1)
267 if (errno == EEXIST)
268 errno = WSAEADDRINUSE;
269 return -1;
271 fp = fdopen (filefd, "wb");
272 if (!fp)
274 int save_e = errno;
275 close (filefd);
276 errno = save_e;
277 return -1;
280 rc = bind (HANDLE2SOCKET (sockfd), (struct sockaddr *)&myaddr, len);
281 if (!rc)
282 rc = getsockname (HANDLE2SOCKET (sockfd),
283 (struct sockaddr *)&myaddr, &len);
284 if (rc)
286 int save_e = errno;
287 fclose (fp);
288 remove (unaddr->sun_path);
289 errno = save_e;
290 return rc;
292 fprintf (fp, "%d\n", ntohs (myaddr.sin_port));
293 fwrite (nonce, 16, 1, fp);
294 fclose (fp);
296 return 0;
298 else
300 int res = bind (HANDLE2SOCKET(sockfd), addr, addrlen);
301 if (res < 0)
302 errno = _assuan_sock_wsa2errno (WSAGetLastError ());
303 return res;
305 #else
306 return bind (sockfd, addr, addrlen);
307 #endif
312 _assuan_sock_get_nonce (struct sockaddr *addr, int addrlen,
313 assuan_sock_nonce_t *nonce)
315 #ifdef HAVE_W32_SYSTEM
316 if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX)
318 struct sockaddr_un *unaddr;
319 unsigned short port;
321 if (sizeof nonce->nonce != 16)
323 errno = EINVAL;
324 return -1;
326 nonce->length = 16;
327 unaddr = (struct sockaddr_un *)addr;
328 if (read_port_and_nonce (unaddr->sun_path, &port, nonce->nonce))
329 return -1;
331 else
333 nonce->length = 42; /* Arbitrary valuie to detect unitialized nonce. */
334 nonce->nonce[0] = 42;
336 #else
337 (void)addr;
338 (void)addrlen;
339 nonce->length = 0;
340 #endif
341 return 0;
346 _assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce)
348 #ifdef HAVE_W32_SYSTEM
349 char buffer[16], *p;
350 size_t nleft;
351 int n;
353 if (sizeof nonce->nonce != 16)
355 errno = EINVAL;
356 return -1;
359 if (nonce->length == 42 && nonce->nonce[0] == 42)
360 return 0; /* Not a Unix domain socket. */
362 if (nonce->length != 16)
364 errno = EINVAL;
365 return -1;
368 p = buffer;
369 nleft = 16;
370 while (nleft)
372 n = _assuan_io_read (SOCKET2HANDLE(fd), p, nleft);
373 if (n < 0 && errno == EINTR)
375 else if (n < 0 && errno == EAGAIN)
376 Sleep (100);
377 else if (n < 0)
378 return -1;
379 else if (!n)
381 errno = EIO;
382 return -1;
384 else
386 p += n;
387 nleft -= n;
390 if (memcmp (buffer, nonce->nonce, 16))
392 errno = EACCES;
393 return -1;
395 #else
396 (void)fd;
397 (void)nonce;
398 #endif
399 return 0;
403 /* Public API. */
405 assuan_sock_close (assuan_fd_t fd)
407 return _assuan_close (fd);
410 assuan_fd_t
411 assuan_sock_new (int domain, int type, int proto)
413 return _assuan_sock_new (domain, type, proto);
417 assuan_sock_connect (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
419 return _assuan_sock_connect (sockfd, addr, addrlen);
423 assuan_sock_bind (assuan_fd_t sockfd, struct sockaddr *addr, int addrlen)
425 return _assuan_sock_bind (sockfd, addr, addrlen);
429 assuan_sock_get_nonce (struct sockaddr *addr, int addrlen,
430 assuan_sock_nonce_t *nonce)
432 return _assuan_sock_get_nonce (addr, addrlen, nonce);
436 assuan_sock_check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce)
438 return _assuan_sock_check_nonce (fd, nonce);