ctdbd_conn: Add deregister_from_ctdbd()
[Samba.git] / source3 / utils / net_ads_join_dns.c
blob3437f96ee589758de06187a0164cf24ad1770353
1 /*
2 Samba Unix/Linux SMB client library
3 net ads dns internal functions
4 Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
5 Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
6 Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
7 Copyright (C) 2006 Gerald (Jerry) Carter (jerry@samba.org)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "utils/net.h"
25 #include "../lib/addns/dnsquery.h"
26 #include "secrets.h"
27 #include "krb5_env.h"
28 #include "utils/net_dns.h"
29 #include "lib/util/string_wrappers.h"
31 #ifdef HAVE_ADS
33 /*******************************************************************
34 Send a DNS update request
35 *******************************************************************/
37 #if defined(HAVE_KRB5)
38 #include "../lib/addns/dns.h"
40 void use_in_memory_ccache(void) {
41 /* Use in-memory credentials cache so we do not interfere with
42 * existing credentials */
43 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
46 static NTSTATUS net_update_dns_internal(struct net_context *c,
47 TALLOC_CTX *ctx, ADS_STRUCT *ads,
48 const char *machine_name,
49 const struct sockaddr_storage *addrs,
50 int num_addrs, bool remove_host)
52 struct dns_rr_ns *nameservers = NULL;
53 size_t ns_count = 0, i;
54 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
55 DNS_ERROR dns_err;
56 fstring dns_server;
57 const char *dnsdomain = NULL;
58 char *root_domain = NULL;
59 uint32_t ttl = 3600;
61 if (c->opt_dns_ttl > 0) {
62 ttl = MIN(c->opt_dns_ttl, UINT32_MAX);
65 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
66 d_printf(_("No DNS domain configured for %s. "
67 "Unable to perform DNS Update.\n"), machine_name);
68 status = NT_STATUS_INVALID_PARAMETER;
69 goto done;
71 dnsdomain++;
73 status = ads_dns_lookup_ns(ctx,
74 dnsdomain,
75 &nameservers,
76 &ns_count);
77 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
78 /* Child domains often do not have NS records. Look
79 for the NS record for the forest root domain
80 (rootDomainNamingContext in therootDSE) */
82 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
83 LDAPMessage *msg = NULL;
84 char *root_dn;
85 ADS_STATUS ads_status;
87 if ( !ads->ldap.ld ) {
88 ads_status = ads_connect( ads );
89 if ( !ADS_ERR_OK(ads_status) ) {
90 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
91 goto done;
95 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
96 "(objectclass=*)", rootname_attrs, &msg);
97 if (!ADS_ERR_OK(ads_status)) {
98 goto done;
101 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
102 if ( !root_dn ) {
103 ads_msgfree( ads, msg );
104 goto done;
107 root_domain = ads_build_domain( root_dn );
109 /* cleanup */
110 ads_msgfree( ads, msg );
112 /* try again for NS servers */
114 status = ads_dns_lookup_ns(ctx,
115 root_domain,
116 &nameservers,
117 &ns_count);
119 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
120 DEBUG(3,("net_update_dns_internal: Failed to find name server for the %s "
121 "realm\n", ads->config.realm));
122 if (ns_count == 0) {
123 status = NT_STATUS_UNSUCCESSFUL;
125 goto done;
128 dnsdomain = root_domain;
132 for (i=0; i < ns_count; i++) {
134 uint32_t flags = DNS_UPDATE_SIGNED |
135 DNS_UPDATE_UNSIGNED |
136 DNS_UPDATE_UNSIGNED_SUFFICIENT |
137 DNS_UPDATE_PROBE |
138 DNS_UPDATE_PROBE_SUFFICIENT;
140 if (c->opt_force) {
141 flags &= ~DNS_UPDATE_PROBE_SUFFICIENT;
142 flags &= ~DNS_UPDATE_UNSIGNED_SUFFICIENT;
146 * Do not return after PROBE completion if this function
147 * is called for DNS removal.
149 if (remove_host) {
150 flags &= ~DNS_UPDATE_PROBE_SUFFICIENT;
153 status = NT_STATUS_UNSUCCESSFUL;
155 /* Now perform the dns update - we'll try non-secure and if we fail,
156 we'll follow it up with a secure update */
158 fstrcpy( dns_server, nameservers[i].hostname );
160 dns_err = DoDNSUpdate(dns_server,
161 dnsdomain,
162 machine_name,
163 addrs,
164 num_addrs,
165 flags,
166 ttl,
167 remove_host);
168 if (ERR_DNS_IS_OK(dns_err)) {
169 status = NT_STATUS_OK;
170 goto done;
173 if (ERR_DNS_EQUAL(dns_err, ERROR_DNS_INVALID_NAME_SERVER) ||
174 ERR_DNS_EQUAL(dns_err, ERROR_DNS_CONNECTION_FAILED) ||
175 ERR_DNS_EQUAL(dns_err, ERROR_DNS_SOCKET_ERROR)) {
176 DEBUG(1,("retrying DNS update with next nameserver after receiving %s\n",
177 dns_errstr(dns_err)));
178 continue;
181 d_printf(_("DNS Update for %s failed: %s\n"),
182 machine_name, dns_errstr(dns_err));
183 status = NT_STATUS_UNSUCCESSFUL;
184 goto done;
187 done:
189 SAFE_FREE( root_domain );
191 return status;
194 NTSTATUS net_update_dns_ext(struct net_context *c,
195 TALLOC_CTX *mem_ctx, ADS_STRUCT *ads,
196 const char *hostname,
197 struct sockaddr_storage *iplist,
198 int num_addrs, bool remove_host)
200 struct sockaddr_storage *iplist_alloc = NULL;
201 fstring machine_name;
202 NTSTATUS status;
204 if (hostname) {
205 fstrcpy(machine_name, hostname);
206 } else {
207 name_to_fqdn( machine_name, lp_netbios_name() );
209 if (!strlower_m( machine_name )) {
210 return NT_STATUS_INVALID_PARAMETER;
214 * If remove_host is true, then remove all IP addresses associated with
215 * this hostname from the AD server.
217 if (!remove_host && (num_addrs == 0 || iplist == NULL)) {
219 * Get our ip address
220 * (not the 127.0.0.x address but a real ip address)
222 num_addrs = get_my_ip_address(&iplist_alloc);
223 if ( num_addrs <= 0 ) {
224 DEBUG(4, ("net_update_dns_ext: Failed to find my "
225 "non-loopback IP addresses!\n"));
226 return NT_STATUS_INVALID_PARAMETER;
228 iplist = iplist_alloc;
231 status = net_update_dns_internal(c, mem_ctx, ads, machine_name,
232 iplist, num_addrs, remove_host);
234 SAFE_FREE(iplist_alloc);
235 return status;
238 static NTSTATUS net_update_dns(struct net_context *c, TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, const char *hostname)
240 NTSTATUS status;
242 status = net_update_dns_ext(c, mem_ctx, ads, hostname, NULL, 0, false);
243 return status;
245 #endif
247 void net_ads_join_dns_updates(struct net_context *c, TALLOC_CTX *ctx, struct libnet_JoinCtx *r)
249 #if defined(HAVE_KRB5)
250 ADS_STRUCT *ads_dns = NULL;
251 int ret;
252 NTSTATUS status;
253 char *machine_password = NULL;
256 * In a clustered environment, don't do dynamic dns updates:
257 * Registering the set of ip addresses that are assigned to
258 * the interfaces of the node that performs the join does usually
259 * not have the desired effect, since the local interfaces do not
260 * carry the complete set of the cluster's public IP addresses.
261 * And it can also contain internal addresses that should not
262 * be visible to the outside at all.
263 * In order to do dns updates in a clustererd setup, use
264 * net ads dns register.
266 if (lp_clustering()) {
267 d_fprintf(stderr, _("Not doing automatic DNS update in a "
268 "clustered setup.\n"));
269 return;
272 if (!r->out.domain_is_ad) {
273 return;
277 * We enter this block with user creds.
278 * kinit with the machine password to do dns update.
281 ads_dns = ads_init(ctx,
282 lp_realm(),
283 NULL,
284 r->in.dc_name,
285 ADS_SASL_PLAIN);
286 if (ads_dns == NULL) {
287 d_fprintf(stderr, _("DNS update failed: out of memory!\n"));
288 goto done;
291 use_in_memory_ccache();
293 ads_dns->auth.user_name = talloc_asprintf(ads_dns,
294 "%s$",
295 lp_netbios_name());
296 if (ads_dns->auth.user_name == NULL) {
297 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
298 goto done;
301 machine_password = secrets_fetch_machine_password(
302 r->out.netbios_domain_name, NULL, NULL);
303 if (machine_password != NULL) {
304 ads_dns->auth.password = talloc_strdup(ads_dns,
305 machine_password);
306 SAFE_FREE(machine_password);
307 if (ads_dns->auth.password == NULL) {
308 d_fprintf(stderr,
309 _("DNS update failed: out of memory\n"));
310 goto done;
314 ads_dns->auth.realm = talloc_asprintf_strupper_m(ads_dns, "%s", r->out.dns_domain_name);
315 if (ads_dns->auth.realm == NULL) {
316 d_fprintf(stderr, _("talloc_asprintf_strupper_m %s failed\n"),
317 ads_dns->auth.realm);
318 goto done;
321 ret = ads_kinit_password(ads_dns);
322 if (ret != 0) {
323 d_fprintf(stderr,
324 _("DNS update failed: kinit failed: %s\n"),
325 error_message(ret));
326 goto done;
329 status = net_update_dns(c, ctx, ads_dns, NULL);
330 if (!NT_STATUS_IS_OK(status)) {
331 d_fprintf( stderr, _("DNS update failed: %s\n"),
332 nt_errstr(status));
335 done:
336 TALLOC_FREE(ads_dns);
337 #endif
339 return;
342 #endif /* HAVE_ADS */