Reachability.m   [plain text]

/*
* Copyright (c) 2006 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
* Portions Copyright (c) 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

#import <err.h>
#import <stdio.h>
#import <arpa/inet.h>
#import <netdb.h>
#import <sys/param.h>
#import <sys/socket.h>
#import <syslog.h>

#import <Heimdal/HeimdalSystemConfiguration.h>

#import <Foundation/Foundation.h>
#import <SystemConfiguration/SystemConfiguration.h>
#import <Heimdal/krb5.h>
#import <Heimdal/locate_plugin.h>

/**
* Reachablity plugin reads System Configuration to pick up the realm
* configuration from OpenDirectory plugins, both OD and AD.
*
* The keys published is:
*
* Kerberos:REALM = {
* kadmin = [ { host = "hostname", port = "port-number" } ]
* kdc = [ .. ]
* kpasswd = [ ]
* }
*
* port is optional
*
* The following behaivor is expected:
*
* 1. Not joined to a domain
* no entry published
* 2. Joined to a domain and replica AVAILABLE:
* entry pushlished with content
* 3. Joined to a domain and replica UNAVAILABLE
* entry pushlished, but no content
*
*/

static krb5_error_code
reachability_init(krb5_context context, void **ctx)
{
*ctx = NULL;
return 0;
}

static void
reachability_fini(void *ctx)
{
}

static krb5_error_code
reachability_lookup(void *ctx,
unsigned long flags,
enum locate_service_type service,
const char *realm,
int domain,
int type,
int (*addfunc)(void *,int,struct sockaddr *),
void *addctx)
{
krb5_error_code ret;
NSAutoreleasePool *pool;
NSString *svc, *sckey, *host, *port;
struct addrinfo hints, *ai0, *ai;
SCDynamicStoreRef store = NULL;
NSDictionary *top = NULL;
NSArray *vals;
NSString *defport = NULL;
int found_entry = 0;
id rp;

@try {
pool = [[NSAutoreleasePool alloc] init];

switch(service) {
case locate_service_kdc:
case locate_service_master_kdc:
case locate_service_krb524:
svc = (NSString *)HEIMDAL_SC_LOCATE_TYPE_KDC;
defport = @"88";
break;
case locate_service_kpasswd:
svc = (NSString *)HEIMDAL_SC_LOCATE_TYPE_KPASSWD;
defport = @"464";
break;
case locate_service_kadmin:
svc = (NSString *)HEIMDAL_SC_LOCATE_TYPE_ADMIN;
defport = @"749";
break;
}
if (defport == NULL) {
ret = KRB5_PLUGIN_NO_HANDLE;
goto out;
}

store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("Kerberos"), NULL, NULL);
sckey = [NSString stringWithFormat:@"%@%s",
(NSString *)HEIMDAL_SC_LOCATE_REALM_PREFIX, realm];
top = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)sckey);
if (top == NULL) {
ret = KRB5_PLUGIN_NO_HANDLE;
goto out;
}

vals = [top valueForKey:svc];
if (vals == NULL) {
ret = KRB5_PLUGIN_NO_HANDLE;
goto out;
}

if ([vals count] == 0)
syslog(LOG_WARNING,
"Kerberos-Reachability SystemConfiguration returned 0 entries for %s",
realm);

for (NSDictionary *a in vals) {
host = [a valueForKey:(NSString *)HEIMDAL_SC_LOCATE_HOST];

rp = [a valueForKey:(NSString *)HEIMDAL_SC_LOCATE_PORT];
if ([rp isKindOfClass:[NSString class]])
port = rp;
else if ([rp respondsToSelector:@selector(stringValue)])
port = [rp stringValue];
else
port = defport;
if (port == nil)
continue;

memset(&hints, 0, sizeof(hints));
hints.ai_flags = 0;
hints.ai_family = type;
hints.ai_socktype = domain;

if (getaddrinfo([host UTF8String], [port UTF8String], &hints, &ai0) != 0)
continue;

for (ai = ai0; ai != NULL; ai = ai->ai_next) {
ret = addfunc(addctx, ai->ai_socktype, ai->ai_addr);
if (ret == 0)
found_entry = 1;
}
freeaddrinfo(ai0);
}

if (!found_entry)
ret = KRB5_KDC_UNREACH;
else
ret = 0;
out:
do {} while(0);
}
@catch (NSException * __unused exception) { }
@finally {

if (top)
CFRelease((CFTypeRef)top);
if (store)
CFRelease(store);
[pool drain];
}

return ret;
}

static krb5_error_code
reachability_lookup_old(void *ctx,
enum locate_service_type service,
const char *realm,
int domain,
int type,
int (*addfunc)(void *,int,struct sockaddr *),
void *addctx)
{
return reachability_lookup(ctx, KRB5_PLF_ALLOW_HOMEDIR, service,
realm, domain, type, addfunc, addctx);
}

krb5plugin_service_locate_ftable service_locator = {
KRB5_PLUGIN_LOCATE_VERSION_2,
reachability_init,
reachability_fini,
reachability_lookup_old,
reachability_lookup
};