1 /* netio.c --- Network I/O functions.
2 * Copyright (C) 2002, 2003, 2004, 2006 Simon Josefsson
4 * This file is part of Shishi.
6 * Shishi is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * Shishi is distributed in the hope that it will be useful,
12 * but 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, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 /* Get _shishi_sendrecv_tls, etc. */
27 /* Get _shishi_realminfo, etc. */
30 /* Get _shishi_realminfo. */
34 shishi_sendrecv_udp (Shishi
* handle
,
35 struct sockaddr
*addr
,
36 const char *indata
, int inlen
,
37 char **outdata
, size_t * outlen
, size_t timeout
)
40 struct sockaddr_in
*lsa_inp
= (struct sockaddr_in
*) &lsa
;
41 char tmpbuf
[BUFSIZ
]; /* XXX can we do without it?
42 MSG_PEEK|MSG_TRUNC doesn't work for udp.. */
45 struct sockaddr_storage from_sa
;
46 socklen_t length
= sizeof (struct sockaddr_storage
);
51 memset (&lsa
, 0, sizeof (lsa
));
52 lsa_inp
->sin_family
= AF_INET
;
53 lsa_inp
->sin_addr
.s_addr
= htonl (INADDR_ANY
);
55 sockfd
= socket (AF_INET
, SOCK_DGRAM
, 0);
58 shishi_error_set (handle
, strerror (errno
));
59 return SHISHI_SOCKET_ERROR
;
62 if (bind (sockfd
, (struct sockaddr
*) &lsa
, sizeof (lsa
)) != 0)
64 shishi_error_set (handle
, strerror (errno
));
66 return SHISHI_BIND_ERROR
;
69 bytes_sent
= sendto (sockfd
, (const void *) indata
, inlen
,
70 0, addr
, sizeof (*addr
));
71 if (bytes_sent
!= inlen
)
73 shishi_error_set (handle
, strerror (errno
));
74 return SHISHI_SENDTO_ERROR
;
78 FD_SET (sockfd
, &readfds
);
79 tout
.tv_sec
= timeout
;
81 if ((rc
= select (sockfd
+ 1, &readfds
, NULL
, NULL
, &tout
)) != 1)
84 shishi_error_set (handle
, strerror (errno
));
86 shishi_error_clear (handle
);
87 return SHISHI_KDC_TIMEOUT
;
90 *outlen
= sizeof (tmpbuf
);
91 *outlen
= recvfrom (sockfd
, tmpbuf
, *outlen
, 0,
92 (struct sockaddr
*) &from_sa
, &length
);
96 shishi_error_set (handle
, strerror (errno
));
97 return SHISHI_RECVFROM_ERROR
;
100 *outdata
= xmalloc (*outlen
);
101 memcpy (*outdata
, tmpbuf
, *outlen
);
103 if (close (sockfd
) != 0)
105 shishi_error_set (handle
, strerror (errno
));
106 return SHISHI_CLOSE_ERROR
;
113 shishi_sendrecv_tcp (Shishi
* handle
,
114 struct sockaddr
*addr
,
115 const char *indata
, int inlen
,
116 char **outdata
, size_t * outlen
, size_t timeout
)
118 char tmpbuf
[BUFSIZ
]; /* XXX can we do without it?
119 MSG_PEEK|MSG_TRUNC doesn't work for udp.. */
122 struct sockaddr_storage from_sa
;
123 socklen_t length
= sizeof (struct sockaddr_storage
);
128 sockfd
= socket (AF_INET
, SOCK_STREAM
, 0);
131 shishi_error_set (handle
, strerror (errno
));
132 return SHISHI_SOCKET_ERROR
;
135 if (connect (sockfd
, addr
, sizeof (*addr
)) != 0)
137 shishi_error_set (handle
, strerror (errno
));
139 return SHISHI_CONNECT_ERROR
;
142 tmpbuf
[3] = inlen
& 0xFF;
143 tmpbuf
[2] = (inlen
>> 8) & 0xFF;
144 tmpbuf
[1] = (inlen
>> 16) & 0xFF;
145 tmpbuf
[0] = (inlen
>> 24) & 0xFF;
147 bytes_sent
= write (sockfd
, tmpbuf
, 4);
149 bytes_sent
= write (sockfd
, (const void *) indata
, inlen
);
150 if (bytes_sent
!= inlen
)
152 shishi_error_set (handle
, strerror (errno
));
153 return SHISHI_SENDTO_ERROR
;
157 FD_SET (sockfd
, &readfds
);
158 tout
.tv_sec
= timeout
;
160 if ((rc
= select (sockfd
+ 1, &readfds
, NULL
, NULL
, &tout
)) != 1)
163 shishi_error_set (handle
, strerror (errno
));
165 shishi_error_clear (handle
);
166 return SHISHI_KDC_TIMEOUT
;
170 *outlen
= recvfrom (sockfd
, tmpbuf
, *outlen
, 0,
171 (struct sockaddr
*) &from_sa
, &length
);
174 shishi_error_set (handle
, strerror (errno
));
175 return SHISHI_RECVFROM_ERROR
;
178 *outlen
= sizeof (tmpbuf
);
179 *outlen
= recvfrom (sockfd
, tmpbuf
, *outlen
, 0,
180 (struct sockaddr
*) &from_sa
, &length
);
182 *outdata
= xmalloc (*outlen
);
183 memcpy (*outdata
, tmpbuf
, *outlen
);
185 if (close (sockfd
) != 0)
187 shishi_error_set (handle
, strerror (errno
));
188 return SHISHI_CLOSE_ERROR
;
195 shishi_kdc_sendrecv_1 (Shishi
* handle
, struct Shishi_kdcinfo
*ki
,
196 const char *indata
, size_t inlen
,
197 char **outdata
, size_t * outlen
,
198 Shishi_tkts_hint
* hint
)
200 const char *protname
;
203 switch (ki
->protocol
)
221 shishi_verbose (handle
, "Sending to %s (%s) via %s", ki
->name
,
222 inet_ntoa (((struct sockaddr_in
*)
223 &ki
->sockaddress
)->sin_addr
),
226 switch (ki
->protocol
)
230 rc
= _shishi_sendrecv_tls (handle
, &ki
->sockaddress
,
231 indata
, inlen
, outdata
, outlen
,
232 handle
->kdctimeout
, hint
);
237 rc
= shishi_sendrecv_tcp (handle
, &ki
->sockaddress
,
238 indata
, inlen
, outdata
, outlen
,
244 rc
= shishi_sendrecv_udp (handle
, &ki
->sockaddress
,
245 indata
, inlen
, outdata
, outlen
,
254 shishi_kdc_sendrecv_static (Shishi
* handle
, char *realm
,
255 const char *indata
, size_t inlen
,
256 char **outdata
, size_t * outlen
,
257 Shishi_tkts_hint
* hint
)
259 struct Shishi_realminfo
*ri
;
263 ri
= _shishi_realminfo (handle
, realm
);
266 shishi_error_printf (handle
, "No KDC defined for realm %s", realm
);
267 return SHISHI_KDC_NOT_KNOWN_FOR_REALM
;
270 for (j
= 0; j
< handle
->kdcretries
; j
++)
271 for (k
= 0; k
< ri
->nkdcaddresses
; k
++)
273 rc
= shishi_kdc_sendrecv_1 (handle
, &ri
->kdcaddresses
[k
],
274 indata
, inlen
, outdata
, outlen
, hint
);
275 if (rc
!= SHISHI_KDC_TIMEOUT
)
279 shishi_error_clear (handle
);
280 return SHISHI_KDC_TIMEOUT
;
284 shishi_kdc_sendrecv_srv_1 (Shishi
* handle
, char *realm
,
285 const char *indata
, size_t inlen
,
286 char **outdata
, size_t * outlen
, Shishi_dns rrs
)
290 for (; rrs
; rrs
= rrs
->next
)
292 Shishi_dns_srv srv
= rrs
->rr
;
293 struct addrinfo hints
;
297 if (rrs
->class != C_IN
)
299 if (rrs
->type
!= T_SRV
)
302 shishi_verbose (handle
, "Located SRV RRs server %s:%d",
303 srv
->name
, srv
->port
);
305 memset (&hints
, 0, sizeof (hints
));
306 hints
.ai_socktype
= SOCK_DGRAM
;
307 port
= xasprintf ("%d", srv
->port
);
308 rc
= getaddrinfo (srv
->name
, port
, &hints
, &ai
);
313 shishi_warn (handle
, "Unknown KDC host `%s' (gai rc %d)",
318 shishi_verbose (handle
, "Sending to %s:%d (%s)",
319 srv
->name
, srv
->port
,
320 inet_ntoa (((struct sockaddr_in
*)
321 ai
->ai_addr
)->sin_addr
));
323 rc
= shishi_sendrecv_udp (handle
, ai
->ai_addr
,
324 indata
, inlen
, outdata
, outlen
,
329 if (rc
!= SHISHI_KDC_TIMEOUT
)
333 return SHISHI_KDC_TIMEOUT
;
337 shishi_kdc_sendrecv_srv (Shishi
* handle
, char *realm
,
338 const char *indata
, size_t inlen
,
339 char **outdata
, size_t * outlen
)
345 shishi_verbose (handle
, "Finding SRV RRs for %s", realm
);
347 tmp
= xasprintf ("_kerberos._udp.%s", realm
);
348 rrs
= shishi_resolv (tmp
, SHISHI_DNS_SRV
);
352 rc
= shishi_kdc_sendrecv_srv_1 (handle
, realm
, indata
, inlen
,
353 outdata
, outlen
, rrs
);
356 shishi_error_printf (handle
, "No KDC SRV RRs for realm %s", realm
);
357 rc
= SHISHI_KDC_NOT_KNOWN_FOR_REALM
;
360 shishi_resolv_free (rrs
);
366 shishi_kdc_sendrecv_direct (Shishi
* handle
, char *realm
,
367 const char *indata
, size_t inlen
,
368 char **outdata
, size_t * outlen
)
371 struct addrinfo hints
;
376 shishi_verbose (handle
, "Trying direct realm host mapping for %s", realm
);
378 se
= getservbyname ("kerberos", NULL
);
380 port
= xasprintf ("%d", ntohs (se
->s_port
));
382 port
= xasprintf ("%d", 88);
384 memset (&hints
, 0, sizeof (hints
));
385 hints
.ai_socktype
= SOCK_DGRAM
;
386 rc
= getaddrinfo (realm
, port
, &hints
, &ai
);
392 shishi_error_printf (handle
, "No direct realm host for realm %s",
394 return SHISHI_KDC_NOT_KNOWN_FOR_REALM
;
397 shishi_verbose (handle
, "Sending to %s:%d (%s)", realm
, port
,
398 inet_ntoa (((struct sockaddr_in
*) ai
->ai_addr
)->sin_addr
));
400 rc
= shishi_sendrecv_udp (handle
, ai
->ai_addr
,
401 indata
, inlen
, outdata
, outlen
,
410 shishi_kdc_sendrecv_hint (Shishi
* handle
, char *realm
,
411 const char *indata
, size_t inlen
,
412 char **outdata
, size_t * outlen
,
413 Shishi_tkts_hint
* hint
)
417 rc
= shishi_kdc_sendrecv_static (handle
, realm
, indata
, inlen
,
418 outdata
, outlen
, hint
);
419 if (rc
== SHISHI_KDC_TIMEOUT
|| rc
== SHISHI_KDC_NOT_KNOWN_FOR_REALM
)
420 rc
= shishi_kdc_sendrecv_srv (handle
, realm
,
421 indata
, inlen
, outdata
, outlen
);
422 if (rc
== SHISHI_KDC_TIMEOUT
|| rc
== SHISHI_KDC_NOT_KNOWN_FOR_REALM
)
423 rc
= shishi_kdc_sendrecv_direct (handle
, realm
,
424 indata
, inlen
, outdata
, outlen
);
430 shishi_kdc_sendrecv (Shishi
* handle
, char *realm
,
431 const char *indata
, size_t inlen
,
432 char **outdata
, size_t * outlen
)
434 return shishi_kdc_sendrecv_hint (handle
, realm
, indata
, inlen
,
435 outdata
, outlen
, NULL
);