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
25 /* Get _shishi_sendrecv_tls, etc. */
28 /* Get _shishi_realminfo, etc. */
31 /* Get _shishi_realminfo. */
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
)
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.. */
46 struct sockaddr_storage from_sa
;
47 socklen_t length
= sizeof (struct sockaddr_storage
);
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);
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
));
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
;
79 FD_SET (sockfd
, &readfds
);
80 tout
.tv_sec
= timeout
;
82 if ((rc
= select (sockfd
+ 1, &readfds
, NULL
, NULL
, &tout
)) != 1)
85 shishi_error_set (handle
, strerror (errno
));
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
);
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
;
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.. */
123 struct sockaddr_storage from_sa
;
124 socklen_t length
= sizeof (struct sockaddr_storage
);
129 sockfd
= socket (AF_INET
, SOCK_STREAM
, 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
));
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
;
158 FD_SET (sockfd
, &readfds
);
159 tout
.tv_sec
= timeout
;
161 if ((rc
= select (sockfd
+ 1, &readfds
, NULL
, NULL
, &tout
)) != 1)
164 shishi_error_set (handle
, strerror (errno
));
166 shishi_error_clear (handle
);
167 return SHISHI_KDC_TIMEOUT
;
171 *outlen
= recvfrom (sockfd
, tmpbuf
, *outlen
, 0,
172 (struct sockaddr
*) &from_sa
, &length
);
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
;
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
;
204 switch (ki
->protocol
)
222 shishi_verbose (handle
, "Sending to %s (%s) via %s", ki
->name
,
223 inet_ntoa (((struct sockaddr_in
*)
224 &ki
->sockaddress
)->sin_addr
),
227 switch (ki
->protocol
)
231 rc
= _shishi_sendrecv_tls (handle
, &ki
->sockaddress
,
232 indata
, inlen
, outdata
, outlen
,
233 handle
->kdctimeout
, hint
);
238 rc
= shishi_sendrecv_tcp (handle
, &ki
->sockaddress
,
239 indata
, inlen
, outdata
, outlen
,
245 rc
= shishi_sendrecv_udp (handle
, &ki
->sockaddress
,
246 indata
, inlen
, outdata
, outlen
,
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
;
264 ri
= _shishi_realminfo (handle
, realm
);
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
)
280 shishi_error_clear (handle
);
281 return SHISHI_KDC_TIMEOUT
;
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
)
291 for (; rrs
; rrs
= rrs
->next
)
293 Shishi_dns_srv srv
= rrs
->rr
;
294 struct addrinfo hints
;
298 if (rrs
->class != C_IN
)
300 if (rrs
->type
!= T_SRV
)
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
);
314 shishi_warn (handle
, "Unknown KDC host `%s' (gai rc %d)",
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
,
330 if (rc
!= SHISHI_KDC_TIMEOUT
)
334 return SHISHI_KDC_TIMEOUT
;
338 shishi_kdc_sendrecv_srv (Shishi
* handle
, char *realm
,
339 const char *indata
, size_t inlen
,
340 char **outdata
, size_t * outlen
)
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
);
353 rc
= shishi_kdc_sendrecv_srv_1 (handle
, realm
, indata
, inlen
,
354 outdata
, outlen
, rrs
);
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
);
367 shishi_kdc_sendrecv_direct (Shishi
* handle
, char *realm
,
368 const char *indata
, size_t inlen
,
369 char **outdata
, size_t * outlen
)
372 struct addrinfo hints
;
377 shishi_verbose (handle
, "Trying direct realm host mapping for %s", realm
);
379 se
= getservbyname ("kerberos", NULL
);
381 port
= xasprintf ("%d", ntohs (se
->s_port
));
383 port
= xasprintf ("%d", 88);
385 memset (&hints
, 0, sizeof (hints
));
386 hints
.ai_socktype
= SOCK_DGRAM
;
387 rc
= getaddrinfo (realm
, port
, &hints
, &ai
);
393 shishi_error_printf (handle
, "No direct realm host for realm %s",
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
,
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
)
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
);
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
);