2 Unix SMB/CIFS implementation.
3 Async DNS kerberos locator plugin
4 Copyright (C) Guenther Deschner 2007-2008
5 Copyright (C) Jeremy Allison 2020.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "../../source3/include/includes.h"
22 #include "../../source3/libsmb/namequery.h"
28 /* Uncomment to debug. */
29 /* #define DEBUG_KRB5 1 */
31 #if defined(HAVE_KRB5) && defined(HAVE_KRB5_LOCATE_PLUGIN_H)
38 #include <krb5/locate_plugin.h>
40 #ifndef KRB5_PLUGIN_NO_HANDLE
41 #define KRB5_PLUGIN_NO_HANDLE KRB5_KDC_UNREACH /* Heimdal */
44 struct singleton_realm_kdc_list_cache
{
46 struct samba_sockaddr
*kdc_list
;
50 static struct singleton_realm_kdc_list_cache
*scache
;
52 static const char *get_service_from_locate_service_type(enum locate_service_type svc
)
55 case locate_service_kdc
:
56 case locate_service_master_kdc
:
58 case locate_service_kadmin
:
59 case locate_service_krb524
:
62 case locate_service_kpasswd
:
72 static const char *locate_service_type_name(enum locate_service_type svc
)
75 case locate_service_kdc
:
76 return "locate_service_kdc";
77 case locate_service_master_kdc
:
78 return "locate_service_master_kdc";
79 case locate_service_kadmin
:
80 return "locate_service_kadmin";
81 case locate_service_krb524
:
82 return "locate_service_krb524";
83 case locate_service_kpasswd
:
84 return "locate_service_kpasswd";
91 static const char *socktype_name(int socktype
)
104 static const char *family_name(int family
)
111 #if defined(HAVE_IPV6)
123 * Check input parameters, return KRB5_PLUGIN_NO_HANDLE for unsupported ones
126 * @param realm string
127 * @param socktype integer
128 * @param family integer
133 static int smb_krb5_adns_locator_lookup_sanity_check(
134 enum locate_service_type svc
,
139 if (!realm
|| strlen(realm
) == 0) {
144 case locate_service_kdc
:
145 case locate_service_master_kdc
:
147 case locate_service_kadmin
:
148 case locate_service_krb524
:
149 case locate_service_kpasswd
:
150 return KRB5_PLUGIN_NO_HANDLE
;
158 #if defined(HAVE_IPV6)
169 case 0: /* Heimdal uses that */
179 * Call back into the MIT libraries with each address
180 * we found. Assume AD-DC's always support both UDP and
181 * TCP port 88 for KDC service.
184 static krb5_error_code
smb_krb5_adns_locator_call_cbfunc(
185 struct samba_sockaddr
*kdcs
,
189 int (*cbfunc
)(void *, int, struct sockaddr
*),
195 for (i
= 0; i
< num_kdcs
; i
++) {
196 struct sockaddr
*sa
= NULL
;
198 if (kdcs
[i
].u
.ss
.ss_family
== AF_INET
) {
199 struct sockaddr_in
*sin
= &kdcs
[i
].u
.in
;
200 sin
->sin_family
= AF_INET
;
201 sin
->sin_port
= htons(88);
204 #if defined(HAVE_IPV6)
205 if (kdcs
[i
].u
.ss
.ss_family
== AF_INET6
) {
206 struct sockaddr_in6
*sin6
= &kdcs
[i
].u
.in6
;
207 sin6
->sin6_family
= AF_INET6
;
208 sin6
->sin6_port
= htons(88);
213 return KRB5_PLUGIN_NO_HANDLE
;
219 char addr
[INET6_ADDRSTRLEN
];
220 fprintf(stderr
, "[%5u]: "
221 "smb_krb5_adns_locator_call_cbfunc: "
223 (unsigned int)getpid(),
231 /* Assume all AD-DC's do both UDP and TCP on port 88. */
232 ret
= cbfunc(cbdata
, socktype
, sa
);
235 fprintf(stderr
, "[%5u]: "
236 "smb_krb5_adns_locator_call_cbfunc: "
237 "failed to call callback: %s (%d)\n",
238 (unsigned int)getpid(),
249 * PUBLIC INTERFACE: locate init
251 * @param context krb5_context
252 * @param privata_data pointer to private data pointer
254 * @return krb5_error_code.
257 static krb5_error_code
smb_krb5_adns_locator_init(krb5_context context
,
260 static bool loaded_config
;
261 if (!loaded_config
) {
262 lp_load_global(get_dyn_CONFIGFILE());
263 loaded_config
= true;
266 fprintf(stderr
,"[%5u]: smb_krb5_adns_locator_init\n",
267 (unsigned int)getpid());
273 * PUBLIC INTERFACE: close locate
275 * @param private_data pointer to private data
280 static void smb_krb5_adns_locator_close(void *private_data
)
283 fprintf(stderr
,"[%5u]: smb_krb5_adns_locator_close\n",
284 (unsigned int)getpid());
290 * PUBLIC INTERFACE: locate lookup
292 * @param private_data pointer to private data
293 * @param svc enum locate_service_type.
294 * @param realm string
295 * @param socktype integer
296 * @param family integer
297 * @param cbfunc callback function to send back entries
298 * @param cbdata void pointer to cbdata
300 * @return krb5_error_code.
303 static krb5_error_code
smb_krb5_adns_locator_lookup(void *private_data
,
304 enum locate_service_type svc
,
308 int (*cbfunc
)(void *, int, struct sockaddr
*),
312 const char *service
= get_service_from_locate_service_type(svc
);
315 fprintf(stderr
,"[%5u]: smb_krb5_adns_locator_lookup: called for '%s' "
317 "socktype: '%s' (%d), family: '%s' (%d)\n",
318 (unsigned int)getpid(),
320 locate_service_type_name(svc
),
322 socktype_name(socktype
),
327 ret
= smb_krb5_adns_locator_lookup_sanity_check(svc
,
333 fprintf(stderr
, "[%5u]: smb_krb5_adns_locator_lookup: "
334 "returning ret: %s (%d)\n",
335 (unsigned int)getpid(),
343 * If is a subsequent lookup for the same realm
344 * and we have a cache for this already, don't re-do
345 * the DNS SRV -> A/AAAA lookups.
347 * kinit does this a lot, it looks for UDP then TCP.
350 if ((scache
== NULL
) || strcmp(realm
, scache
->realm
) != 0) {
351 /* Cache is NULL or a different realm lookup. */
355 * We have a new lookup to do. As it's a singleton
356 * cache make sure we have no old cache.
360 scache
= talloc_zero(NULL
,
361 struct singleton_realm_kdc_list_cache
);
362 if (scache
== NULL
) {
363 return KRB5_PLUGIN_NO_HANDLE
;
365 scache
->realm
= talloc_strdup(scache
, realm
);
366 if (scache
->realm
== NULL
) {
368 return KRB5_PLUGIN_NO_HANDLE
;
371 status
= get_kdc_list(scache
,
376 if (!NT_STATUS_IS_OK(status
)) {
378 fprintf(stderr
, "[%5u]: "
379 "smb_krb5_adns_locator_lookup: "
380 "get_kdc_list() for realm %s failed "
382 (unsigned int)getpid(),
387 return KRB5_PLUGIN_NO_HANDLE
;
389 if (scache
->num_kdcs
== 0) {
391 return KRB5_PLUGIN_NO_HANDLE
;
396 fprintf(stderr
, "[%5u]: "
397 "smb_krb5_adns_locator_lookup: "
398 "returning cached data for realm %s\n",
399 (unsigned int)getpid(),
404 * If we get here we know scache contains the right
405 * realm and non-null address list.
409 fprintf(stderr
, "[%5u]: smb_krb5_adns_locator_lookup: "
410 "got %zu IP addresses for realm %s\n",
411 (unsigned int)getpid(),
417 * Don't free kdc list on success, we're
418 * always returning from the cache.
420 return smb_krb5_adns_locator_call_cbfunc(scache
->kdc_list
,
428 #ifdef HEIMDAL_KRB5_LOCATE_PLUGIN_H
429 #define SMB_KRB5_LOCATOR_SYMBOL_NAME resolve /* Heimdal */
431 #define SMB_KRB5_LOCATOR_SYMBOL_NAME service_locator /* MIT */
434 _PUBLIC_
const krb5plugin_service_locate_ftable SMB_KRB5_LOCATOR_SYMBOL_NAME
= {
436 .init
= smb_krb5_adns_locator_init
,
437 .fini
= smb_krb5_adns_locator_close
,
438 #ifdef KRB5_PLUGIN_LOCATE_VERSION_2
439 .old_lookup
= smb_krb5_adns_locator_lookup
,
441 .lookup
= smb_krb5_adns_locator_lookup
,