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