1/* 2 Unix SMB/CIFS implementation. 3 4 Winbind daemon connection manager 5 6 Copyright (C) Tim Potter 2001 7 Copyright (C) Andrew Bartlett 2002 8 Copyright (C) Gerald Carter 2003 9 10 This program is free software; you can redistribute it and/or modify 11 it under the terms of the GNU General Public License as published by 12 the Free Software Foundation; either version 2 of the License, or 13 (at your option) any later version. 14 15 This program is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License for more details. 19 20 You should have received a copy of the GNU General Public License 21 along with this program; if not, write to the Free Software 22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 23*/ 24 25 26#include "includes.h" 27 28/********************************************************************** 29 Is this our primary domain ? 30**********************************************************************/ 31 32#ifdef HAVE_KRB5 33static BOOL is_our_primary_domain(const char *domain) 34{ 35 int role = lp_server_role(); 36 37 if ((role == ROLE_DOMAIN_MEMBER) && strequal(lp_workgroup(), domain)) { 38 return True; 39 } else if (strequal(get_global_sam_name(), domain)) { 40 return True; 41 } 42 return False; 43} 44#endif 45 46/************************************************************************** 47 Find the name and IP address for a server in the realm/domain 48 *************************************************************************/ 49 50static BOOL ads_dc_name(const char *domain, 51 const char *realm, 52 struct in_addr *dc_ip, 53 fstring srv_name) 54{ 55 ADS_STRUCT *ads; 56 char *sitename; 57 int i; 58 59 if (!realm && strequal(domain, lp_workgroup())) { 60 realm = lp_realm(); 61 } 62 63 sitename = sitename_fetch(realm); 64 65 /* Try this 3 times then give up. */ 66 for( i =0 ; i < 3; i++) { 67 ads = ads_init(realm, domain, NULL); 68 if (!ads) { 69 SAFE_FREE(sitename); 70 return False; 71 } 72 73 DEBUG(4,("ads_dc_name: domain=%s\n", domain)); 74 75#ifdef HAVE_ADS 76 /* we don't need to bind, just connect */ 77 ads->auth.flags |= ADS_AUTH_NO_BIND; 78 ads_connect(ads); 79#endif 80 81 if (!ads->config.realm) { 82 SAFE_FREE(sitename); 83 ads_destroy(&ads); 84 return False; 85 } 86 87 /* Now we've found a server, see if our sitename 88 has changed. If so, we need to re-do the DNS query 89 to ensure we only find servers in our site. */ 90 91 if (stored_sitename_changed(realm, sitename)) { 92 SAFE_FREE(sitename); 93 sitename = sitename_fetch(realm); 94 ads_destroy(&ads); 95 /* Ensure we don't cache the DC we just connected to. */ 96 namecache_delete(realm, 0x1C); 97 namecache_delete(domain, 0x1C); 98 continue; 99 } 100 101#ifdef HAVE_KRB5 102 if (is_our_primary_domain(domain) && (ads->config.flags & ADS_KDC) && ads_closest_dc(ads)) { 103 /* We're going to use this KDC for this realm/domain. 104 If we are using sites, then force the krb5 libs 105 to use this KDC. */ 106 107 create_local_private_krb5_conf_for_domain(realm, 108 domain, 109 sitename, 110 ads->ldap_ip); 111 } 112#endif 113 break; 114 } 115 116 if (i == 3) { 117 DEBUG(1,("ads_dc_name: sitename (now \"%s\") keeps changing ???\n", 118 sitename ? sitename : "")); 119 SAFE_FREE(sitename); 120 return False; 121 } 122 123 SAFE_FREE(sitename); 124 125 fstrcpy(srv_name, ads->config.ldap_server_name); 126 strupper_m(srv_name); 127 *dc_ip = ads->ldap_ip; 128 ads_destroy(&ads); 129 130 DEBUG(4,("ads_dc_name: using server='%s' IP=%s\n", 131 srv_name, inet_ntoa(*dc_ip))); 132 133 return True; 134} 135 136/**************************************************************************** 137 Utility function to return the name of a DC. The name is guaranteed to be 138 valid since we have already done a name_status_find on it 139 ***************************************************************************/ 140 141static BOOL rpc_dc_name(const char *domain, fstring srv_name, struct in_addr *ip_out) 142{ 143 struct ip_service *ip_list = NULL; 144 struct in_addr dc_ip, exclude_ip; 145 int count, i; 146 NTSTATUS result; 147 148 zero_ip(&exclude_ip); 149 150 /* get a list of all domain controllers */ 151 152 if (!NT_STATUS_IS_OK(get_sorted_dc_list(domain, NULL, &ip_list, &count, 153 False))) { 154 DEBUG(3, ("Could not look up dc's for domain %s\n", domain)); 155 return False; 156 } 157 158 /* Remove the entry we've already failed with (should be the PDC). */ 159 160 for (i = 0; i < count; i++) { 161 if (is_zero_ip(ip_list[i].ip)) 162 continue; 163 164 if (name_status_find(domain, 0x1c, 0x20, ip_list[i].ip, srv_name)) { 165 result = check_negative_conn_cache( domain, srv_name ); 166 if ( NT_STATUS_IS_OK(result) ) { 167 dc_ip = ip_list[i].ip; 168 goto done; 169 } 170 } 171 } 172 173 174 SAFE_FREE(ip_list); 175 176 /* No-one to talk to )-: */ 177 return False; /* Boo-hoo */ 178 179 done: 180 /* We have the netbios name and IP address of a domain controller. 181 Ideally we should sent a SAMLOGON request to determine whether 182 the DC is alive and kicking. If we can catch a dead DC before 183 performing a cli_connect() we can avoid a 30-second timeout. */ 184 185 DEBUG(3, ("rpc_dc_name: Returning DC %s (%s) for domain %s\n", srv_name, 186 inet_ntoa(dc_ip), domain)); 187 188 *ip_out = dc_ip; 189 190 SAFE_FREE(ip_list); 191 192 return True; 193} 194 195/********************************************************************** 196 wrapper around ads and rpc methods of finds DC's 197**********************************************************************/ 198 199BOOL get_dc_name(const char *domain, const char *realm, fstring srv_name, struct in_addr *ip_out) 200{ 201 struct in_addr dc_ip; 202 BOOL ret; 203 BOOL our_domain = False; 204 205 zero_ip(&dc_ip); 206 207 ret = False; 208 209 if ( strequal(lp_workgroup(), domain) || strequal(lp_realm(), realm) ) 210 our_domain = True; 211 212 /* always try to obey what the admin specified in smb.conf 213 (for the local domain) */ 214 215 if ( (our_domain && lp_security()==SEC_ADS) || realm ) { 216 ret = ads_dc_name(domain, realm, &dc_ip, srv_name); 217 } 218 219 if (!domain) { 220 /* if we have only the realm we can't do anything else */ 221 return False; 222 } 223 224 if (!ret) { 225 /* fall back on rpc methods if the ADS methods fail */ 226 ret = rpc_dc_name(domain, srv_name, &dc_ip); 227 } 228 229 *ip_out = dc_ip; 230 231 return ret; 232} 233