/ plugins / Reachability.m
Reachability.m
  1  /*
  2   * Copyright (c) 2006 Kungliga Tekniska Högskolan
  3   * (Royal Institute of Technology, Stockholm, Sweden).
  4   * All rights reserved.
  5   *
  6   * Portions Copyright (c) 2010 Apple Inc. All rights reserved.
  7   *
  8   * Redistribution and use in source and binary forms, with or without
  9   * modification, are permitted provided that the following conditions
 10   * are met:
 11   *
 12   * 1. Redistributions of source code must retain the above copyright
 13   *    notice, this list of conditions and the following disclaimer.
 14   *
 15   * 2. Redistributions in binary form must reproduce the above copyright
 16   *    notice, this list of conditions and the following disclaimer in the
 17   *    documentation and/or other materials provided with the distribution.
 18   *
 19   * 3. Neither the name of the Institute nor the names of its contributors
 20   *    may be used to endorse or promote products derived from this software
 21   *    without specific prior written permission.
 22   *
 23   * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 24   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 25   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 26   * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 27   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 28   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 29   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 30   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 31   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 32   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 33   * SUCH DAMAGE.
 34   */
 35  
 36  #import <err.h>
 37  #import <stdio.h>
 38  #import <arpa/inet.h>
 39  #import <netdb.h>
 40  #import <sys/param.h>
 41  #import <sys/socket.h>
 42  #import <syslog.h>
 43  
 44  #import <Heimdal/HeimdalSystemConfiguration.h>
 45  
 46  #import <Foundation/Foundation.h>
 47  #import <SystemConfiguration/SystemConfiguration.h>
 48  #import <Heimdal/krb5.h>
 49  #import <Heimdal/locate_plugin.h>
 50  
 51  /**
 52   * Reachablity plugin reads System Configuration to pick up the realm
 53   * configuration from OpenDirectory plugins, both OD and AD.
 54   *
 55   * The keys published is:
 56   *
 57   * Kerberos:REALM = {
 58   *   kadmin = [ { host = "hostname", port = "port-number" } ]
 59   *   kdc = [ .. ]
 60   *   kpasswd = [ ]
 61   * }
 62   *
 63   * port is optional
 64   *
 65   * The following behaivor is expected:
 66   *
 67   * 1. Not joined to a domain
 68   *      no entry published
 69   * 2. Joined to a domain and replica AVAILABLE:
 70   *       entry pushlished with content
 71   * 3. Joined to a domain and replica UNAVAILABLE
 72   *       entry pushlished, but no content
 73   *
 74   */
 75  
 76  static krb5_error_code
 77  reachability_init(krb5_context context, void **ctx)
 78  {
 79      *ctx = NULL;
 80      return 0;
 81  }
 82  
 83  static void
 84  reachability_fini(void *ctx)
 85  {
 86  }
 87  
 88  static krb5_error_code
 89  reachability_lookup(void *ctx,
 90  		    unsigned long flags,
 91  		    enum locate_service_type service,
 92  		    const char *realm,
 93  		    int domain,
 94  		    int type,
 95  		    int (*addfunc)(void *,int,struct sockaddr *),
 96  		    void *addctx)
 97  {
 98      krb5_error_code ret;
 99      NSAutoreleasePool *pool;
100      NSString *svc, *sckey, *host, *port;
101      struct addrinfo hints, *ai0, *ai;
102      SCDynamicStoreRef store = NULL;
103      NSDictionary *top = NULL;
104      NSArray *vals;
105      NSString *defport = NULL;
106      int found_entry = 0;
107      id rp;
108      
109      @try {
110  	pool = [[NSAutoreleasePool alloc] init];
111  
112  	switch(service) {
113  	case locate_service_kdc:
114  	case locate_service_master_kdc:
115  	case locate_service_krb524:
116  	    svc = (NSString *)HEIMDAL_SC_LOCATE_TYPE_KDC;
117  	    defport = @"88";
118  	    break;
119  	case locate_service_kpasswd:
120  	    svc = (NSString *)HEIMDAL_SC_LOCATE_TYPE_KPASSWD;
121  	    defport = @"464";
122  	    break;
123  	case locate_service_kadmin:
124  	    svc = (NSString *)HEIMDAL_SC_LOCATE_TYPE_ADMIN;
125  	    defport = @"749";
126  	    break;
127  	}
128  	if (defport == NULL) {
129  	    ret = KRB5_PLUGIN_NO_HANDLE;
130  	    goto out;
131  	}
132  	
133  	store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("Kerberos"), NULL, NULL);
134  	sckey = [NSString stringWithFormat:@"%@%s",
135  			  (NSString *)HEIMDAL_SC_LOCATE_REALM_PREFIX, realm];
136  	top = (NSDictionary *)SCDynamicStoreCopyValue(store, (CFStringRef)sckey);
137  	if (top == NULL) {
138  	    ret = KRB5_PLUGIN_NO_HANDLE;
139  	    goto out;
140  	}
141  
142  	vals = [top valueForKey:svc];
143  	if (vals == NULL) {
144  	    ret = KRB5_PLUGIN_NO_HANDLE;
145  	    goto out;
146  	}
147  
148  	if ([vals count] == 0)
149  	    syslog(LOG_WARNING,
150  		   "Kerberos-Reachability SystemConfiguration returned 0 entries for %s",
151  		   realm);
152  	
153  	for (NSDictionary *a in vals) {
154  	    host = [a valueForKey:(NSString *)HEIMDAL_SC_LOCATE_HOST];
155  	    
156  	    rp = [a valueForKey:(NSString *)HEIMDAL_SC_LOCATE_PORT];
157  	    if ([rp isKindOfClass:[NSString class]])
158  		port = rp;
159  	    else if ([rp respondsToSelector:@selector(stringValue)])
160  		port = [rp stringValue];
161  	    else
162  		port = defport;
163  	    if (port == nil)
164  		continue;
165  	    
166  	    memset(&hints, 0, sizeof(hints));
167  	    hints.ai_flags = 0;
168  	    hints.ai_family = type;
169  	    hints.ai_socktype = domain;
170  	    
171  	    if (getaddrinfo([host UTF8String], [port UTF8String], &hints, &ai0) != 0)
172  		continue;
173  	    
174  	    for (ai = ai0; ai != NULL; ai = ai->ai_next) {
175  		ret = addfunc(addctx, ai->ai_socktype, ai->ai_addr);
176  		if (ret == 0)
177  		    found_entry = 1;
178  	    }
179  	    freeaddrinfo(ai0);
180  	}
181  	
182  	if (!found_entry)
183  	    ret = KRB5_KDC_UNREACH;
184  	else
185  	    ret = 0;
186       out:
187  	do {} while(0);
188      }
189      @catch (NSException * __unused exception) { }
190      @finally {
191  
192  	if (top)
193  	    CFRelease((CFTypeRef)top);
194  	if (store)
195  	    CFRelease(store);
196  	[pool drain];
197      }
198  
199      return ret;
200  }
201  
202  static krb5_error_code
203  reachability_lookup_old(void *ctx,
204  			enum locate_service_type service,
205  			const char *realm,
206  			int domain,
207  			int type,
208  			int (*addfunc)(void *,int,struct sockaddr *),
209  			void *addctx)
210  {
211      return reachability_lookup(ctx, KRB5_PLF_ALLOW_HOMEDIR, service,
212  			       realm, domain, type, addfunc, addctx);
213  }
214  
215  krb5plugin_service_locate_ftable service_locator = {
216      KRB5_PLUGIN_LOCATE_VERSION_2,
217      reachability_init,
218      reachability_fini,
219      reachability_lookup_old,
220      reachability_lookup
221  };