mount.cifs: check access of credential files before opening
[Samba.git] / source / libads / smb_krb5_locator.c
blobbe14a12697463b6222d7e9c8c4b3d680cd6607ec
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 2 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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "includes.h"
23 #if defined(HAVE_KRB5) && defined(HAVE_KRB5_LOCATE_PLUGIN_H)
25 #include <krb5/locate_plugin.h>
27 static const char *get_service_from_locate_service_type(enum locate_service_type svc)
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;
42 return NULL;
46 static const char *locate_service_type_name(enum locate_service_type svc)
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;
62 return NULL;
65 static const char *socktype_name(int socktype)
67 switch (socktype) {
68 case SOCK_STREAM:
69 return "SOCK_STREAM";
70 case SOCK_DGRAM:
71 return "SOCK_DGRAM";
72 default:
73 break;
75 return "unknown";
78 static const char *family_name(int family)
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;
90 return "unknown";
93 /**
94 * Check input parameters, return KRB5_PLUGIN_NO_HANDLE for unsupported ones
96 * @param svc
97 * @param realm string
98 * @param socktype integer
99 * @param family integer
101 * @return integer.
104 static int smb_krb5_locator_lookup_sanity_check(enum locate_service_type svc,
105 const char *realm,
106 int socktype,
107 int family)
109 if (!realm || strlen(realm) == 0) {
110 return EINVAL;
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;
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;
143 switch (socktype) {
144 case SOCK_STREAM:
145 case SOCK_DGRAM:
146 case 0: /* Heimdal uses that */
147 break;
148 default:
149 return EINVAL;
152 return 0;
156 * Try to get addrinfo for a given host and call the krb5 callback
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
164 * @return krb5_error_code.
167 static 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)
173 struct addrinfo *out;
174 int ret;
175 int count = 3;
177 while (count) {
179 ret = getaddrinfo(name, service, in, &out);
180 if (ret == 0) {
181 break;
184 if (ret == EAI_AGAIN) {
185 count--;
186 continue;
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
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));
204 freeaddrinfo(out);
206 return ret;
210 * PUBLIC INTERFACE: locate init
212 * @param context krb5_context
213 * @param privata_data pointer to private data pointer
215 * @return krb5_error_code.
218 krb5_error_code smb_krb5_locator_init(krb5_context context,
219 void **private_data)
221 setup_logging("smb_krb5_locator", True);
222 load_case_tables();
223 lp_load(dyn_CONFIGFILE,True,False,False,True);
225 DEBUG(10,("smb_krb5_locator_init: called\n"));
227 return 0;
231 * PUBLIC INTERFACE: close locate
233 * @param private_data pointer to private data
235 * @return void.
238 void smb_krb5_locator_close(void *private_data)
240 DEBUG(10,("smb_krb5_locator_close: called\n"));
242 /* gfree_all(); */
246 * PUBLIC INTERFACE: locate lookup
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
256 * @return krb5_error_code.
259 krb5_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)
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;
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));
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;
290 /* first try to fetch from SAF cache */
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;
299 DEBUG(10,("smb_krb5_locator_lookup: got %s for %s from SAF cache\n",
300 saf_name, realm));
302 ZERO_STRUCT(aihints);
304 aihints.ai_family = family;
305 aihints.ai_socktype = socktype;
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;
315 return 0;
317 find_kdc:
319 /* now try to find via site-aware DNS SRV query */
321 sitename = sitename_fetch(realm);
322 status = get_kdc_list(realm, sitename, &ip_list, &count);
324 /* if we didn't found any KDCs on our site go to the main list */
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);
332 SAFE_FREE(sitename);
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
345 for (i=0; i<count; i++) {
347 const char *host = NULL;
348 const char *port = NULL;
350 ZERO_STRUCT(aihints);
352 aihints.ai_family = family;
353 aihints.ai_socktype = socktype;
355 host = inet_ntoa(ip_list[i].ip);
356 port = get_service_from_locate_service_type(svc);
358 ret = smb_krb5_locator_call_cbfunc(host,
359 port,
360 &aihints,
361 cbfunc, cbdata);
362 if (ret) {
363 /* got error */
364 break;
368 SAFE_FREE(ip_list);
370 return ret;
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
379 const 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,
386 #endif