smbstatus: add json items to traverse_struct
[Samba.git] / source3 / utils / net_ads_join_dns.c
blob7c98b0ee27f82d00a3b4b296bf92350d7bc30b2b
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;
60 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
61 d_printf(_("No DNS domain configured for %s. "
62 "Unable to perform DNS Update.\n"), machine_name);
63 status = NT_STATUS_INVALID_PARAMETER;
64 goto done;
66 dnsdomain++;
68 status = ads_dns_lookup_ns(ctx,
69 dnsdomain,
70 &nameservers,
71 &ns_count);
72 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
73 /* Child domains often do not have NS records. Look
74 for the NS record for the forest root domain
75 (rootDomainNamingContext in therootDSE) */
77 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
78 LDAPMessage *msg = NULL;
79 char *root_dn;
80 ADS_STATUS ads_status;
82 if ( !ads->ldap.ld ) {
83 ads_status = ads_connect( ads );
84 if ( !ADS_ERR_OK(ads_status) ) {
85 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
86 goto done;
90 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
91 "(objectclass=*)", rootname_attrs, &msg);
92 if (!ADS_ERR_OK(ads_status)) {
93 goto done;
96 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
97 if ( !root_dn ) {
98 ads_msgfree( ads, msg );
99 goto done;
102 root_domain = ads_build_domain( root_dn );
104 /* cleanup */
105 ads_msgfree( ads, msg );
107 /* try again for NS servers */
109 status = ads_dns_lookup_ns(ctx,
110 root_domain,
111 &nameservers,
112 &ns_count);
114 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
115 DEBUG(3,("net_update_dns_internal: Failed to find name server for the %s "
116 "realm\n", ads->config.realm));
117 if (ns_count == 0) {
118 status = NT_STATUS_UNSUCCESSFUL;
120 goto done;
123 dnsdomain = root_domain;
127 for (i=0; i < ns_count; i++) {
129 uint32_t flags = DNS_UPDATE_SIGNED |
130 DNS_UPDATE_UNSIGNED |
131 DNS_UPDATE_UNSIGNED_SUFFICIENT |
132 DNS_UPDATE_PROBE |
133 DNS_UPDATE_PROBE_SUFFICIENT;
135 if (c->opt_force) {
136 flags &= ~DNS_UPDATE_PROBE_SUFFICIENT;
137 flags &= ~DNS_UPDATE_UNSIGNED_SUFFICIENT;
141 * Do not return after PROBE completion if this function
142 * is called for DNS removal.
144 if (remove_host) {
145 flags &= ~DNS_UPDATE_PROBE_SUFFICIENT;
148 status = NT_STATUS_UNSUCCESSFUL;
150 /* Now perform the dns update - we'll try non-secure and if we fail,
151 we'll follow it up with a secure update */
153 fstrcpy( dns_server, nameservers[i].hostname );
155 dns_err = DoDNSUpdate(dns_server,
156 dnsdomain,
157 machine_name,
158 addrs,
159 num_addrs,
160 flags,
161 remove_host);
162 if (ERR_DNS_IS_OK(dns_err)) {
163 status = NT_STATUS_OK;
164 goto done;
167 if (ERR_DNS_EQUAL(dns_err, ERROR_DNS_INVALID_NAME_SERVER) ||
168 ERR_DNS_EQUAL(dns_err, ERROR_DNS_CONNECTION_FAILED) ||
169 ERR_DNS_EQUAL(dns_err, ERROR_DNS_SOCKET_ERROR)) {
170 DEBUG(1,("retrying DNS update with next nameserver after receiving %s\n",
171 dns_errstr(dns_err)));
172 continue;
175 d_printf(_("DNS Update for %s failed: %s\n"),
176 machine_name, dns_errstr(dns_err));
177 status = NT_STATUS_UNSUCCESSFUL;
178 goto done;
181 done:
183 SAFE_FREE( root_domain );
185 return status;
188 NTSTATUS net_update_dns_ext(struct net_context *c,
189 TALLOC_CTX *mem_ctx, ADS_STRUCT *ads,
190 const char *hostname,
191 struct sockaddr_storage *iplist,
192 int num_addrs, bool remove_host)
194 struct sockaddr_storage *iplist_alloc = NULL;
195 fstring machine_name;
196 NTSTATUS status;
198 if (hostname) {
199 fstrcpy(machine_name, hostname);
200 } else {
201 name_to_fqdn( machine_name, lp_netbios_name() );
203 if (!strlower_m( machine_name )) {
204 return NT_STATUS_INVALID_PARAMETER;
208 * If remove_host is true, then remove all IP addresses associated with
209 * this hostname from the AD server.
211 if (!remove_host && (num_addrs == 0 || iplist == NULL)) {
213 * Get our ip address
214 * (not the 127.0.0.x address but a real ip address)
216 num_addrs = get_my_ip_address(&iplist_alloc);
217 if ( num_addrs <= 0 ) {
218 DEBUG(4, ("net_update_dns_ext: Failed to find my "
219 "non-loopback IP addresses!\n"));
220 return NT_STATUS_INVALID_PARAMETER;
222 iplist = iplist_alloc;
225 status = net_update_dns_internal(c, mem_ctx, ads, machine_name,
226 iplist, num_addrs, remove_host);
228 SAFE_FREE(iplist_alloc);
229 return status;
232 static NTSTATUS net_update_dns(struct net_context *c, TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, const char *hostname)
234 NTSTATUS status;
236 status = net_update_dns_ext(c, mem_ctx, ads, hostname, NULL, 0, false);
237 return status;
239 #endif
241 void net_ads_join_dns_updates(struct net_context *c, TALLOC_CTX *ctx, struct libnet_JoinCtx *r)
243 #if defined(HAVE_KRB5)
244 ADS_STRUCT *ads_dns = NULL;
245 int ret;
246 NTSTATUS status;
247 char *machine_password = NULL;
250 * In a clustered environment, don't do dynamic dns updates:
251 * Registering the set of ip addresses that are assigned to
252 * the interfaces of the node that performs the join does usually
253 * not have the desired effect, since the local interfaces do not
254 * carry the complete set of the cluster's public IP addresses.
255 * And it can also contain internal addresses that should not
256 * be visible to the outside at all.
257 * In order to do dns updates in a clustererd setup, use
258 * net ads dns register.
260 if (lp_clustering()) {
261 d_fprintf(stderr, _("Not doing automatic DNS update in a "
262 "clustered setup.\n"));
263 return;
266 if (!r->out.domain_is_ad) {
267 return;
271 * We enter this block with user creds.
272 * kinit with the machine password to do dns update.
275 ads_dns = ads_init(ctx,
276 lp_realm(),
277 NULL,
278 r->in.dc_name,
279 ADS_SASL_PLAIN);
280 if (ads_dns == NULL) {
281 d_fprintf(stderr, _("DNS update failed: out of memory!\n"));
282 goto done;
285 use_in_memory_ccache();
287 ads_dns->auth.user_name = talloc_asprintf(ads_dns,
288 "%s$",
289 lp_netbios_name());
290 if (ads_dns->auth.user_name == NULL) {
291 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
292 goto done;
295 machine_password = secrets_fetch_machine_password(
296 r->out.netbios_domain_name, NULL, NULL);
297 if (machine_password != NULL) {
298 ads_dns->auth.password = talloc_strdup(ads_dns,
299 machine_password);
300 SAFE_FREE(machine_password);
301 if (ads_dns->auth.password == NULL) {
302 d_fprintf(stderr,
303 _("DNS update failed: out of memory\n"));
304 goto done;
308 ads_dns->auth.realm = talloc_asprintf_strupper_m(ads_dns, "%s", r->out.dns_domain_name);
309 if (ads_dns->auth.realm == NULL) {
310 d_fprintf(stderr, _("talloc_asprintf_strupper_m %s failed\n"),
311 ads_dns->auth.realm);
312 goto done;
315 ret = ads_kinit_password(ads_dns);
316 if (ret != 0) {
317 d_fprintf(stderr,
318 _("DNS update failed: kinit failed: %s\n"),
319 error_message(ret));
320 goto done;
323 status = net_update_dns(c, ctx, ads_dns, NULL);
324 if (!NT_STATUS_IS_OK(status)) {
325 d_fprintf( stderr, _("DNS update failed: %s\n"),
326 nt_errstr(status));
329 done:
330 TALLOC_FREE(ads_dns);
331 #endif
333 return;
336 #endif /* HAVE_ADS */