Add ticketlife, renewlife.
[shishi.git] / lib / netio.c
blob001b3abfbd151e6ef180c5215a987caaf38eb195
1 /* netio.c network I/O functions
2 * Copyright (C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "internal.h"
24 static int
25 shishi_sendrecv_udp (Shishi * handle,
26 struct sockaddr *addr,
27 const char *indata, int inlen,
28 char *outdata, int *outlen, int timeout)
30 struct sockaddr lsa;
31 struct sockaddr_in *lsa_inp = (struct sockaddr_in *) &lsa;
32 int sockfd;
33 int bytes_sent;
34 struct sockaddr_storage from_sa;
35 int length = sizeof (struct sockaddr_storage);
36 fd_set readfds;
37 struct timeval tout;
38 int rc;
40 memset (&lsa, 0, sizeof (lsa));
41 lsa_inp->sin_family = AF_INET;
42 lsa_inp->sin_addr.s_addr = htonl (INADDR_ANY);
44 sockfd = socket (AF_INET, SOCK_DGRAM, 0);
45 if (sockfd < 0)
47 shishi_error_set (handle, strerror (errno));
48 return SHISHI_SOCKET_ERROR;
51 if (bind (sockfd, (struct sockaddr *) &lsa, sizeof (lsa)) != 0)
53 shishi_error_set (handle, strerror (errno));
54 close (sockfd);
55 return SHISHI_BIND_ERROR;
58 bytes_sent = sendto (sockfd, (const void *) indata, inlen,
59 0, addr, sizeof (*addr));
60 if (bytes_sent != inlen)
62 shishi_error_set (handle, strerror (errno));
63 return SHISHI_SENDTO_ERROR;
66 FD_ZERO (&readfds);
67 FD_SET (sockfd, &readfds);
68 tout.tv_sec = timeout;
69 tout.tv_usec = 0;
70 if ((rc = select (sockfd + 1, &readfds, NULL, NULL, &tout)) != 1)
72 if (rc == -1)
73 shishi_error_set (handle, strerror (errno));
74 else
75 shishi_error_clear (handle);
76 return SHISHI_KDC_TIMEOUT;
79 *outlen = recvfrom (sockfd, outdata, *outlen, 0,
80 (struct sockaddr *) &from_sa, &length);
82 if (*outlen == -1)
84 shishi_error_set (handle, strerror (errno));
85 return SHISHI_RECVFROM_ERROR;
88 if (close (sockfd) != 0)
90 shishi_error_set (handle, strerror (errno));
91 return SHISHI_CLOSE_ERROR;
94 return SHISHI_OK;
97 static int
98 shishi_kdc_sendrecv_static (Shishi * handle, char *realm,
99 const char *indata, size_t inlen,
100 char *outdata, size_t * outlen)
102 int i, j, k;
103 int rc;
105 for (i = 0; i < handle->nrealminfos; i++)
106 if (realm && strcmp (handle->realminfos[i].name, realm) == 0)
108 for (j = 0; j < handle->kdcretries; j++)
109 for (k = 0; k < handle->realminfos[i].nkdcaddresses; k++)
111 struct Shishi_kdcinfo *ki =
112 &handle->realminfos[i].kdcaddresses[k];
114 if (VERBOSE (handle))
116 printf ("Sending to %s (%s)...\n", ki->name,
117 inet_ntoa (((struct sockaddr_in *)
118 &ki->sockaddress)->sin_addr));
121 rc = shishi_sendrecv_udp (handle, &ki->sockaddress,
122 indata, inlen, outdata, outlen,
123 handle->kdctimeout);
124 if (rc != SHISHI_KDC_TIMEOUT)
125 return rc;
128 shishi_error_clear (handle);
129 return SHISHI_KDC_TIMEOUT;
132 shishi_error_printf (handle, "No KDC defined for realm %s", realm);
133 return SHISHI_KDC_NOT_KNOWN_FOR_REALM;
136 static int
137 shishi_kdc_sendrecv_srv_1 (Shishi * handle, char *realm,
138 const char *indata, size_t inlen,
139 char *outdata, size_t * outlen,
140 dnshost_t rrs)
142 int rc;
144 for (; rrs; rrs = rrs->next)
146 dns_srv_t srv = (dns_srv_t) rrs->rr;
147 struct addrinfo hints;
148 struct addrinfo *ai;
149 char *port;
151 if (rrs->class != C_IN)
152 continue;
153 if (rrs->type != T_SRV)
154 continue;
156 if (VERBOSE (handle))
157 printf ("Located SRV RRs server %s:%d...\n", srv->name, srv->port);
159 memset (&hints, 0, sizeof(hints));
160 hints.ai_socktype = SOCK_DGRAM;
161 asprintf (&port, "%d", srv->port);
162 rc = getaddrinfo (srv->name, port, &hints, &ai);
163 free (port);
165 if (rc != 0)
167 shishi_warn (handle, "Unknown KDC host `%s' (gai rc %d)",
168 srv->name, rc);
169 freeaddrinfo (ai);
170 continue;
173 if (VERBOSE (handle))
174 printf ("Sending to %s:%d (%s)...\n", srv->name, srv->port,
175 inet_ntoa (((struct sockaddr_in *)ai->ai_addr)->sin_addr));
177 rc = shishi_sendrecv_udp (handle, ai->ai_addr,
178 indata, inlen, outdata, outlen,
179 handle->kdctimeout);
181 freeaddrinfo (ai);
183 if (rc != SHISHI_KDC_TIMEOUT)
184 return rc;
187 return SHISHI_KDC_TIMEOUT;
190 static int
191 shishi_kdc_sendrecv_srv (Shishi * handle, char *realm,
192 const char *indata, size_t inlen,
193 char *outdata, size_t * outlen)
195 dnshost_t rrs;
196 char *tmp;
197 int rc;
199 if (VERBOSE (handle))
200 printf ("Finding SRV RRs for %s...\n", realm);
202 asprintf (&tmp, "_kerberos._udp.%s", realm);
203 rrs = _shishi_resolv(tmp, T_SRV);
204 free (tmp);
206 if (rrs)
207 rc = shishi_kdc_sendrecv_srv_1 (handle, realm, indata, inlen,
208 outdata, outlen, rrs);
209 else
211 shishi_error_printf (handle, "No KDC SRV RRs for realm %s", realm);
212 rc = SHISHI_KDC_NOT_KNOWN_FOR_REALM;
215 _shishi_resolv_free (rrs);
217 return rc;
220 static int
221 shishi_kdc_sendrecv_direct (Shishi * handle, char *realm,
222 const char *indata, size_t inlen,
223 char *outdata, size_t * outlen)
225 struct servent *se;
226 struct addrinfo hints;
227 struct addrinfo *ai;
228 char *port;
229 int rc;
231 if (VERBOSE (handle))
232 printf ("Trying direct realm host mapping for %s...\n", realm);
234 se = getservbyname ("kerberos", NULL);
235 if (se)
236 asprintf (&port, "%d", ntohs(se->s_port));
237 else
238 asprintf (&port, "%d", 88);
240 memset (&hints, 0, sizeof(hints));
241 hints.ai_socktype = SOCK_DGRAM;
242 rc = getaddrinfo (realm, port, &hints, &ai);
244 free (port);
246 if (rc != 0)
248 shishi_error_printf (handle, "No direct realm host for realm %s", realm);
249 return SHISHI_KDC_NOT_KNOWN_FOR_REALM;
252 if (VERBOSE (handle))
253 printf ("Sending to %s:%s (%s)...\n", realm, port,
254 inet_ntoa (((struct sockaddr_in *)ai->ai_addr)->sin_addr));
256 rc = shishi_sendrecv_udp (handle, ai->ai_addr,
257 indata, inlen, outdata, outlen,
258 handle->kdctimeout);
260 freeaddrinfo (ai);
262 return rc;
266 shishi_kdc_sendrecv (Shishi * handle, char *realm,
267 const char *indata, size_t inlen,
268 char *outdata, size_t * outlen)
270 int rc;
272 rc = shishi_kdc_sendrecv_static (handle, realm,
273 indata, inlen, outdata, outlen);
275 if (rc == SHISHI_KDC_TIMEOUT || rc == SHISHI_KDC_NOT_KNOWN_FOR_REALM)
276 rc = shishi_kdc_sendrecv_srv (handle, realm,
277 indata, inlen, outdata, outlen);
278 if (rc == SHISHI_KDC_TIMEOUT || rc == SHISHI_KDC_NOT_KNOWN_FOR_REALM)
279 rc = shishi_kdc_sendrecv_direct (handle, realm,
280 indata, inlen, outdata, outlen);
282 return rc;