r24267: Fix the build farm
[Samba/gebeck_regimport.git] / source3 / libads / smb_krb5_locator.c
blobb5a6ffd4533b3cade3ce2256656372ced2b300d3
1 /*
2 Unix SMB/CIFS implementation.
3 kerberos locator plugin
4 Copyright (C) Guenther Deschner 2007
6 This program 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 3 of the License, or
9 (at your option) any later version.
11 This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
22 #if defined(HAVE_KRB5) && defined(HAVE_KRB5_LOCATE_PLUGIN_H)
24 #include <krb5/locate_plugin.h>
26 static const char *get_service_from_locate_service_type(enum locate_service_type svc)
28 switch (svc) {
29 case locate_service_kdc:
30 case locate_service_master_kdc:
31 return "88";
32 case locate_service_kadmin:
33 case locate_service_krb524:
34 /* not supported */
35 return NULL;
36 case locate_service_kpasswd:
37 return "464";
38 default:
39 break;
41 return NULL;
45 static const char *locate_service_type_name(enum locate_service_type svc)
47 switch (svc) {
48 case locate_service_kdc:
49 return "locate_service_kdc";
50 case locate_service_master_kdc:
51 return "locate_service_master_kdc";
52 case locate_service_kadmin:
53 return "locate_service_kadmin";
54 case locate_service_krb524:
55 return "locate_service_krb524";
56 case locate_service_kpasswd:
57 return "locate_service_kpasswd";
58 default:
59 break;
61 return NULL;
64 static const char *socktype_name(int socktype)
66 switch (socktype) {
67 case SOCK_STREAM:
68 return "SOCK_STREAM";
69 case SOCK_DGRAM:
70 return "SOCK_DGRAM";
71 default:
72 break;
74 return "unknown";
77 static const char *family_name(int family)
79 switch (family) {
80 case AF_UNSPEC:
81 return "AF_UNSPEC";
82 case AF_INET:
83 return "AF_INET";
84 case AF_INET6:
85 return "AF_INET6";
86 default:
87 break;
89 return "unknown";
92 /**
93 * Check input parameters, return KRB5_PLUGIN_NO_HANDLE for unsupported ones
95 * @param svc
96 * @param realm string
97 * @param socktype integer
98 * @param family integer
100 * @return integer.
103 static int smb_krb5_locator_lookup_sanity_check(enum locate_service_type svc,
104 const char *realm,
105 int socktype,
106 int family)
108 if (!realm || strlen(realm) == 0) {
109 return EINVAL;
112 switch (svc) {
113 case locate_service_kdc:
114 case locate_service_master_kdc:
115 case locate_service_kpasswd:
116 break;
117 case locate_service_kadmin:
118 case locate_service_krb524:
119 #ifdef KRB5_PLUGIN_NO_HANDLE
120 return KRB5_PLUGIN_NO_HANDLE;
121 #else
122 return KRB5_KDC_UNREACH; /* Heimdal */
123 #endif
124 default:
125 return EINVAL;
128 switch (family) {
129 case AF_UNSPEC:
130 case AF_INET:
131 break;
132 case AF_INET6: /* not yet */
133 #ifdef KRB5_PLUGIN_NO_HANDLE
134 return KRB5_PLUGIN_NO_HANDLE;
135 #else
136 return KRB5_KDC_UNREACH; /* Heimdal */
137 #endif
138 default:
139 return EINVAL;
142 switch (socktype) {
143 case SOCK_STREAM:
144 case SOCK_DGRAM:
145 case 0: /* Heimdal uses that */
146 break;
147 default:
148 return EINVAL;
151 return 0;
155 * Try to get addrinfo for a given host and call the krb5 callback
157 * @param name string
158 * @param service string
159 * @param in struct addrinfo hint
160 * @param cbfunc krb5 callback function
161 * @param cbdata void pointer cbdata
163 * @return krb5_error_code.
166 static krb5_error_code smb_krb5_locator_call_cbfunc(const char *name,
167 const char *service,
168 struct addrinfo *in,
169 int (*cbfunc)(void *, int, struct sockaddr *),
170 void *cbdata)
172 struct addrinfo *out;
173 int ret;
174 int count = 3;
176 while (count) {
178 ret = getaddrinfo(name, service, in, &out);
179 if (ret == 0) {
180 break;
183 if (ret == EAI_AGAIN) {
184 count--;
185 continue;
188 DEBUG(10,("smb_krb5_locator_lookup: got ret: %s (%d)\n",
189 gai_strerror(ret), ret));
190 #ifdef KRB5_PLUGIN_NO_HANDLE
191 return KRB5_PLUGIN_NO_HANDLE;
192 #else
193 return KRB5_KDC_UNREACH; /* Heimdal */
194 #endif
197 ret = cbfunc(cbdata, out->ai_socktype, out->ai_addr);
198 if (ret) {
199 DEBUG(10,("smb_krb5_locator_lookup: failed to call callback: %s (%d)\n",
200 error_message(ret), ret));
203 freeaddrinfo(out);
205 return ret;
209 * PUBLIC INTERFACE: locate init
211 * @param context krb5_context
212 * @param privata_data pointer to private data pointer
214 * @return krb5_error_code.
217 krb5_error_code smb_krb5_locator_init(krb5_context context,
218 void **private_data)
220 setup_logging("smb_krb5_locator", True);
221 load_case_tables();
222 lp_load(dyn_CONFIGFILE,True,False,False,True);
224 DEBUG(10,("smb_krb5_locator_init: called\n"));
226 return 0;
230 * PUBLIC INTERFACE: close locate
232 * @param private_data pointer to private data
234 * @return void.
237 void smb_krb5_locator_close(void *private_data)
239 DEBUG(10,("smb_krb5_locator_close: called\n"));
241 /* gfree_all(); */
245 * PUBLIC INTERFACE: locate lookup
247 * @param private_data pointer to private data
248 * @param svc enum locate_service_type.
249 * @param realm string
250 * @param socktype integer
251 * @param family integer
252 * @param cbfunc callback function to send back entries
253 * @param cbdata void pointer to cbdata
255 * @return krb5_error_code.
258 krb5_error_code smb_krb5_locator_lookup(void *private_data,
259 enum locate_service_type svc,
260 const char *realm,
261 int socktype,
262 int family,
263 int (*cbfunc)(void *, int, struct sockaddr *),
264 void *cbdata)
266 NTSTATUS status;
267 krb5_error_code ret;
268 char *sitename = NULL;
269 struct ip_service *ip_list;
270 int count = 0;
271 struct addrinfo aihints;
272 char *saf_name = NULL;
273 int i;
275 DEBUG(10,("smb_krb5_locator_lookup: called for\n"));
276 DEBUGADD(10,("\tsvc: %s (%d), realm: %s\n",
277 locate_service_type_name(svc), svc, realm));
278 DEBUGADD(10,("\tsocktype: %s (%d), family: %s (%d)\n",
279 socktype_name(socktype), socktype,
280 family_name(family), family));
282 ret = smb_krb5_locator_lookup_sanity_check(svc, realm, socktype, family);
283 if (ret) {
284 DEBUG(10,("smb_krb5_locator_lookup: returning ret: %s (%d)\n",
285 error_message(ret), ret));
286 return ret;
289 /* first try to fetch from SAF cache */
291 saf_name = saf_fetch(realm);
292 if (!saf_name || strlen(saf_name) == 0) {
293 DEBUG(10,("smb_krb5_locator_lookup: no SAF name stored for %s\n",
294 realm));
295 goto find_kdc;
298 DEBUG(10,("smb_krb5_locator_lookup: got %s for %s from SAF cache\n",
299 saf_name, realm));
301 ZERO_STRUCT(aihints);
303 aihints.ai_family = family;
304 aihints.ai_socktype = socktype;
306 ret = smb_krb5_locator_call_cbfunc(saf_name,
307 get_service_from_locate_service_type(svc),
308 &aihints,
309 cbfunc, cbdata);
310 if (ret) {
311 return ret;
314 return 0;
316 find_kdc:
318 /* now try to find via site-aware DNS SRV query */
320 sitename = sitename_fetch(realm);
321 status = get_kdc_list(realm, sitename, &ip_list, &count);
323 /* if we didn't found any KDCs on our site go to the main list */
325 if (NT_STATUS_IS_OK(status) && sitename && (count == 0)) {
326 SAFE_FREE(ip_list);
327 SAFE_FREE(sitename);
328 status = get_kdc_list(realm, NULL, &ip_list, &count);
331 SAFE_FREE(sitename);
333 if (!NT_STATUS_IS_OK(status)) {
334 DEBUG(10,("smb_krb5_locator_lookup: got %s (%s)\n",
335 nt_errstr(status),
336 error_message(nt_status_to_krb5(status))));
337 #ifdef KRB5_PLUGIN_NO_HANDLE
338 return KRB5_PLUGIN_NO_HANDLE;
339 #else
340 return KRB5_KDC_UNREACH; /* Heimdal */
341 #endif
344 for (i=0; i<count; i++) {
346 const char *host = NULL;
347 const char *port = NULL;
349 ZERO_STRUCT(aihints);
351 aihints.ai_family = family;
352 aihints.ai_socktype = socktype;
354 host = inet_ntoa(ip_list[i].ip);
355 port = get_service_from_locate_service_type(svc);
357 ret = smb_krb5_locator_call_cbfunc(host,
358 port,
359 &aihints,
360 cbfunc, cbdata);
361 if (ret) {
362 /* got error */
363 break;
367 SAFE_FREE(ip_list);
369 return ret;
372 #ifdef HEIMDAL_KRB5_LOCATE_PLUGIN_H
373 #define SMB_KRB5_LOCATOR_SYMBOL_NAME resolve /* Heimdal */
374 #else
375 #define SMB_KRB5_LOCATOR_SYMBOL_NAME service_locator /* MIT */
376 #endif
378 const krb5plugin_service_locate_ftable SMB_KRB5_LOCATOR_SYMBOL_NAME = {
379 0, /* version */
380 smb_krb5_locator_init,
381 smb_krb5_locator_close,
382 smb_krb5_locator_lookup,
385 #endif