00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "includes.h"
00022
00023 #if defined(HAVE_KRB5) && defined(HAVE_KRB5_LOCATE_PLUGIN_H)
00024
00025 #include <krb5/locate_plugin.h>
00026
00027 static const char *get_service_from_locate_service_type(enum locate_service_type svc)
00028 {
00029 switch (svc) {
00030 case locate_service_kdc:
00031 case locate_service_master_kdc:
00032 return "88";
00033 case locate_service_kadmin:
00034 case locate_service_krb524:
00035
00036 return NULL;
00037 case locate_service_kpasswd:
00038 return "464";
00039 default:
00040 break;
00041 }
00042 return NULL;
00043
00044 }
00045
00046 static const char *locate_service_type_name(enum locate_service_type svc)
00047 {
00048 switch (svc) {
00049 case locate_service_kdc:
00050 return "locate_service_kdc";
00051 case locate_service_master_kdc:
00052 return "locate_service_master_kdc";
00053 case locate_service_kadmin:
00054 return "locate_service_kadmin";
00055 case locate_service_krb524:
00056 return "locate_service_krb524";
00057 case locate_service_kpasswd:
00058 return "locate_service_kpasswd";
00059 default:
00060 break;
00061 }
00062 return NULL;
00063 }
00064
00065 static const char *socktype_name(int socktype)
00066 {
00067 switch (socktype) {
00068 case SOCK_STREAM:
00069 return "SOCK_STREAM";
00070 case SOCK_DGRAM:
00071 return "SOCK_DGRAM";
00072 default:
00073 break;
00074 }
00075 return "unknown";
00076 }
00077
00078 static const char *family_name(int family)
00079 {
00080 switch (family) {
00081 case AF_UNSPEC:
00082 return "AF_UNSPEC";
00083 case AF_INET:
00084 return "AF_INET";
00085 case AF_INET6:
00086 return "AF_INET6";
00087 default:
00088 break;
00089 }
00090 return "unknown";
00091 }
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104 static int smb_krb5_locator_lookup_sanity_check(enum locate_service_type svc,
00105 const char *realm,
00106 int socktype,
00107 int family)
00108 {
00109 if (!realm || strlen(realm) == 0) {
00110 return EINVAL;
00111 }
00112
00113 switch (svc) {
00114 case locate_service_kdc:
00115 case locate_service_master_kdc:
00116 case locate_service_kpasswd:
00117 break;
00118 case locate_service_kadmin:
00119 case locate_service_krb524:
00120 #ifdef KRB5_PLUGIN_NO_HANDLE
00121 return KRB5_PLUGIN_NO_HANDLE;
00122 #else
00123 return KRB5_KDC_UNREACH;
00124 #endif
00125 default:
00126 return EINVAL;
00127 }
00128
00129 switch (family) {
00130 case AF_UNSPEC:
00131 case AF_INET:
00132 break;
00133 case AF_INET6:
00134 #ifdef KRB5_PLUGIN_NO_HANDLE
00135 return KRB5_PLUGIN_NO_HANDLE;
00136 #else
00137 return KRB5_KDC_UNREACH;
00138 #endif
00139 default:
00140 return EINVAL;
00141 }
00142
00143 switch (socktype) {
00144 case SOCK_STREAM:
00145 case SOCK_DGRAM:
00146 case 0:
00147 break;
00148 default:
00149 return EINVAL;
00150 }
00151
00152 return 0;
00153 }
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167 static krb5_error_code smb_krb5_locator_call_cbfunc(const char *name,
00168 const char *service,
00169 struct addrinfo *in,
00170 int (*cbfunc)(void *, int, struct sockaddr *),
00171 void *cbdata)
00172 {
00173 struct addrinfo *out;
00174 int ret;
00175 int count = 3;
00176
00177 while (count) {
00178
00179 ret = getaddrinfo(name, service, in, &out);
00180 if (ret == 0) {
00181 break;
00182 }
00183
00184 if (ret == EAI_AGAIN) {
00185 count--;
00186 continue;
00187 }
00188
00189 DEBUG(10,("smb_krb5_locator_lookup: got ret: %s (%d)\n",
00190 gai_strerror(ret), ret));
00191 #ifdef KRB5_PLUGIN_NO_HANDLE
00192 return KRB5_PLUGIN_NO_HANDLE;
00193 #else
00194 return KRB5_KDC_UNREACH;
00195 #endif
00196 }
00197
00198 ret = cbfunc(cbdata, out->ai_socktype, out->ai_addr);
00199 if (ret) {
00200 DEBUG(10,("smb_krb5_locator_lookup: failed to call callback: %s (%d)\n",
00201 error_message(ret), ret));
00202 }
00203
00204 freeaddrinfo(out);
00205
00206 return ret;
00207 }
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218 krb5_error_code smb_krb5_locator_init(krb5_context context,
00219 void **private_data)
00220 {
00221 setup_logging("smb_krb5_locator", True);
00222 load_case_tables();
00223 lp_load(dyn_CONFIGFILE,True,False,False,True);
00224
00225 DEBUG(10,("smb_krb5_locator_init: called\n"));
00226
00227 return 0;
00228 }
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238 void smb_krb5_locator_close(void *private_data)
00239 {
00240 DEBUG(10,("smb_krb5_locator_close: called\n"));
00241
00242
00243 }
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259 krb5_error_code smb_krb5_locator_lookup(void *private_data,
00260 enum locate_service_type svc,
00261 const char *realm,
00262 int socktype,
00263 int family,
00264 int (*cbfunc)(void *, int, struct sockaddr *),
00265 void *cbdata)
00266 {
00267 NTSTATUS status;
00268 krb5_error_code ret;
00269 char *sitename = NULL;
00270 struct ip_service *ip_list;
00271 int count = 0;
00272 struct addrinfo aihints;
00273 char *saf_name = NULL;
00274 int i;
00275
00276 DEBUG(10,("smb_krb5_locator_lookup: called for\n"));
00277 DEBUGADD(10,("\tsvc: %s (%d), realm: %s\n",
00278 locate_service_type_name(svc), svc, realm));
00279 DEBUGADD(10,("\tsocktype: %s (%d), family: %s (%d)\n",
00280 socktype_name(socktype), socktype,
00281 family_name(family), family));
00282
00283 ret = smb_krb5_locator_lookup_sanity_check(svc, realm, socktype, family);
00284 if (ret) {
00285 DEBUG(10,("smb_krb5_locator_lookup: returning ret: %s (%d)\n",
00286 error_message(ret), ret));
00287 return ret;
00288 }
00289
00290
00291
00292 saf_name = saf_fetch(realm);
00293 if (!saf_name || strlen(saf_name) == 0) {
00294 DEBUG(10,("smb_krb5_locator_lookup: no SAF name stored for %s\n",
00295 realm));
00296 goto find_kdc;
00297 }
00298
00299 DEBUG(10,("smb_krb5_locator_lookup: got %s for %s from SAF cache\n",
00300 saf_name, realm));
00301
00302 ZERO_STRUCT(aihints);
00303
00304 aihints.ai_family = family;
00305 aihints.ai_socktype = socktype;
00306
00307 ret = smb_krb5_locator_call_cbfunc(saf_name,
00308 get_service_from_locate_service_type(svc),
00309 &aihints,
00310 cbfunc, cbdata);
00311 if (ret) {
00312 return ret;
00313 }
00314
00315 return 0;
00316
00317 find_kdc:
00318
00319
00320
00321 sitename = sitename_fetch(realm);
00322 status = get_kdc_list(realm, sitename, &ip_list, &count);
00323
00324
00325
00326 if (NT_STATUS_IS_OK(status) && sitename && (count == 0)) {
00327 SAFE_FREE(ip_list);
00328 SAFE_FREE(sitename);
00329 status = get_kdc_list(realm, NULL, &ip_list, &count);
00330 }
00331
00332 SAFE_FREE(sitename);
00333
00334 if (!NT_STATUS_IS_OK(status)) {
00335 DEBUG(10,("smb_krb5_locator_lookup: got %s (%s)\n",
00336 nt_errstr(status),
00337 error_message(nt_status_to_krb5(status))));
00338 #ifdef KRB5_PLUGIN_NO_HANDLE
00339 return KRB5_PLUGIN_NO_HANDLE;
00340 #else
00341 return KRB5_KDC_UNREACH;
00342 #endif
00343 }
00344
00345 for (i=0; i<count; i++) {
00346
00347 const char *host = NULL;
00348 const char *port = NULL;
00349
00350 ZERO_STRUCT(aihints);
00351
00352 aihints.ai_family = family;
00353 aihints.ai_socktype = socktype;
00354
00355 host = inet_ntoa(ip_list[i].ip);
00356 port = get_service_from_locate_service_type(svc);
00357
00358 ret = smb_krb5_locator_call_cbfunc(host,
00359 port,
00360 &aihints,
00361 cbfunc, cbdata);
00362 if (ret) {
00363
00364 break;
00365 }
00366 }
00367
00368 SAFE_FREE(ip_list);
00369
00370 return ret;
00371 }
00372
00373 #ifdef HEIMDAL_KRB5_LOCATE_PLUGIN_H
00374 #define SMB_KRB5_LOCATOR_SYMBOL_NAME resolve
00375 #else
00376 #define SMB_KRB5_LOCATOR_SYMBOL_NAME service_locator
00377 #endif
00378
00379 const krb5plugin_service_locate_ftable SMB_KRB5_LOCATOR_SYMBOL_NAME = {
00380 0,
00381 smb_krb5_locator_init,
00382 smb_krb5_locator_close,
00383 smb_krb5_locator_lookup,
00384 };
00385
00386 #endif