2 Unix SMB/CIFS implementation.
3 kerberos locator plugin
4 Copyright (C) Guenther Deschner 2007-2008
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 "nsswitch/winbind_client.h"
21 #include "libwbclient/wbclient.h"
27 #if defined(HAVE_KRB5) && defined(HAVE_KRB5_LOCATE_PLUGIN_H)
34 #include <krb5/locate_plugin.h>
36 #ifndef KRB5_PLUGIN_NO_HANDLE
37 #define KRB5_PLUGIN_NO_HANDLE KRB5_KDC_UNREACH /* Heimdal */
40 static const char *get_service_from_locate_service_type(enum locate_service_type svc)
43 case locate_service_kdc:
44 case locate_service_master_kdc:
46 case locate_service_kadmin:
47 case locate_service_krb524:
50 case locate_service_kpasswd:
60 static const char *locate_service_type_name(enum locate_service_type svc)
63 case locate_service_kdc:
64 return "locate_service_kdc";
65 case locate_service_master_kdc:
66 return "locate_service_master_kdc";
67 case locate_service_kadmin:
68 return "locate_service_kadmin";
69 case locate_service_krb524:
70 return "locate_service_krb524";
71 case locate_service_kpasswd:
72 return "locate_service_kpasswd";
79 static const char *socktype_name(int socktype)
92 static const char *family_name(int family)
99 #if defined(HAVE_IPV6)
111 * Check input parameters, return KRB5_PLUGIN_NO_HANDLE for unsupported ones
114 * @param realm string
115 * @param socktype integer
116 * @param family integer
121 static int smb_krb5_locator_lookup_sanity_check(enum locate_service_type svc,
126 if (!realm || strlen(realm) == 0) {
131 case locate_service_kdc:
132 case locate_service_master_kdc:
133 case locate_service_kpasswd:
135 case locate_service_kadmin:
136 case locate_service_krb524:
137 return KRB5_PLUGIN_NO_HANDLE;
146 #if defined(HAVE_IPV6)
157 case 0: /* Heimdal uses that */
167 * Try to get addrinfo for a given host and call the krb5 callback
170 * @param service string
171 * @param in struct addrinfo hint
172 * @param cbfunc krb5 callback function
173 * @param cbdata void pointer cbdata
175 * @return krb5_error_code.
178 static krb5_error_code smb_krb5_locator_call_cbfunc(const char *name,
181 int (*cbfunc)(void *, int, struct sockaddr *),
184 struct addrinfo *out = NULL;
186 struct addrinfo *res = NULL;
191 ret = getaddrinfo(name, service, in, &out);
196 if ((ret == EAI_AGAIN) && (count > 1)) {
202 fprintf(stderr, "[%5u]: smb_krb5_locator_lookup: "
203 "getaddrinfo failed: %s (%d)\n",
204 (unsigned int)getpid(), gai_strerror(ret), ret);
207 return KRB5_PLUGIN_NO_HANDLE;
210 for (res = out; res; res = res->ai_next) {
211 if (!res->ai_addr || res->ai_addrlen == 0) {
215 ret = cbfunc(cbdata, res->ai_socktype, res->ai_addr);
218 fprintf(stderr, "[%5u]: smb_krb5_locator_lookup: "
219 "failed to call callback: %s (%d)\n",
220 (unsigned int)getpid(), error_message(ret), ret);
233 * PUBLIC INTERFACE: locate init
235 * @param context krb5_context
236 * @param privata_data pointer to private data pointer
238 * @return krb5_error_code.
241 static krb5_error_code smb_krb5_locator_init(krb5_context context,
248 * PUBLIC INTERFACE: close locate
250 * @param private_data pointer to private data
255 static void smb_krb5_locator_close(void *private_data)
261 static bool ask_winbind(const char *realm, char **dcname)
264 const char *dc = NULL;
265 struct wbcDomainControllerInfoEx *dc_info = NULL;
268 flags = WBC_LOOKUP_DC_KDC_REQUIRED |
269 WBC_LOOKUP_DC_IS_DNS_NAME |
270 WBC_LOOKUP_DC_RETURN_DNS_NAME;
272 wbc_status = wbcLookupDomainControllerEx(realm, NULL, NULL, flags, &dc_info);
274 if (!WBC_ERROR_IS_OK(wbc_status)) {
276 fprintf(stderr,"[%5u]: smb_krb5_locator_lookup: failed with: %s\n",
277 (unsigned int)getpid(), wbcErrorString(wbc_status));
282 if (!dc && dc_info->dc_unc) {
283 dc = dc_info->dc_unc;
284 if (dc[0] == '\\') dc++;
285 if (dc[0] == '\\') dc++;
289 wbcFreeMemory(dc_info);
293 *dcname = strdup(dc);
295 wbcFreeMemory(dc_info);
299 wbcFreeMemory(dc_info);
304 * PUBLIC INTERFACE: locate lookup
306 * @param private_data pointer to private data
307 * @param svc enum locate_service_type.
308 * @param realm string
309 * @param socktype integer
310 * @param family integer
311 * @param cbfunc callback function to send back entries
312 * @param cbdata void pointer to cbdata
314 * @return krb5_error_code.
317 static krb5_error_code smb_krb5_locator_lookup(void *private_data,
318 enum locate_service_type svc,
322 int (*cbfunc)(void *, int, struct sockaddr *),
326 struct addrinfo aihints;
327 char *kdc_name = NULL;
328 const char *service = get_service_from_locate_service_type(svc);
330 ZERO_STRUCT(aihints);
333 fprintf(stderr,"[%5u]: smb_krb5_locator_lookup: called for '%s' "
335 "socktype: '%s' (%d), family: '%s' (%d)\n",
336 (unsigned int)getpid(), realm,
337 locate_service_type_name(svc), svc,
338 socktype_name(socktype), socktype,
339 family_name(family), family);
341 ret = smb_krb5_locator_lookup_sanity_check(svc, realm, socktype,
345 fprintf(stderr, "[%5u]: smb_krb5_locator_lookup: "
346 "returning ret: %s (%d)\n",
347 (unsigned int)getpid(), error_message(ret), ret);
352 if (!winbind_env_set()) {
353 if (!ask_winbind(realm, &kdc_name)) {
355 fprintf(stderr, "[%5u]: smb_krb5_locator_lookup: "
356 "failed to query winbindd\n",
357 (unsigned int)getpid());
362 const char *env = NULL;
364 if (asprintf(&var, "%s_%s",
365 WINBINDD_LOCATOR_KDC_ADDRESS, realm) == -1) {
371 fprintf(stderr, "[%5u]: smb_krb5_locator_lookup: "
372 "failed to get kdc from env %s\n",
373 (unsigned int)getpid(), var);
380 kdc_name = strdup(env);
386 fprintf(stderr, "[%5u]: smb_krb5_locator_lookup: "
387 "got '%s' for '%s' from winbindd\n", (unsigned int)getpid(),
391 aihints.ai_family = family;
392 aihints.ai_socktype = socktype;
394 ret = smb_krb5_locator_call_cbfunc(kdc_name,
403 return KRB5_PLUGIN_NO_HANDLE;
406 #ifdef HEIMDAL_KRB5_LOCATE_PLUGIN_H
407 #define SMB_KRB5_LOCATOR_SYMBOL_NAME resolve /* Heimdal */
409 #define SMB_KRB5_LOCATOR_SYMBOL_NAME service_locator /* MIT */
412 const krb5plugin_service_locate_ftable SMB_KRB5_LOCATOR_SYMBOL_NAME = {
414 smb_krb5_locator_init,
415 smb_krb5_locator_close,
416 smb_krb5_locator_lookup,