No need for getline.h.
[shishi.git] / lib / netio.c
blobb1e3904dcf7e1b91c367c18c77f863292138e8b5
1 /* netio.c --- Network I/O functions.
2 * Copyright (C) 2002, 2003, 2004, 2006, 2007 Simon Josefsson
4 * This file is part of Shishi.
6 * Shishi is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * Shishi 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
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Shishi; if not, see http://www.gnu.org/licenses or write
18 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
19 * Floor, Boston, MA 02110-1301, USA
23 #include "internal.h"
25 /* Get _shishi_sendrecv_tls, etc. */
26 #include "starttls.h"
28 /* Get _shishi_realminfo, etc. */
29 #include "diskio.h"
31 /* Get _shishi_realminfo. */
32 #include "cfg.h"
34 static int
35 shishi_sendrecv_udp (Shishi * handle,
36 struct sockaddr *addr,
37 const char *indata, int inlen,
38 char **outdata, size_t * outlen, size_t timeout)
40 struct sockaddr lsa;
41 struct sockaddr_in *lsa_inp = (struct sockaddr_in *) &lsa;
42 char tmpbuf[BUFSIZ]; /* XXX can we do without it?
43 MSG_PEEK|MSG_TRUNC doesn't work for udp.. */
44 int sockfd;
45 int bytes_sent;
46 struct sockaddr_storage from_sa;
47 socklen_t length = sizeof (struct sockaddr_storage);
48 fd_set readfds;
49 struct timeval tout;
50 int rc;
52 memset (&lsa, 0, sizeof (lsa));
53 lsa_inp->sin_family = AF_INET;
54 lsa_inp->sin_addr.s_addr = htonl (INADDR_ANY);
56 sockfd = socket (AF_INET, SOCK_DGRAM, 0);
57 if (sockfd < 0)
59 shishi_error_set (handle, strerror (errno));
60 return SHISHI_SOCKET_ERROR;
63 if (bind (sockfd, (struct sockaddr *) &lsa, sizeof (lsa)) != 0)
65 shishi_error_set (handle, strerror (errno));
66 close (sockfd);
67 return SHISHI_BIND_ERROR;
70 bytes_sent = sendto (sockfd, (const void *) indata, inlen,
71 0, addr, sizeof (*addr));
72 if (bytes_sent != inlen)
74 shishi_error_set (handle, strerror (errno));
75 return SHISHI_SENDTO_ERROR;
78 FD_ZERO (&readfds);
79 FD_SET (sockfd, &readfds);
80 tout.tv_sec = timeout;
81 tout.tv_usec = 0;
82 if ((rc = select (sockfd + 1, &readfds, NULL, NULL, &tout)) != 1)
84 if (rc == -1)
85 shishi_error_set (handle, strerror (errno));
86 else
87 shishi_error_clear (handle);
88 return SHISHI_KDC_TIMEOUT;
91 *outlen = sizeof (tmpbuf);
92 *outlen = recvfrom (sockfd, tmpbuf, *outlen, 0,
93 (struct sockaddr *) &from_sa, &length);
95 if (*outlen == -1)
97 shishi_error_set (handle, strerror (errno));
98 return SHISHI_RECVFROM_ERROR;
101 *outdata = xmalloc (*outlen);
102 memcpy (*outdata, tmpbuf, *outlen);
104 if (close (sockfd) != 0)
106 shishi_error_set (handle, strerror (errno));
107 return SHISHI_CLOSE_ERROR;
110 return SHISHI_OK;
113 static int
114 shishi_sendrecv_tcp (Shishi * handle,
115 struct sockaddr *addr,
116 const char *indata, int inlen,
117 char **outdata, size_t * outlen, size_t timeout)
119 char tmpbuf[BUFSIZ]; /* XXX can we do without it?
120 MSG_PEEK|MSG_TRUNC doesn't work for udp.. */
121 int sockfd;
122 int bytes_sent;
123 struct sockaddr_storage from_sa;
124 socklen_t length = sizeof (struct sockaddr_storage);
125 fd_set readfds;
126 struct timeval tout;
127 int rc;
129 sockfd = socket (AF_INET, SOCK_STREAM, 0);
130 if (sockfd < 0)
132 shishi_error_set (handle, strerror (errno));
133 return SHISHI_SOCKET_ERROR;
136 if (connect (sockfd, addr, sizeof (*addr)) != 0)
138 shishi_error_set (handle, strerror (errno));
139 close (sockfd);
140 return SHISHI_CONNECT_ERROR;
143 tmpbuf[3] = inlen & 0xFF;
144 tmpbuf[2] = (inlen >> 8) & 0xFF;
145 tmpbuf[1] = (inlen >> 16) & 0xFF;
146 tmpbuf[0] = (inlen >> 24) & 0xFF;
148 bytes_sent = write (sockfd, tmpbuf, 4);
150 bytes_sent = write (sockfd, (const void *) indata, inlen);
151 if (bytes_sent != inlen)
153 shishi_error_set (handle, strerror (errno));
154 return SHISHI_SENDTO_ERROR;
157 FD_ZERO (&readfds);
158 FD_SET (sockfd, &readfds);
159 tout.tv_sec = timeout;
160 tout.tv_usec = 0;
161 if ((rc = select (sockfd + 1, &readfds, NULL, NULL, &tout)) != 1)
163 if (rc == -1)
164 shishi_error_set (handle, strerror (errno));
165 else
166 shishi_error_clear (handle);
167 return SHISHI_KDC_TIMEOUT;
170 *outlen = 4;
171 *outlen = recvfrom (sockfd, tmpbuf, *outlen, 0,
172 (struct sockaddr *) &from_sa, &length);
173 if (*outlen == -1)
175 shishi_error_set (handle, strerror (errno));
176 return SHISHI_RECVFROM_ERROR;
179 *outlen = sizeof (tmpbuf);
180 *outlen = recvfrom (sockfd, tmpbuf, *outlen, 0,
181 (struct sockaddr *) &from_sa, &length);
183 *outdata = xmalloc (*outlen);
184 memcpy (*outdata, tmpbuf, *outlen);
186 if (close (sockfd) != 0)
188 shishi_error_set (handle, strerror (errno));
189 return SHISHI_CLOSE_ERROR;
192 return SHISHI_OK;
195 static int
196 shishi_kdc_sendrecv_1 (Shishi * handle, struct Shishi_kdcinfo *ki,
197 const char *indata, size_t inlen,
198 char **outdata, size_t * outlen,
199 Shishi_tkts_hint * hint)
201 const char *protname;
202 int rc;
204 switch (ki->protocol)
206 #ifdef USE_STARTTLS
207 case TLS:
208 protname = "tls";
209 break;
210 #endif
212 case TCP:
213 protname = "tcp";
214 break;
216 default:
217 case UDP:
218 protname = "udp";
219 break;
222 shishi_verbose (handle, "Sending to %s (%s) via %s", ki->name,
223 inet_ntoa (((struct sockaddr_in *)
224 &ki->sockaddress)->sin_addr),
225 protname);
227 switch (ki->protocol)
229 #ifdef USE_STARTTLS
230 case TLS:
231 rc = _shishi_sendrecv_tls (handle, &ki->sockaddress,
232 indata, inlen, outdata, outlen,
233 handle->kdctimeout, hint);
234 break;
235 #endif
237 case TCP:
238 rc = shishi_sendrecv_tcp (handle, &ki->sockaddress,
239 indata, inlen, outdata, outlen,
240 handle->kdctimeout);
241 break;
243 case UDP:
244 default:
245 rc = shishi_sendrecv_udp (handle, &ki->sockaddress,
246 indata, inlen, outdata, outlen,
247 handle->kdctimeout);
248 break;
251 return rc;
254 static int
255 shishi_kdc_sendrecv_static (Shishi * handle, char *realm,
256 const char *indata, size_t inlen,
257 char **outdata, size_t * outlen,
258 Shishi_tkts_hint * hint)
260 struct Shishi_realminfo *ri;
261 size_t j, k;
262 int rc;
264 ri = _shishi_realminfo (handle, realm);
265 if (!ri)
267 shishi_error_printf (handle, "No KDC defined for realm %s", realm);
268 return SHISHI_KDC_NOT_KNOWN_FOR_REALM;
271 for (j = 0; j < handle->kdcretries; j++)
272 for (k = 0; k < ri->nkdcaddresses; k++)
274 rc = shishi_kdc_sendrecv_1 (handle, &ri->kdcaddresses[k],
275 indata, inlen, outdata, outlen, hint);
276 if (rc != SHISHI_KDC_TIMEOUT)
277 return rc;
280 shishi_error_clear (handle);
281 return SHISHI_KDC_TIMEOUT;
284 static int
285 shishi_kdc_sendrecv_srv_1 (Shishi * handle, char *realm,
286 const char *indata, size_t inlen,
287 char **outdata, size_t * outlen, Shishi_dns rrs)
289 int rc;
291 for (; rrs; rrs = rrs->next)
293 Shishi_dns_srv srv = rrs->rr;
294 struct addrinfo hints;
295 struct addrinfo *ai;
296 char *port;
298 if (rrs->class != C_IN)
299 continue;
300 if (rrs->type != T_SRV)
301 continue;
303 shishi_verbose (handle, "Located SRV RRs server %s:%d",
304 srv->name, srv->port);
306 memset (&hints, 0, sizeof (hints));
307 hints.ai_socktype = SOCK_DGRAM;
308 port = xasprintf ("%d", srv->port);
309 rc = getaddrinfo (srv->name, port, &hints, &ai);
310 free (port);
312 if (rc != 0)
314 shishi_warn (handle, "Unknown KDC host `%s' (gai rc %d)",
315 srv->name, rc);
316 continue;
319 shishi_verbose (handle, "Sending to %s:%d (%s)",
320 srv->name, srv->port,
321 inet_ntoa (((struct sockaddr_in *)
322 ai->ai_addr)->sin_addr));
324 rc = shishi_sendrecv_udp (handle, ai->ai_addr,
325 indata, inlen, outdata, outlen,
326 handle->kdctimeout);
328 freeaddrinfo (ai);
330 if (rc != SHISHI_KDC_TIMEOUT)
331 return rc;
334 return SHISHI_KDC_TIMEOUT;
337 static int
338 shishi_kdc_sendrecv_srv (Shishi * handle, char *realm,
339 const char *indata, size_t inlen,
340 char **outdata, size_t * outlen)
342 Shishi_dns rrs;
343 char *tmp;
344 int rc;
346 shishi_verbose (handle, "Finding SRV RRs for %s", realm);
348 tmp = xasprintf ("_kerberos._udp.%s", realm);
349 rrs = shishi_resolv (tmp, SHISHI_DNS_SRV);
350 free (tmp);
352 if (rrs)
353 rc = shishi_kdc_sendrecv_srv_1 (handle, realm, indata, inlen,
354 outdata, outlen, rrs);
355 else
357 shishi_error_printf (handle, "No KDC SRV RRs for realm %s", realm);
358 rc = SHISHI_KDC_NOT_KNOWN_FOR_REALM;
361 shishi_resolv_free (rrs);
363 return rc;
366 static int
367 shishi_kdc_sendrecv_direct (Shishi * handle, char *realm,
368 const char *indata, size_t inlen,
369 char **outdata, size_t * outlen)
371 struct servent *se;
372 struct addrinfo hints;
373 struct addrinfo *ai;
374 char *port;
375 int rc;
377 shishi_verbose (handle, "Trying direct realm host mapping for %s", realm);
379 se = getservbyname ("kerberos", NULL);
380 if (se)
381 port = xasprintf ("%d", ntohs (se->s_port));
382 else
383 port = xasprintf ("%d", 88);
385 memset (&hints, 0, sizeof (hints));
386 hints.ai_socktype = SOCK_DGRAM;
387 rc = getaddrinfo (realm, port, &hints, &ai);
389 free (port);
391 if (rc != 0)
393 shishi_error_printf (handle, "No direct realm host for realm %s",
394 realm);
395 return SHISHI_KDC_NOT_KNOWN_FOR_REALM;
398 shishi_verbose (handle, "Sending to %s:%d (%s)", realm, port,
399 inet_ntoa (((struct sockaddr_in *) ai->ai_addr)->sin_addr));
401 rc = shishi_sendrecv_udp (handle, ai->ai_addr,
402 indata, inlen, outdata, outlen,
403 handle->kdctimeout);
405 freeaddrinfo (ai);
407 return rc;
411 shishi_kdc_sendrecv_hint (Shishi * handle, char *realm,
412 const char *indata, size_t inlen,
413 char **outdata, size_t * outlen,
414 Shishi_tkts_hint * hint)
416 int rc;
418 rc = shishi_kdc_sendrecv_static (handle, realm, indata, inlen,
419 outdata, outlen, hint);
420 if (rc == SHISHI_KDC_TIMEOUT || rc == SHISHI_KDC_NOT_KNOWN_FOR_REALM)
421 rc = shishi_kdc_sendrecv_srv (handle, realm,
422 indata, inlen, outdata, outlen);
423 if (rc == SHISHI_KDC_TIMEOUT || rc == SHISHI_KDC_NOT_KNOWN_FOR_REALM)
424 rc = shishi_kdc_sendrecv_direct (handle, realm,
425 indata, inlen, outdata, outlen);
427 return rc;
431 shishi_kdc_sendrecv (Shishi * handle, char *realm,
432 const char *indata, size_t inlen,
433 char **outdata, size_t * outlen)
435 return shishi_kdc_sendrecv_hint (handle, realm, indata, inlen,
436 outdata, outlen, NULL);