Line data Source code
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)
8 :
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.
13 :
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.
18 :
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/>.
21 : */
22 :
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"
30 :
31 : #ifdef HAVE_ADS
32 :
33 : /*******************************************************************
34 : Send a DNS update request
35 : *******************************************************************/
36 :
37 : #if defined(HAVE_KRB5)
38 : #include "../lib/addns/dns.h"
39 :
40 304 : void use_in_memory_ccache(void) {
41 : /* Use in-memory credentials cache so we do not interfere with
42 : * existing credentials */
43 304 : setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
44 304 : }
45 :
46 68 : 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)
51 : {
52 68 : struct dns_rr_ns *nameservers = NULL;
53 68 : size_t ns_count = 0, i;
54 68 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
55 0 : DNS_ERROR dns_err;
56 0 : fstring dns_server;
57 68 : const char *dnsdomain = NULL;
58 68 : char *root_domain = NULL;
59 68 : uint32_t ttl = 3600;
60 :
61 68 : if (c->opt_dns_ttl > 0) {
62 2 : ttl = MIN(c->opt_dns_ttl, UINT32_MAX);
63 : }
64 :
65 68 : if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
66 26 : d_printf(_("No DNS domain configured for %s. "
67 : "Unable to perform DNS Update.\n"), machine_name);
68 26 : status = NT_STATUS_INVALID_PARAMETER;
69 26 : goto done;
70 : }
71 42 : dnsdomain++;
72 :
73 42 : status = ads_dns_lookup_ns(ctx,
74 : dnsdomain,
75 : &nameservers,
76 : &ns_count);
77 42 : 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) */
81 :
82 22 : const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
83 22 : LDAPMessage *msg = NULL;
84 0 : char *root_dn;
85 0 : ADS_STATUS ads_status;
86 :
87 22 : if ( !ads->ldap.ld ) {
88 2 : ads_status = ads_connect( ads );
89 2 : if ( !ADS_ERR_OK(ads_status) ) {
90 0 : DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
91 0 : goto done;
92 : }
93 : }
94 :
95 22 : ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
96 : "(objectclass=*)", rootname_attrs, &msg);
97 22 : if (!ADS_ERR_OK(ads_status)) {
98 0 : goto done;
99 : }
100 :
101 22 : root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
102 22 : if ( !root_dn ) {
103 0 : ads_msgfree( ads, msg );
104 0 : goto done;
105 : }
106 :
107 22 : root_domain = ads_build_domain( root_dn );
108 :
109 : /* cleanup */
110 22 : ads_msgfree( ads, msg );
111 :
112 : /* try again for NS servers */
113 :
114 22 : status = ads_dns_lookup_ns(ctx,
115 : root_domain,
116 : &nameservers,
117 : &ns_count);
118 :
119 22 : if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
120 0 : DEBUG(3,("net_update_dns_internal: Failed to find name server for the %s "
121 : "realm\n", ads->config.realm));
122 0 : if (ns_count == 0) {
123 0 : status = NT_STATUS_UNSUCCESSFUL;
124 : }
125 0 : goto done;
126 : }
127 :
128 22 : dnsdomain = root_domain;
129 :
130 : }
131 :
132 42 : for (i=0; i < ns_count; i++) {
133 :
134 42 : uint32_t flags = DNS_UPDATE_SIGNED |
135 : DNS_UPDATE_UNSIGNED |
136 : DNS_UPDATE_UNSIGNED_SUFFICIENT |
137 : DNS_UPDATE_PROBE |
138 : DNS_UPDATE_PROBE_SUFFICIENT;
139 :
140 42 : if (c->opt_force) {
141 2 : flags &= ~DNS_UPDATE_PROBE_SUFFICIENT;
142 2 : flags &= ~DNS_UPDATE_UNSIGNED_SUFFICIENT;
143 : }
144 :
145 : /*
146 : * Do not return after PROBE completion if this function
147 : * is called for DNS removal.
148 : */
149 42 : if (remove_host) {
150 8 : flags &= ~DNS_UPDATE_PROBE_SUFFICIENT;
151 : }
152 :
153 42 : status = NT_STATUS_UNSUCCESSFUL;
154 :
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 */
157 :
158 42 : fstrcpy( dns_server, nameservers[i].hostname );
159 :
160 42 : dns_err = DoDNSUpdate(dns_server,
161 : dnsdomain,
162 : machine_name,
163 : addrs,
164 : num_addrs,
165 : flags,
166 : ttl,
167 : remove_host);
168 42 : if (ERR_DNS_IS_OK(dns_err)) {
169 38 : status = NT_STATUS_OK;
170 38 : goto done;
171 : }
172 :
173 4 : if (ERR_DNS_EQUAL(dns_err, ERROR_DNS_INVALID_NAME_SERVER) ||
174 4 : ERR_DNS_EQUAL(dns_err, ERROR_DNS_CONNECTION_FAILED) ||
175 4 : ERR_DNS_EQUAL(dns_err, ERROR_DNS_SOCKET_ERROR)) {
176 0 : DEBUG(1,("retrying DNS update with next nameserver after receiving %s\n",
177 : dns_errstr(dns_err)));
178 0 : continue;
179 : }
180 :
181 4 : d_printf(_("DNS Update for %s failed: %s\n"),
182 : machine_name, dns_errstr(dns_err));
183 4 : status = NT_STATUS_UNSUCCESSFUL;
184 4 : goto done;
185 : }
186 :
187 0 : done:
188 :
189 68 : SAFE_FREE( root_domain );
190 :
191 68 : return status;
192 : }
193 :
194 68 : 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)
199 : {
200 68 : struct sockaddr_storage *iplist_alloc = NULL;
201 0 : fstring machine_name;
202 0 : NTSTATUS status;
203 :
204 68 : if (hostname) {
205 20 : fstrcpy(machine_name, hostname);
206 : } else {
207 48 : name_to_fqdn( machine_name, lp_netbios_name() );
208 : }
209 68 : if (!strlower_m( machine_name )) {
210 0 : return NT_STATUS_INVALID_PARAMETER;
211 : }
212 :
213 : /*
214 : * If remove_host is true, then remove all IP addresses associated with
215 : * this hostname from the AD server.
216 : */
217 68 : if (!remove_host && (num_addrs == 0 || iplist == NULL)) {
218 : /*
219 : * Get our ip address
220 : * (not the 127.0.0.x address but a real ip address)
221 : */
222 48 : num_addrs = get_my_ip_address(&iplist_alloc);
223 48 : if ( num_addrs <= 0 ) {
224 0 : DEBUG(4, ("net_update_dns_ext: Failed to find my "
225 : "non-loopback IP addresses!\n"));
226 0 : return NT_STATUS_INVALID_PARAMETER;
227 : }
228 48 : iplist = iplist_alloc;
229 : }
230 :
231 68 : status = net_update_dns_internal(c, mem_ctx, ads, machine_name,
232 : iplist, num_addrs, remove_host);
233 :
234 68 : SAFE_FREE(iplist_alloc);
235 68 : return status;
236 : }
237 :
238 48 : static NTSTATUS net_update_dns(struct net_context *c, TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, const char *hostname)
239 : {
240 0 : NTSTATUS status;
241 :
242 48 : status = net_update_dns_ext(c, mem_ctx, ads, hostname, NULL, 0, false);
243 48 : return status;
244 : }
245 : #endif
246 :
247 48 : void net_ads_join_dns_updates(struct net_context *c, TALLOC_CTX *ctx, struct libnet_JoinCtx *r)
248 : {
249 : #if defined(HAVE_KRB5)
250 48 : ADS_STRUCT *ads_dns = NULL;
251 0 : int ret;
252 0 : NTSTATUS status;
253 48 : char *machine_password = NULL;
254 :
255 : /*
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.
265 : */
266 48 : if (lp_clustering()) {
267 0 : d_fprintf(stderr, _("Not doing automatic DNS update in a "
268 : "clustered setup.\n"));
269 0 : return;
270 : }
271 :
272 48 : if (!r->out.domain_is_ad) {
273 0 : return;
274 : }
275 :
276 : /*
277 : * We enter this block with user creds.
278 : * kinit with the machine password to do dns update.
279 : */
280 :
281 48 : ads_dns = ads_init(ctx,
282 : lp_realm(),
283 : NULL,
284 : r->in.dc_name,
285 : ADS_SASL_PLAIN);
286 48 : if (ads_dns == NULL) {
287 0 : d_fprintf(stderr, _("DNS update failed: out of memory!\n"));
288 0 : goto done;
289 : }
290 :
291 48 : use_in_memory_ccache();
292 :
293 48 : ads_dns->auth.user_name = talloc_asprintf(ads_dns,
294 : "%s$",
295 : lp_netbios_name());
296 48 : if (ads_dns->auth.user_name == NULL) {
297 0 : d_fprintf(stderr, _("DNS update failed: out of memory\n"));
298 0 : goto done;
299 : }
300 :
301 48 : machine_password = secrets_fetch_machine_password(
302 : r->out.netbios_domain_name, NULL, NULL);
303 48 : if (machine_password != NULL) {
304 48 : ads_dns->auth.password = talloc_strdup(ads_dns,
305 : machine_password);
306 48 : SAFE_FREE(machine_password);
307 48 : if (ads_dns->auth.password == NULL) {
308 0 : d_fprintf(stderr,
309 0 : _("DNS update failed: out of memory\n"));
310 0 : goto done;
311 : }
312 : }
313 :
314 48 : ads_dns->auth.realm = talloc_asprintf_strupper_m(ads_dns, "%s", r->out.dns_domain_name);
315 48 : if (ads_dns->auth.realm == NULL) {
316 0 : d_fprintf(stderr, _("talloc_asprintf_strupper_m %s failed\n"),
317 : ads_dns->auth.realm);
318 0 : goto done;
319 : }
320 :
321 48 : ret = ads_kinit_password(ads_dns);
322 48 : if (ret != 0) {
323 0 : d_fprintf(stderr,
324 0 : _("DNS update failed: kinit failed: %s\n"),
325 : error_message(ret));
326 0 : goto done;
327 : }
328 :
329 48 : status = net_update_dns(c, ctx, ads_dns, NULL);
330 48 : if (!NT_STATUS_IS_OK(status)) {
331 28 : d_fprintf( stderr, _("DNS update failed: %s\n"),
332 : nt_errstr(status));
333 : }
334 :
335 20 : done:
336 48 : TALLOC_FREE(ads_dns);
337 : #endif
338 :
339 48 : return;
340 : }
341 :
342 : #endif /* HAVE_ADS */
|