• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/samba-3.0.25b/source/libads/
1/*
2   Unix SMB/CIFS implementation.
3   kerberos locator plugin
4   Copyright (C) Guenther Deschner 2007
5
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 2 of the License, or
9   (at your option) any later version.
10
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.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21#include "includes.h"
22
23#if defined(HAVE_KRB5) && defined(HAVE_KRB5_LOCATE_PLUGIN_H)
24
25#include <krb5/locate_plugin.h>
26
27static const char *get_service_from_locate_service_type(enum locate_service_type svc)
28{
29	switch (svc) {
30		case locate_service_kdc:
31		case locate_service_master_kdc:
32			return "88";
33		case locate_service_kadmin:
34		case locate_service_krb524:
35			/* not supported */
36			return NULL;
37		case locate_service_kpasswd:
38			return "464";
39		default:
40			break;
41	}
42	return NULL;
43
44}
45
46static const char *locate_service_type_name(enum locate_service_type svc)
47{
48	switch (svc) {
49		case locate_service_kdc:
50			return "locate_service_kdc";
51		case locate_service_master_kdc:
52			return "locate_service_master_kdc";
53		case locate_service_kadmin:
54			return "locate_service_kadmin";
55		case locate_service_krb524:
56			return "locate_service_krb524";
57		case locate_service_kpasswd:
58			return "locate_service_kpasswd";
59		default:
60			break;
61	}
62	return NULL;
63}
64
65static const char *socktype_name(int socktype)
66{
67	switch (socktype) {
68		case SOCK_STREAM:
69			return "SOCK_STREAM";
70		case SOCK_DGRAM:
71			return "SOCK_DGRAM";
72		default:
73			break;
74	}
75	return "unknown";
76}
77
78static const char *family_name(int family)
79{
80	switch (family) {
81		case AF_UNSPEC:
82			return "AF_UNSPEC";
83		case AF_INET:
84			return "AF_INET";
85		case AF_INET6:
86			return "AF_INET6";
87		default:
88			break;
89	}
90	return "unknown";
91}
92
93/**
94 * Check input parameters, return KRB5_PLUGIN_NO_HANDLE for unsupported ones
95 *
96 * @param svc
97 * @param realm string
98 * @param socktype integer
99 * @param family integer
100 *
101 * @return integer.
102 */
103
104static int smb_krb5_locator_lookup_sanity_check(enum locate_service_type svc,
105						const char *realm,
106						int socktype,
107						int family)
108{
109	if (!realm || strlen(realm) == 0) {
110		return EINVAL;
111	}
112
113	switch (svc) {
114		case locate_service_kdc:
115		case locate_service_master_kdc:
116		case locate_service_kpasswd:
117			break;
118		case locate_service_kadmin:
119		case locate_service_krb524:
120#ifdef KRB5_PLUGIN_NO_HANDLE
121			return KRB5_PLUGIN_NO_HANDLE;
122#else
123			return KRB5_KDC_UNREACH; /* Heimdal */
124#endif
125		default:
126			return EINVAL;
127	}
128
129	switch (family) {
130		case AF_UNSPEC:
131		case AF_INET:
132			break;
133		case AF_INET6: /* not yet */
134#ifdef KRB5_PLUGIN_NO_HANDLE
135			return KRB5_PLUGIN_NO_HANDLE;
136#else
137			return KRB5_KDC_UNREACH; /* Heimdal */
138#endif
139		default:
140			return EINVAL;
141	}
142
143	switch (socktype) {
144		case SOCK_STREAM:
145		case SOCK_DGRAM:
146		case 0: /* Heimdal uses that */
147			break;
148		default:
149			return EINVAL;
150	}
151
152	return 0;
153}
154
155/**
156 * Try to get addrinfo for a given host and call the krb5 callback
157 *
158 * @param name string
159 * @param service string
160 * @param in struct addrinfo hint
161 * @param cbfunc krb5 callback function
162 * @param cbdata void pointer cbdata
163 *
164 * @return krb5_error_code.
165 */
166
167static krb5_error_code smb_krb5_locator_call_cbfunc(const char *name,
168						    const char *service,
169						    struct addrinfo *in,
170						    int (*cbfunc)(void *, int, struct sockaddr *),
171						    void *cbdata)
172{
173	struct addrinfo *out;
174	int ret;
175	int count = 3;
176
177	while (count) {
178
179		ret = getaddrinfo(name, service, in, &out);
180		if (ret == 0) {
181			break;
182		}
183
184		if (ret == EAI_AGAIN) {
185			count--;
186			continue;
187		}
188
189		DEBUG(10,("smb_krb5_locator_lookup: got ret: %s (%d)\n",
190			gai_strerror(ret), ret));
191#ifdef KRB5_PLUGIN_NO_HANDLE
192		return KRB5_PLUGIN_NO_HANDLE;
193#else
194		return KRB5_KDC_UNREACH; /* Heimdal */
195#endif
196	}
197
198	ret = cbfunc(cbdata, out->ai_socktype, out->ai_addr);
199	if (ret) {
200		DEBUG(10,("smb_krb5_locator_lookup: failed to call callback: %s (%d)\n",
201			error_message(ret), ret));
202	}
203
204	freeaddrinfo(out);
205
206	return ret;
207}
208
209/**
210 * PUBLIC INTERFACE: locate init
211 *
212 * @param context krb5_context
213 * @param privata_data pointer to private data pointer
214 *
215 * @return krb5_error_code.
216 */
217
218krb5_error_code smb_krb5_locator_init(krb5_context context,
219				      void **private_data)
220{
221	setup_logging("smb_krb5_locator", True);
222	load_case_tables();
223	lp_load(dyn_CONFIGFILE,True,False,False,True);
224
225	DEBUG(10,("smb_krb5_locator_init: called\n"));
226
227	return 0;
228}
229
230/**
231 * PUBLIC INTERFACE: close locate
232 *
233 * @param private_data pointer to private data
234 *
235 * @return void.
236 */
237
238void smb_krb5_locator_close(void *private_data)
239{
240	DEBUG(10,("smb_krb5_locator_close: called\n"));
241
242	/* gfree_all(); */
243}
244
245/**
246 * PUBLIC INTERFACE: locate lookup
247 *
248 * @param private_data pointer to private data
249 * @param svc enum locate_service_type.
250 * @param realm string
251 * @param socktype integer
252 * @param family integer
253 * @param cbfunc callback function to send back entries
254 * @param cbdata void pointer to cbdata
255 *
256 * @return krb5_error_code.
257 */
258
259krb5_error_code smb_krb5_locator_lookup(void *private_data,
260					enum locate_service_type svc,
261					const char *realm,
262					int socktype,
263					int family,
264					int (*cbfunc)(void *, int, struct sockaddr *),
265					void *cbdata)
266{
267	NTSTATUS status;
268	krb5_error_code ret;
269	char *sitename = NULL;
270	struct ip_service *ip_list;
271	int count = 0;
272	struct addrinfo aihints;
273	char *saf_name = NULL;
274	int i;
275
276	DEBUG(10,("smb_krb5_locator_lookup: called for\n"));
277	DEBUGADD(10,("\tsvc: %s (%d), realm: %s\n",
278		locate_service_type_name(svc), svc, realm));
279	DEBUGADD(10,("\tsocktype: %s (%d), family: %s (%d)\n",
280		socktype_name(socktype), socktype,
281	        family_name(family), family));
282
283	ret = smb_krb5_locator_lookup_sanity_check(svc, realm, socktype, family);
284	if (ret) {
285		DEBUG(10,("smb_krb5_locator_lookup: returning ret: %s (%d)\n",
286			error_message(ret), ret));
287		return ret;
288	}
289
290	/* first try to fetch from SAF cache */
291
292	saf_name = saf_fetch(realm);
293	if (!saf_name || strlen(saf_name) == 0) {
294		DEBUG(10,("smb_krb5_locator_lookup: no SAF name stored for %s\n",
295			realm));
296		goto find_kdc;
297	}
298
299	DEBUG(10,("smb_krb5_locator_lookup: got %s for %s from SAF cache\n",
300		saf_name, realm));
301
302	ZERO_STRUCT(aihints);
303
304	aihints.ai_family = family;
305	aihints.ai_socktype = socktype;
306
307	ret = smb_krb5_locator_call_cbfunc(saf_name,
308					  get_service_from_locate_service_type(svc),
309					  &aihints,
310					  cbfunc, cbdata);
311	if (ret) {
312		return ret;
313	}
314
315	return 0;
316
317 find_kdc:
318
319	/* now try to find via site-aware DNS SRV query */
320
321	sitename = sitename_fetch(realm);
322	status = get_kdc_list(realm, sitename, &ip_list, &count);
323
324	/* if we didn't found any KDCs on our site go to the main list */
325
326	if (NT_STATUS_IS_OK(status) && sitename && (count == 0)) {
327		SAFE_FREE(ip_list);
328		SAFE_FREE(sitename);
329		status = get_kdc_list(realm, NULL, &ip_list, &count);
330	}
331
332	SAFE_FREE(sitename);
333
334	if (!NT_STATUS_IS_OK(status)) {
335		DEBUG(10,("smb_krb5_locator_lookup: got %s (%s)\n",
336			nt_errstr(status),
337			error_message(nt_status_to_krb5(status))));
338#ifdef KRB5_PLUGIN_NO_HANDLE
339		return KRB5_PLUGIN_NO_HANDLE;
340#else
341		return KRB5_KDC_UNREACH; /* Heimdal */
342#endif
343	}
344
345	for (i=0; i<count; i++) {
346
347		const char *host = NULL;
348		const char *port = NULL;
349
350		ZERO_STRUCT(aihints);
351
352		aihints.ai_family = family;
353		aihints.ai_socktype = socktype;
354
355		host = inet_ntoa(ip_list[i].ip);
356		port = get_service_from_locate_service_type(svc);
357
358		ret = smb_krb5_locator_call_cbfunc(host,
359						  port,
360						  &aihints,
361						  cbfunc, cbdata);
362		if (ret) {
363			/* got error */
364			break;
365		}
366	}
367
368	SAFE_FREE(ip_list);
369
370	return ret;
371}
372
373#ifdef HEIMDAL_KRB5_LOCATE_PLUGIN_H
374#define SMB_KRB5_LOCATOR_SYMBOL_NAME resolve /* Heimdal */
375#else
376#define SMB_KRB5_LOCATOR_SYMBOL_NAME service_locator /* MIT */
377#endif
378
379const krb5plugin_service_locate_ftable SMB_KRB5_LOCATOR_SYMBOL_NAME = {
380	0, /* version */
381	smb_krb5_locator_init,
382	smb_krb5_locator_close,
383	smb_krb5_locator_lookup,
384};
385
386#endif
387