Fix warnings with talloc_asprintf.
[Samba/fernandojvsilva.git] / nsswitch / winbind_krb5_locator.c
blob272e7dbab153bacc2a28a468e88a31bbce23228f
1 /*
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"
23 #ifndef DEBUG_KRB5
24 #undef DEBUG_KRB5
25 #endif
27 #if defined(HAVE_KRB5) && defined(HAVE_KRB5_LOCATE_PLUGIN_H)
29 #include <krb5/krb5.h>
30 #include <krb5/locate_plugin.h>
32 #ifndef KRB5_PLUGIN_NO_HANDLE
33 #define KRB5_PLUGIN_NO_HANDLE KRB5_KDC_UNREACH /* Heimdal */
34 #endif
36 static const char *get_service_from_locate_service_type(enum locate_service_type svc)
38 switch (svc) {
39 case locate_service_kdc:
40 case locate_service_master_kdc:
41 return "88";
42 case locate_service_kadmin:
43 case locate_service_krb524:
44 /* not supported */
45 return NULL;
46 case locate_service_kpasswd:
47 return "464";
48 default:
49 break;
51 return NULL;
55 #ifdef DEBUG_KRB5
56 static const char *locate_service_type_name(enum locate_service_type svc)
58 switch (svc) {
59 case locate_service_kdc:
60 return "locate_service_kdc";
61 case locate_service_master_kdc:
62 return "locate_service_master_kdc";
63 case locate_service_kadmin:
64 return "locate_service_kadmin";
65 case locate_service_krb524:
66 return "locate_service_krb524";
67 case locate_service_kpasswd:
68 return "locate_service_kpasswd";
69 default:
70 break;
72 return NULL;
75 static const char *socktype_name(int socktype)
77 switch (socktype) {
78 case SOCK_STREAM:
79 return "SOCK_STREAM";
80 case SOCK_DGRAM:
81 return "SOCK_DGRAM";
82 default:
83 break;
85 return "unknown";
88 static const char *family_name(int family)
90 switch (family) {
91 case AF_UNSPEC:
92 return "AF_UNSPEC";
93 case AF_INET:
94 return "AF_INET";
95 #if defined(HAVE_IPV6)
96 case AF_INET6:
97 return "AF_INET6";
98 #endif
99 default:
100 break;
102 return "unknown";
104 #endif
107 * Check input parameters, return KRB5_PLUGIN_NO_HANDLE for unsupported ones
109 * @param svc
110 * @param realm string
111 * @param socktype integer
112 * @param family integer
114 * @return integer.
117 static int smb_krb5_locator_lookup_sanity_check(enum locate_service_type svc,
118 const char *realm,
119 int socktype,
120 int family)
122 if (!realm || strlen(realm) == 0) {
123 return EINVAL;
126 switch (svc) {
127 case locate_service_kdc:
128 case locate_service_master_kdc:
129 case locate_service_kpasswd:
130 break;
131 case locate_service_kadmin:
132 case locate_service_krb524:
133 return KRB5_PLUGIN_NO_HANDLE;
134 default:
135 return EINVAL;
138 switch (family) {
139 case AF_UNSPEC:
140 case AF_INET:
141 break;
142 #if defined(HAVE_IPV6)
143 case AF_INET6:
144 break;
145 #endif
146 default:
147 return EINVAL;
150 switch (socktype) {
151 case SOCK_STREAM:
152 case SOCK_DGRAM:
153 case 0: /* Heimdal uses that */
154 break;
155 default:
156 return EINVAL;
159 return 0;
163 * Try to get addrinfo for a given host and call the krb5 callback
165 * @param name string
166 * @param service string
167 * @param in struct addrinfo hint
168 * @param cbfunc krb5 callback function
169 * @param cbdata void pointer cbdata
171 * @return krb5_error_code.
174 static krb5_error_code smb_krb5_locator_call_cbfunc(const char *name,
175 const char *service,
176 struct addrinfo *in,
177 int (*cbfunc)(void *, int, struct sockaddr *),
178 void *cbdata)
180 struct addrinfo *out = NULL;
181 int ret;
182 int count = 3;
184 while (count) {
186 ret = getaddrinfo(name, service, in, &out);
187 if (ret == 0) {
188 break;
191 if (ret == EAI_AGAIN) {
192 count--;
193 continue;
196 #ifdef DEBUG_KRB5
197 fprintf(stderr, "[%5u]: smb_krb5_locator_lookup: "
198 "getaddrinfo failed: %s (%d)\n",
199 (unsigned int)getpid(), gai_strerror(ret), ret);
200 #endif
202 return KRB5_PLUGIN_NO_HANDLE;
205 ret = cbfunc(cbdata, out->ai_socktype, out->ai_addr);
206 #ifdef DEBUG_KRB5
207 if (ret) {
208 fprintf(stderr, "[%5u]: smb_krb5_locator_lookup: "
209 "failed to call callback: %s (%d)\n",
210 (unsigned int)getpid(), error_message(ret), ret);
212 #endif
214 freeaddrinfo(out);
215 return ret;
219 * PUBLIC INTERFACE: locate init
221 * @param context krb5_context
222 * @param privata_data pointer to private data pointer
224 * @return krb5_error_code.
227 static krb5_error_code smb_krb5_locator_init(krb5_context context,
228 void **private_data)
230 return 0;
234 * PUBLIC INTERFACE: close locate
236 * @param private_data pointer to private data
238 * @return void.
241 static void smb_krb5_locator_close(void *private_data)
243 return;
247 static bool ask_winbind(const char *realm, char **dcname)
249 wbcErr wbc_status;
250 const char *dc = NULL;
251 struct wbcDomainControllerInfoEx *dc_info = NULL;
252 uint32_t flags;
254 flags = WBC_LOOKUP_DC_KDC_REQUIRED |
255 WBC_LOOKUP_DC_IS_DNS_NAME |
256 WBC_LOOKUP_DC_RETURN_DNS_NAME |
257 WBC_LOOKUP_DC_IP_REQUIRED;
259 wbc_status = wbcLookupDomainControllerEx(realm, NULL, NULL, flags, &dc_info);
261 if (!WBC_ERROR_IS_OK(wbc_status)) {
262 #ifdef DEBUG_KRB5
263 fprintf(stderr,"[%5u]: smb_krb5_locator_lookup: failed with: %s\n",
264 (unsigned int)getpid(), wbcErrorString(wbc_status));
265 #endif
266 return false;
269 if (dc_info->dc_address) {
270 dc = dc_info->dc_address;
271 if (dc[0] == '\\') dc++;
272 if (dc[0] == '\\') dc++;
275 if (!dc && dc_info->dc_unc) {
276 dc = dc_info->dc_unc;
277 if (dc[0] == '\\') dc++;
278 if (dc[0] == '\\') dc++;
281 if (!dc) {
282 wbcFreeMemory(dc_info);
283 return false;
286 *dcname = strdup(dc);
287 if (!*dcname) {
288 wbcFreeMemory(dc_info);
289 return false;
292 wbcFreeMemory(dc_info);
293 return true;
297 * PUBLIC INTERFACE: locate lookup
299 * @param private_data pointer to private data
300 * @param svc enum locate_service_type.
301 * @param realm string
302 * @param socktype integer
303 * @param family integer
304 * @param cbfunc callback function to send back entries
305 * @param cbdata void pointer to cbdata
307 * @return krb5_error_code.
310 static krb5_error_code smb_krb5_locator_lookup(void *private_data,
311 enum locate_service_type svc,
312 const char *realm,
313 int socktype,
314 int family,
315 int (*cbfunc)(void *, int, struct sockaddr *),
316 void *cbdata)
318 krb5_error_code ret;
319 struct addrinfo aihints;
320 char *kdc_name = NULL;
321 const char *service = get_service_from_locate_service_type(svc);
323 ZERO_STRUCT(aihints);
325 #ifdef DEBUG_KRB5
326 fprintf(stderr,"[%5u]: smb_krb5_locator_lookup: called for '%s' "
327 "svc: '%s' (%d) "
328 "socktype: '%s' (%d), family: '%s' (%d)\n",
329 (unsigned int)getpid(), realm,
330 locate_service_type_name(svc), svc,
331 socktype_name(socktype), socktype,
332 family_name(family), family);
333 #endif
334 ret = smb_krb5_locator_lookup_sanity_check(svc, realm, socktype,
335 family);
336 if (ret) {
337 #ifdef DEBUG_KRB5
338 fprintf(stderr, "[%5u]: smb_krb5_locator_lookup: "
339 "returning ret: %s (%d)\n",
340 (unsigned int)getpid(), error_message(ret), ret);
341 #endif
342 return ret;
345 if (!winbind_env_set()) {
346 if (!ask_winbind(realm, &kdc_name)) {
347 #ifdef DEBUG_KRB5
348 fprintf(stderr, "[%5u]: smb_krb5_locator_lookup: "
349 "failed to query winbindd\n",
350 (unsigned int)getpid());
351 #endif
352 goto failed;
354 } else {
355 const char *env = NULL;
356 char *var = NULL;
357 if (asprintf(&var, "%s_%s",
358 WINBINDD_LOCATOR_KDC_ADDRESS, realm) == -1) {
359 goto failed;
361 env = getenv(var);
362 if (!env) {
363 #ifdef DEBUG_KRB5
364 fprintf(stderr, "[%5u]: smb_krb5_locator_lookup: "
365 "failed to get kdc from env %s\n",
366 (unsigned int)getpid(), var);
367 #endif
368 free(var);
369 goto failed;
371 free(var);
373 kdc_name = strdup(env);
374 if (!kdc_name) {
375 goto failed;
378 #ifdef DEBUG_KRB5
379 fprintf(stderr, "[%5u]: smb_krb5_locator_lookup: "
380 "got '%s' for '%s' from winbindd\n", (unsigned int)getpid(),
381 kdc_name, realm);
382 #endif
384 aihints.ai_family = family;
385 aihints.ai_socktype = socktype;
387 ret = smb_krb5_locator_call_cbfunc(kdc_name,
388 service,
389 &aihints,
390 cbfunc, cbdata);
391 SAFE_FREE(kdc_name);
393 return ret;
395 failed:
396 return KRB5_PLUGIN_NO_HANDLE;
399 #ifdef HEIMDAL_KRB5_LOCATE_PLUGIN_H
400 #define SMB_KRB5_LOCATOR_SYMBOL_NAME resolve /* Heimdal */
401 #else
402 #define SMB_KRB5_LOCATOR_SYMBOL_NAME service_locator /* MIT */
403 #endif
405 const krb5plugin_service_locate_ftable SMB_KRB5_LOCATOR_SYMBOL_NAME = {
406 0, /* version */
407 smb_krb5_locator_init,
408 smb_krb5_locator_close,
409 smb_krb5_locator_lookup,
412 #endif