1/* 2 * LKDC-lookup-plugin.c 3 * LocalKDC 4 */ 5 6/* 7 * Copyright (c) 2006-2007 Apple Inc. All rights reserved. 8 * 9 * @APPLE_LICENSE_HEADER_START@ 10 * 11 * This file contains Original Code and/or Modifications of Original Code 12 * as defined in and that are subject to the Apple Public Source License 13 * Version 2.0 (the 'License'). You may not use this file except in 14 * compliance with the License. Please obtain a copy of the License at 15 * http://www.opensource.apple.com/apsl/ and read it before using this 16 * file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_LICENSE_HEADER_END@ 27 */ 28 29#include "LKDC-lookup-plugin.h" 30#include <asl.h> 31#include <errno.h> 32#include <stdarg.h> 33#include <stdlib.h> 34#include <string.h> 35#include <stdio.h> 36#include <arpa/inet.h> 37#include <netdb.h> 38 39#include <Heimdal/krb5.h> 40#include <Heimdal/locate_plugin.h> 41 42#include "LKDCHelper.h" 43 44typedef struct _state { 45 krb5_context krb_context; 46 time_t cacheCreateTime; 47} state; 48 49#define LKDC_PLUGIN_DEBUG 1 50#if LKDC_PLUGIN_DEBUG 51#define debug(fmt, ...) do { debug_(__func__, fmt, ## __VA_ARGS__); } while(0) 52static inline void 53debug_(const char *func, const char *fmt, ...) 54{ 55 static const char ellipsis[] = "[...]"; 56 char buf[2048]; 57 char *p = buf; 58 char *endp = &buf[sizeof(buf)]; 59 ssize_t n = snprintf(p, endp-p, "%s: ", func); 60 61 if ((size_t)n >= endp-p) 62 return; 63 p += n; 64 va_list ap; 65 va_start(ap, fmt); 66 n = vsnprintf(p, endp-p, fmt, ap); 67 va_end(ap); 68 if ((size_t)n >= endp-p) 69 snprintf(endp-sizeof(ellipsis), sizeof(ellipsis), ellipsis); 70 asl_log(NULL, NULL, ASL_LEVEL_DEBUG, "%s", buf); 71} 72#else 73#define debug(...) 74#endif 75 76static krb5_error_code LKDCInit (krb5_context c, void **ptr) 77{ 78 return 0; 79} 80 81static void LKDCFinish (void *ptr) { 82 return; 83} 84 85static krb5_error_code LKDCLookup (void *ptr, 86 enum locate_service_type svc, 87 const char *realm, 88 int socktype, 89 int family, 90 int (*cbfunc)(void *, int, struct sockaddr *), 91 void *cbdata) 92{ 93 krb5_error_code error = KRB5_PLUGIN_NO_HANDLE; 94 char *hostname = NULL; 95 struct addrinfo aiHints; 96 struct addrinfo *aiResult = NULL; 97 struct addrinfo *res = NULL; 98 uint16_t port; 99 int err = 0; 100 101 switch (family) { 102 case 0: 103 case AF_INET: 104 case AF_INET6: 105 break; 106 default: 107 debug("Declined to handle address family %d", family); 108 return error; 109 } 110 111 debug("svc = %d, realm = %s, family= %d, socktype = %d", svc, realm, family, socktype); 112 switch (svc) { 113 case locate_service_kdc: 114 case locate_service_master_kdc: 115 break; 116 case locate_service_kadmin: 117 case locate_service_krb524: 118 case locate_service_kpasswd: 119 default: 120 return error; 121 } 122 debug("KDC|MasterKDC"); 123 124 /* Do we handle this type of realm? */ 125 if (strncmp ("LKDC:", realm, 5) != 0) { 126 return error; 127 } 128 129 err = LKDCFindKDCForRealm (realm, &hostname, &port); 130 if (0 != err || NULL == hostname) { 131 return error; 132 } 133 134 bzero (&aiHints, sizeof (aiHints)); 135 aiHints.ai_flags = 0; 136 aiHints.ai_family = family; 137 aiHints.ai_socktype = socktype; 138 139 err = getaddrinfo (hostname, 140 NULL, // realmDetails->servicePortName? 141 &aiHints, 142 &aiResult); 143 debug("getaddrinfo () == %d", err); 144 145 if (0 == err) { 146 for (res = aiResult; res != NULL; res = res->ai_next) { 147 void *in_addr = NULL; 148 uint16_t in_port = 0; 149 150 debug("0x%08p: family = %d, socktype = %d, protocol = %d", res, res->ai_family, res->ai_socktype, res->ai_protocol); 151 debug("Running callback 0x%08p", res); 152 switch (res->ai_family) { 153 case AF_INET: 154 in_addr = &(((struct sockaddr_in *)res->ai_addr)->sin_addr); 155 ((struct sockaddr_in *)res->ai_addr)->sin_port = htons (in_port = port); 156 break; 157 case AF_INET6: 158 in_addr = &(((struct sockaddr_in6 *)res->ai_addr)->sin6_addr); 159 ((struct sockaddr_in6 *)res->ai_addr)->sin6_port = htons (in_port = port); 160 break; 161 default: 162 in_addr = NULL; 163 debug("Unexpected address family %d", res->ai_family); 164 break; 165 } 166 if (NULL != in_addr) { 167 err = cbfunc (cbdata, res->ai_socktype, res->ai_addr); 168 debug("Callback done 0x%08p, err=%d", res, err); 169#if LKDC_PLUGIN_DEBUG 170 { 171 char ipString[1024]; 172 ipString[0] = '\0'; 173 if (NULL == inet_ntop(res->ai_family, in_addr, ipString, sizeof(ipString))) 174 debug("inet_ntop failed: %s", strerror(errno)); 175 else 176 debug("addr = %s, port = %d", ipString, (int)in_port); 177 } 178#endif 179 } 180 181 } 182 freeaddrinfo (aiResult); 183 aiResult = NULL; 184 } else { 185 debug("failed %d", error); 186 return error; 187 } 188 189 debug("OK"); 190 return 0; 191} 192 193/* Structure used by Kerberos to locate the functions to call for this plugin. */ 194 195const krb5plugin_service_locate_ftable service_locator = { 196 0, /* version */ 197 LKDCInit, /* Initialize - called each time */ 198 LKDCFinish, /* Finish - called each time */ 199 LKDCLookup, /* Lookup function */ 200}; 201