Line data Source code
1 : /*
2 : Samba Unix/Linux SMB client library
3 : net ads commands
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 "libsmb/namequery.h"
26 : #include "rpc_client/cli_pipe.h"
27 : #include "librpc/gen_ndr/ndr_krb5pac.h"
28 : #include "../librpc/gen_ndr/ndr_spoolss.h"
29 : #include "nsswitch/libwbclient/wbclient.h"
30 : #include "ads.h"
31 : #include "libads/cldap.h"
32 : #include "../lib/addns/dnsquery.h"
33 : #include "../libds/common/flags.h"
34 : #include "librpc/gen_ndr/libnet_join.h"
35 : #include "libnet/libnet_join.h"
36 : #include "smb_krb5.h"
37 : #include "secrets.h"
38 : #include "krb5_env.h"
39 : #include "../libcli/security/security.h"
40 : #include "libsmb/libsmb.h"
41 : #include "lib/param/loadparm.h"
42 : #include "utils/net_dns.h"
43 : #include "auth/kerberos/pac_utils.h"
44 : #include "lib/util/string_wrappers.h"
45 :
46 : #ifdef HAVE_JANSSON
47 : #include <jansson.h>
48 : #include "audit_logging.h" /* various JSON helpers */
49 : #include "auth/common_auth.h"
50 : #endif /* [HAVE_JANSSON] */
51 :
52 : #ifdef HAVE_ADS
53 :
54 : /* when we do not have sufficient input parameters to contact a remote domain
55 : * we always fall back to our own realm - Guenther*/
56 :
57 56 : static const char *assume_own_realm(struct net_context *c)
58 : {
59 56 : if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
60 56 : return lp_realm();
61 : }
62 :
63 0 : return NULL;
64 : }
65 :
66 : #ifdef HAVE_JANSSON
67 :
68 : /*
69 : * note: JSON output deliberately bypasses gettext so as to provide the same
70 : * output irrespective of the locale.
71 : */
72 :
73 4 : static int output_json(const struct json_object *jsobj)
74 : {
75 4 : TALLOC_CTX *ctx = NULL;
76 4 : char *json = NULL;
77 :
78 4 : if (json_is_invalid(jsobj)) {
79 0 : return -1;
80 : }
81 :
82 4 : ctx = talloc_new(NULL);
83 4 : if (ctx == NULL) {
84 0 : d_fprintf(stderr, _("Out of memory\n"));
85 0 : return -1;
86 : }
87 :
88 4 : json = json_to_string(ctx, jsobj);
89 4 : if (!json) {
90 0 : d_fprintf(stderr, _("error encoding to JSON\n"));
91 0 : return -1;
92 : }
93 :
94 4 : d_printf("%s\n", json);
95 4 : TALLOC_FREE(ctx);
96 :
97 4 : return 0;
98 : }
99 :
100 2 : static int net_ads_cldap_netlogon_json
101 : (ADS_STRUCT *ads,
102 : const char *addr,
103 : const struct NETLOGON_SAM_LOGON_RESPONSE_EX *reply)
104 : {
105 2 : struct json_object jsobj = json_new_object();
106 2 : struct json_object flagsobj = json_new_object();
107 2 : char response_type [32] = { '\0' };
108 2 : int ret = 0;
109 :
110 2 : if (json_is_invalid(&jsobj) || json_is_invalid(&flagsobj)) {
111 0 : d_fprintf(stderr, _("error setting up JSON value\n"));
112 :
113 0 : goto failure;
114 : }
115 :
116 2 : switch (reply->command) {
117 0 : case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
118 0 : strncpy(response_type,
119 : "LOGON_SAM_LOGON_USER_UNKNOWN_EX",
120 : sizeof(response_type));
121 0 : break;
122 2 : case LOGON_SAM_LOGON_RESPONSE_EX:
123 2 : strncpy(response_type, "LOGON_SAM_LOGON_RESPONSE_EX",
124 : sizeof(response_type));
125 2 : break;
126 0 : default:
127 0 : snprintf(response_type, sizeof(response_type), "0x%x",
128 0 : reply->command);
129 0 : break;
130 : }
131 :
132 2 : ret = json_add_string(&jsobj, "Information for Domain Controller",
133 : addr);
134 2 : if (ret != 0) {
135 0 : goto failure;
136 : }
137 :
138 2 : ret = json_add_string(&jsobj, "Response Type", response_type);
139 2 : if (ret != 0) {
140 0 : goto failure;
141 : }
142 :
143 2 : ret = json_add_guid(&jsobj, "GUID", &reply->domain_uuid);
144 2 : if (ret != 0) {
145 0 : goto failure;
146 : }
147 :
148 2 : ret = json_add_bool(&flagsobj, "Is a PDC",
149 2 : reply->server_type & NBT_SERVER_PDC);
150 2 : if (ret != 0) {
151 0 : goto failure;
152 : }
153 :
154 2 : ret = json_add_bool(&flagsobj, "Is a GC of the forest",
155 2 : reply->server_type & NBT_SERVER_GC);
156 2 : if (ret != 0) {
157 0 : goto failure;
158 : }
159 :
160 2 : ret = json_add_bool(&flagsobj, "Is an LDAP server",
161 2 : reply->server_type & NBT_SERVER_LDAP);
162 2 : if (ret != 0) {
163 0 : goto failure;
164 : }
165 :
166 2 : ret = json_add_bool(&flagsobj, "Supports DS",
167 2 : reply->server_type & NBT_SERVER_DS);
168 2 : if (ret != 0) {
169 0 : goto failure;
170 : }
171 :
172 2 : ret = json_add_bool(&flagsobj, "Is running a KDC",
173 2 : reply->server_type & NBT_SERVER_KDC);
174 2 : if (ret != 0) {
175 0 : goto failure;
176 : }
177 :
178 2 : ret = json_add_bool(&flagsobj, "Is running time services",
179 2 : reply->server_type & NBT_SERVER_TIMESERV);
180 2 : if (ret != 0) {
181 0 : goto failure;
182 : }
183 :
184 2 : ret = json_add_bool(&flagsobj, "Is the closest DC",
185 2 : reply->server_type & NBT_SERVER_CLOSEST);
186 2 : if (ret != 0) {
187 0 : goto failure;
188 : }
189 :
190 2 : ret = json_add_bool(&flagsobj, "Is writable",
191 2 : reply->server_type & NBT_SERVER_WRITABLE);
192 2 : if (ret != 0) {
193 0 : goto failure;
194 : }
195 :
196 2 : ret = json_add_bool(&flagsobj, "Has a hardware clock",
197 2 : reply->server_type & NBT_SERVER_GOOD_TIMESERV);
198 2 : if (ret != 0) {
199 0 : goto failure;
200 : }
201 :
202 2 : ret = json_add_bool(&flagsobj,
203 : "Is a non-domain NC serviced by LDAP server",
204 2 : reply->server_type & NBT_SERVER_NDNC);
205 2 : if (ret != 0) {
206 0 : goto failure;
207 : }
208 :
209 2 : ret = json_add_bool
210 : (&flagsobj, "Is NT6 DC that has some secrets",
211 2 : reply->server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6);
212 2 : if (ret != 0) {
213 0 : goto failure;
214 : }
215 :
216 2 : ret = json_add_bool
217 : (&flagsobj, "Is NT6 DC that has all secrets",
218 2 : reply->server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6);
219 2 : if (ret != 0) {
220 0 : goto failure;
221 : }
222 :
223 2 : ret = json_add_bool(&flagsobj, "Runs Active Directory Web Services",
224 2 : reply->server_type & NBT_SERVER_ADS_WEB_SERVICE);
225 2 : if (ret != 0) {
226 0 : goto failure;
227 : }
228 :
229 2 : ret = json_add_bool(&flagsobj, "Runs on Windows 2012 or later",
230 2 : reply->server_type & NBT_SERVER_DS_8);
231 2 : if (ret != 0) {
232 0 : goto failure;
233 : }
234 :
235 2 : ret = json_add_string(&jsobj, "Forest", reply->forest);
236 2 : if (ret != 0) {
237 0 : goto failure;
238 : }
239 :
240 2 : ret = json_add_string(&jsobj, "Domain", reply->dns_domain);
241 2 : if (ret != 0) {
242 0 : goto failure;
243 : }
244 :
245 2 : ret = json_add_string(&jsobj, "Domain Controller", reply->pdc_dns_name);
246 2 : if (ret != 0) {
247 0 : goto failure;
248 : }
249 :
250 :
251 2 : ret = json_add_string(&jsobj, "Pre-Win2k Domain", reply->domain_name);
252 2 : if (ret != 0) {
253 0 : goto failure;
254 : }
255 :
256 2 : ret = json_add_string(&jsobj, "Pre-Win2k Hostname", reply->pdc_name);
257 2 : if (ret != 0) {
258 0 : goto failure;
259 : }
260 :
261 2 : if (*reply->user_name) {
262 0 : ret = json_add_string(&jsobj, "User name", reply->user_name);
263 0 : if (ret != 0) {
264 0 : goto failure;
265 : }
266 : }
267 :
268 2 : ret = json_add_string(&jsobj, "Server Site Name", reply->server_site);
269 2 : if (ret != 0) {
270 0 : goto failure;
271 : }
272 :
273 2 : ret = json_add_string(&jsobj, "Client Site Name", reply->client_site);
274 2 : if (ret != 0) {
275 0 : goto failure;
276 : }
277 :
278 2 : ret = json_add_int(&jsobj, "NT Version", reply->nt_version);
279 2 : if (ret != 0) {
280 0 : goto failure;
281 : }
282 :
283 2 : ret = json_add_int(&jsobj, "LMNT Token", reply->lmnt_token);
284 2 : if (ret != 0) {
285 0 : goto failure;
286 : }
287 :
288 2 : ret = json_add_int(&jsobj, "LM20 Token", reply->lm20_token);
289 2 : if (ret != 0) {
290 0 : goto failure;
291 : }
292 :
293 2 : ret = json_add_object(&jsobj, "Flags", &flagsobj);
294 2 : if (ret != 0) {
295 0 : goto failure;
296 : }
297 :
298 2 : ret = output_json(&jsobj);
299 2 : json_free(&jsobj); /* frees flagsobj recursively */
300 :
301 2 : return ret;
302 :
303 0 : failure:
304 0 : json_free(&flagsobj);
305 0 : json_free(&jsobj);
306 :
307 0 : return ret;
308 : }
309 :
310 : #else /* [HAVE_JANSSON] */
311 :
312 : static int net_ads_cldap_netlogon_json
313 : (ADS_STRUCT *ads,
314 : const char *addr,
315 : const struct NETLOGON_SAM_LOGON_RESPONSE_EX * reply)
316 : {
317 : d_fprintf(stderr, _("JSON support not available\n"));
318 :
319 : return -1;
320 : }
321 :
322 : #endif /* [HAVE_JANSSON] */
323 :
324 : /*
325 : do a cldap netlogon query
326 : */
327 3 : static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
328 : {
329 : char addr[INET6_ADDRSTRLEN];
330 : struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
331 :
332 3 : print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
333 :
334 3 : if ( !ads_cldap_netlogon_5(talloc_tos(), &ads->ldap.ss, ads->server.realm, &reply ) ) {
335 0 : d_fprintf(stderr, _("CLDAP query failed!\n"));
336 0 : return -1;
337 : }
338 :
339 3 : if (c->opt_json) {
340 2 : return net_ads_cldap_netlogon_json(ads, addr, &reply);
341 : }
342 :
343 1 : d_printf(_("Information for Domain Controller: %s\n\n"),
344 : addr);
345 :
346 1 : d_printf(_("Response Type: "));
347 1 : switch (reply.command) {
348 0 : case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
349 0 : d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
350 0 : break;
351 1 : case LOGON_SAM_LOGON_RESPONSE_EX:
352 1 : d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
353 1 : break;
354 0 : default:
355 0 : d_printf("0x%x\n", reply.command);
356 0 : break;
357 : }
358 :
359 1 : d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
360 :
361 14 : d_printf(_("Flags:\n"
362 : "\tIs a PDC: %s\n"
363 : "\tIs a GC of the forest: %s\n"
364 : "\tIs an LDAP server: %s\n"
365 : "\tSupports DS: %s\n"
366 : "\tIs running a KDC: %s\n"
367 : "\tIs running time services: %s\n"
368 : "\tIs the closest DC: %s\n"
369 : "\tIs writable: %s\n"
370 : "\tHas a hardware clock: %s\n"
371 : "\tIs a non-domain NC serviced by LDAP server: %s\n"
372 : "\tIs NT6 DC that has some secrets: %s\n"
373 : "\tIs NT6 DC that has all secrets: %s\n"
374 : "\tRuns Active Directory Web Services: %s\n"
375 : "\tRuns on Windows 2012 or later: %s\n"),
376 1 : (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
377 1 : (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
378 1 : (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
379 1 : (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
380 1 : (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
381 1 : (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
382 1 : (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
383 1 : (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
384 1 : (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
385 1 : (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
386 1 : (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
387 1 : (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"),
388 1 : (reply.server_type & NBT_SERVER_ADS_WEB_SERVICE) ? _("yes") : _("no"),
389 1 : (reply.server_type & NBT_SERVER_DS_8) ? _("yes") : _("no"));
390 :
391 :
392 1 : printf(_("Forest: %s\n"), reply.forest);
393 1 : printf(_("Domain: %s\n"), reply.dns_domain);
394 1 : printf(_("Domain Controller: %s\n"), reply.pdc_dns_name);
395 :
396 1 : printf(_("Pre-Win2k Domain: %s\n"), reply.domain_name);
397 1 : printf(_("Pre-Win2k Hostname: %s\n"), reply.pdc_name);
398 :
399 1 : if (*reply.user_name) printf(_("User name: %s\n"), reply.user_name);
400 :
401 1 : printf(_("Server Site Name: %s\n"), reply.server_site);
402 1 : printf(_("Client Site Name: %s\n"), reply.client_site);
403 :
404 1 : d_printf(_("NT Version: %d\n"), reply.nt_version);
405 1 : d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
406 1 : d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
407 :
408 1 : return 0;
409 : }
410 :
411 : /*
412 : this implements the CLDAP based netlogon lookup requests
413 : for finding the domain controller of a ADS domain
414 : */
415 3 : static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
416 : {
417 : ADS_STRUCT *ads;
418 : int ret;
419 :
420 3 : if (c->display_usage) {
421 0 : d_printf("%s\n"
422 : "net ads lookup\n"
423 : " %s",
424 : _("Usage:"),
425 : _("Find the ADS DC using CLDAP lookup.\n"));
426 0 : return 0;
427 : }
428 :
429 3 : if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
430 0 : d_fprintf(stderr, _("Didn't find the cldap server!\n"));
431 0 : ads_destroy(&ads);
432 0 : return -1;
433 : }
434 :
435 3 : if (!ads->config.realm) {
436 0 : ads->config.realm = discard_const_p(char, c->opt_target_workgroup);
437 0 : ads->ldap.port = 389;
438 : }
439 :
440 3 : ret = net_ads_cldap_netlogon(c, ads);
441 3 : ads_destroy(&ads);
442 3 : return ret;
443 : }
444 :
445 :
446 : #ifdef HAVE_JANSSON
447 :
448 2 : static int net_ads_info_json(ADS_STRUCT *ads)
449 : {
450 2 : int ret = 0;
451 : char addr[INET6_ADDRSTRLEN];
452 : time_t pass_time;
453 2 : struct json_object jsobj = json_new_object();
454 :
455 2 : if (json_is_invalid(&jsobj)) {
456 0 : d_fprintf(stderr, _("error setting up JSON value\n"));
457 :
458 0 : goto failure;
459 : }
460 :
461 2 : pass_time = secrets_fetch_pass_last_set_time(ads->server.workgroup);
462 :
463 2 : print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
464 :
465 2 : ret = json_add_string (&jsobj, "LDAP server", addr);
466 2 : if (ret != 0) {
467 0 : goto failure;
468 : }
469 :
470 2 : ret = json_add_string (&jsobj, "LDAP server name",
471 2 : ads->config.ldap_server_name);
472 2 : if (ret != 0) {
473 0 : goto failure;
474 : }
475 :
476 2 : ret = json_add_string (&jsobj, "Realm", ads->config.realm);
477 2 : if (ret != 0) {
478 0 : goto failure;
479 : }
480 :
481 2 : ret = json_add_string (&jsobj, "Bind Path", ads->config.bind_path);
482 2 : if (ret != 0) {
483 0 : goto failure;
484 : }
485 :
486 2 : ret = json_add_int (&jsobj, "LDAP port", ads->ldap.port);
487 2 : if (ret != 0) {
488 0 : goto failure;
489 : }
490 :
491 2 : ret = json_add_int (&jsobj, "Server time", ads->config.current_time);
492 2 : if (ret != 0) {
493 0 : goto failure;
494 : }
495 :
496 2 : ret = json_add_string (&jsobj, "KDC server", ads->auth.kdc_server);
497 2 : if (ret != 0) {
498 0 : goto failure;
499 : }
500 :
501 2 : ret = json_add_int (&jsobj, "Server time offset",
502 2 : ads->auth.time_offset);
503 2 : if (ret != 0) {
504 0 : goto failure;
505 : }
506 :
507 2 : ret = json_add_int (&jsobj, "Last machine account password change",
508 : pass_time);
509 2 : if (ret != 0) {
510 0 : goto failure;
511 : }
512 :
513 2 : ret = output_json(&jsobj);
514 2 : failure:
515 2 : json_free(&jsobj);
516 2 : ads_destroy(&ads);
517 :
518 2 : return ret;
519 : }
520 :
521 : #else /* [HAVE_JANSSON] */
522 :
523 : static int net_ads_info_json(ADS_STRUCT *ads)
524 : {
525 : d_fprintf(stderr, _("JSON support not available\n"));
526 :
527 : return -1;
528 : }
529 :
530 : #endif /* [HAVE_JANSSON] */
531 :
532 :
533 :
534 3 : static int net_ads_info(struct net_context *c, int argc, const char **argv)
535 : {
536 : ADS_STRUCT *ads;
537 : char addr[INET6_ADDRSTRLEN];
538 : time_t pass_time;
539 :
540 3 : if (c->display_usage) {
541 0 : d_printf("%s\n"
542 : "net ads info\n"
543 : " %s",
544 : _("Usage:"),
545 : _("Display information about an Active Directory "
546 : "server.\n"));
547 0 : return 0;
548 : }
549 :
550 3 : if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
551 0 : d_fprintf(stderr, _("Didn't find the ldap server!\n"));
552 0 : return -1;
553 : }
554 :
555 3 : if (!ads || !ads->config.realm) {
556 0 : d_fprintf(stderr, _("Didn't find the ldap server!\n"));
557 0 : ads_destroy(&ads);
558 0 : return -1;
559 : }
560 :
561 : /* Try to set the server's current time since we didn't do a full
562 : TCP LDAP session initially */
563 :
564 3 : if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
565 0 : d_fprintf( stderr, _("Failed to get server's current time!\n"));
566 : }
567 :
568 3 : if (c->opt_json) {
569 2 : return net_ads_info_json(ads);
570 : }
571 :
572 1 : pass_time = secrets_fetch_pass_last_set_time(ads->server.workgroup);
573 :
574 1 : print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
575 :
576 1 : d_printf(_("LDAP server: %s\n"), addr);
577 1 : d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
578 1 : d_printf(_("Realm: %s\n"), ads->config.realm);
579 1 : d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
580 1 : d_printf(_("LDAP port: %d\n"), ads->ldap.port);
581 1 : d_printf(_("Server time: %s\n"),
582 1 : http_timestring(talloc_tos(), ads->config.current_time));
583 :
584 1 : d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
585 1 : d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
586 :
587 1 : d_printf(_("Last machine account password change: %s\n"),
588 : http_timestring(talloc_tos(), pass_time));
589 :
590 1 : ads_destroy(&ads);
591 1 : return 0;
592 : }
593 :
594 276 : static void use_in_memory_ccache(void) {
595 : /* Use in-memory credentials cache so we do not interfere with
596 : * existing credentials */
597 276 : setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
598 276 : }
599 :
600 182 : static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
601 : uint32_t auth_flags, ADS_STRUCT **ads_ret)
602 : {
603 182 : ADS_STRUCT *ads = NULL;
604 : ADS_STATUS status;
605 182 : bool need_password = false;
606 182 : bool second_time = false;
607 : char *cp;
608 182 : const char *realm = NULL;
609 182 : bool tried_closest_dc = false;
610 :
611 : /* lp_realm() should be handled by a command line param,
612 : However, the join requires that realm be set in smb.conf
613 : and compares our realm with the remote server's so this is
614 : ok until someone needs more flexibility */
615 :
616 182 : *ads_ret = NULL;
617 :
618 182 : retry_connect:
619 182 : if (only_own_domain) {
620 126 : realm = lp_realm();
621 : } else {
622 56 : realm = assume_own_realm(c);
623 : }
624 :
625 182 : ads = ads_init(realm,
626 : c->opt_target_workgroup,
627 : c->opt_host,
628 : ADS_SASL_PLAIN);
629 :
630 182 : if (!c->opt_user_name) {
631 0 : c->opt_user_name = "administrator";
632 : }
633 :
634 182 : if (c->opt_user_specified) {
635 170 : need_password = true;
636 : }
637 :
638 194 : retry:
639 182 : if (!c->opt_password && need_password && !c->opt_machine_pass) {
640 72 : c->opt_password = net_prompt_pass(c, c->opt_user_name);
641 72 : if (!c->opt_password) {
642 0 : ads_destroy(&ads);
643 0 : return ADS_ERROR(LDAP_NO_MEMORY);
644 : }
645 : }
646 :
647 182 : if (c->opt_password) {
648 170 : use_in_memory_ccache();
649 170 : SAFE_FREE(ads->auth.password);
650 170 : ads->auth.password = smb_xstrdup(c->opt_password);
651 : }
652 :
653 182 : ads->auth.flags |= auth_flags;
654 182 : SAFE_FREE(ads->auth.user_name);
655 182 : ads->auth.user_name = smb_xstrdup(c->opt_user_name);
656 :
657 : /*
658 : * If the username is of the form "name@realm",
659 : * extract the realm and convert to upper case.
660 : * This is only used to establish the connection.
661 : */
662 182 : if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
663 38 : *cp++ = '\0';
664 38 : SAFE_FREE(ads->auth.realm);
665 38 : ads->auth.realm = smb_xstrdup(cp);
666 38 : if (!strupper_m(ads->auth.realm)) {
667 0 : ads_destroy(&ads);
668 0 : return ADS_ERROR(LDAP_NO_MEMORY);
669 : }
670 : }
671 :
672 182 : status = ads_connect(ads);
673 :
674 182 : if (!ADS_ERR_OK(status)) {
675 :
676 0 : if (NT_STATUS_EQUAL(ads_ntstatus(status),
677 : NT_STATUS_NO_LOGON_SERVERS)) {
678 0 : DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
679 0 : ads_destroy(&ads);
680 0 : return status;
681 : }
682 :
683 0 : if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
684 0 : need_password = true;
685 0 : second_time = true;
686 0 : goto retry;
687 : } else {
688 0 : ads_destroy(&ads);
689 0 : return status;
690 : }
691 : }
692 :
693 : /* when contacting our own domain, make sure we use the closest DC.
694 : * This is done by reconnecting to ADS because only the first call to
695 : * ads_connect will give us our own sitename */
696 :
697 182 : if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
698 :
699 182 : tried_closest_dc = true; /* avoid loop */
700 :
701 182 : if (!ads_closest_dc(ads)) {
702 :
703 0 : namecache_delete(ads->server.realm, 0x1C);
704 0 : namecache_delete(ads->server.workgroup, 0x1C);
705 :
706 0 : ads_destroy(&ads);
707 0 : ads = NULL;
708 :
709 0 : goto retry_connect;
710 : }
711 : }
712 :
713 182 : *ads_ret = ads;
714 182 : return status;
715 : }
716 :
717 170 : ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
718 : {
719 170 : return ads_startup_int(c, only_own_domain, 0, ads);
720 : }
721 :
722 12 : ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
723 : {
724 12 : return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
725 : }
726 :
727 : /*
728 : Check to see if connection can be made via ads.
729 : ads_startup() stores the password in opt_password if it needs to so
730 : that rpc or rap can use it without re-prompting.
731 : */
732 16 : static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
733 : {
734 : ADS_STRUCT *ads;
735 : ADS_STATUS status;
736 :
737 16 : ads = ads_init(realm, workgroup, host, ADS_SASL_PLAIN);
738 16 : if (ads == NULL ) {
739 0 : return -1;
740 : }
741 :
742 16 : ads->auth.flags |= ADS_AUTH_NO_BIND;
743 :
744 16 : status = ads_connect(ads);
745 16 : if ( !ADS_ERR_OK(status) ) {
746 0 : return -1;
747 : }
748 :
749 16 : ads_destroy(&ads);
750 16 : return 0;
751 : }
752 :
753 14 : int net_ads_check_our_domain(struct net_context *c)
754 : {
755 14 : return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
756 : }
757 :
758 2 : int net_ads_check(struct net_context *c)
759 : {
760 2 : return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
761 : }
762 :
763 : /*
764 : determine the netbios workgroup name for a domain
765 : */
766 0 : static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
767 : {
768 : ADS_STRUCT *ads;
769 : struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
770 :
771 0 : if (c->display_usage) {
772 0 : d_printf ("%s\n"
773 : "net ads workgroup\n"
774 : " %s\n",
775 : _("Usage:"),
776 : _("Print the workgroup name"));
777 0 : return 0;
778 : }
779 :
780 0 : if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
781 0 : d_fprintf(stderr, _("Didn't find the cldap server!\n"));
782 0 : return -1;
783 : }
784 :
785 0 : if (!ads->config.realm) {
786 0 : ads->config.realm = discard_const_p(char, c->opt_target_workgroup);
787 0 : ads->ldap.port = 389;
788 : }
789 :
790 0 : if ( !ads_cldap_netlogon_5(talloc_tos(), &ads->ldap.ss, ads->server.realm, &reply ) ) {
791 0 : d_fprintf(stderr, _("CLDAP query failed!\n"));
792 0 : ads_destroy(&ads);
793 0 : return -1;
794 : }
795 :
796 0 : d_printf(_("Workgroup: %s\n"), reply.domain_name);
797 :
798 0 : ads_destroy(&ads);
799 :
800 0 : return 0;
801 : }
802 :
803 :
804 :
805 0 : static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
806 : {
807 0 : char **disp_fields = (char **) data_area;
808 :
809 0 : if (!field) { /* must be end of record */
810 0 : if (disp_fields[0]) {
811 0 : if (!strchr_m(disp_fields[0], '$')) {
812 0 : if (disp_fields[1])
813 0 : d_printf("%-21.21s %s\n",
814 0 : disp_fields[0], disp_fields[1]);
815 : else
816 0 : d_printf("%s\n", disp_fields[0]);
817 : }
818 : }
819 0 : SAFE_FREE(disp_fields[0]);
820 0 : SAFE_FREE(disp_fields[1]);
821 0 : return true;
822 : }
823 0 : if (!values) /* must be new field, indicate string field */
824 0 : return true;
825 0 : if (strcasecmp_m(field, "sAMAccountName") == 0) {
826 0 : disp_fields[0] = SMB_STRDUP((char *) values[0]);
827 : }
828 0 : if (strcasecmp_m(field, "description") == 0)
829 0 : disp_fields[1] = SMB_STRDUP((char *) values[0]);
830 0 : return true;
831 : }
832 :
833 0 : static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
834 : {
835 0 : return net_user_usage(c, argc, argv);
836 : }
837 :
838 2 : static int ads_user_add(struct net_context *c, int argc, const char **argv)
839 : {
840 : ADS_STRUCT *ads;
841 : ADS_STATUS status;
842 : char *upn, *userdn;
843 2 : LDAPMessage *res=NULL;
844 2 : int rc = -1;
845 2 : char *ou_str = NULL;
846 :
847 2 : if (argc < 1 || c->display_usage)
848 0 : return net_ads_user_usage(c, argc, argv);
849 :
850 2 : if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
851 0 : return -1;
852 : }
853 :
854 2 : status = ads_find_user_acct(ads, &res, argv[0]);
855 :
856 2 : if (!ADS_ERR_OK(status)) {
857 0 : d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
858 0 : goto done;
859 : }
860 :
861 2 : if (ads_count_replies(ads, res)) {
862 0 : d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
863 : argv[0]);
864 0 : goto done;
865 : }
866 :
867 2 : if (c->opt_container) {
868 0 : ou_str = SMB_STRDUP(c->opt_container);
869 : } else {
870 2 : ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
871 : }
872 :
873 2 : status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
874 :
875 2 : if (!ADS_ERR_OK(status)) {
876 0 : d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
877 : ads_errstr(status));
878 0 : goto done;
879 : }
880 :
881 : /* if no password is to be set, we're done */
882 2 : if (argc == 1) {
883 0 : d_printf(_("User %s added\n"), argv[0]);
884 0 : rc = 0;
885 0 : goto done;
886 : }
887 :
888 : /* try setting the password */
889 2 : if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
890 0 : goto done;
891 : }
892 2 : status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
893 2 : ads->auth.time_offset);
894 2 : SAFE_FREE(upn);
895 2 : if (ADS_ERR_OK(status)) {
896 2 : d_printf(_("User %s added\n"), argv[0]);
897 2 : rc = 0;
898 2 : goto done;
899 : }
900 :
901 : /* password didn't set, delete account */
902 0 : d_fprintf(stderr, _("Could not add user %s. "
903 : "Error setting password %s\n"),
904 : argv[0], ads_errstr(status));
905 0 : ads_msgfree(ads, res);
906 0 : status=ads_find_user_acct(ads, &res, argv[0]);
907 0 : if (ADS_ERR_OK(status)) {
908 0 : userdn = ads_get_dn(ads, talloc_tos(), res);
909 0 : ads_del_dn(ads, userdn);
910 0 : TALLOC_FREE(userdn);
911 : }
912 :
913 1 : done:
914 2 : if (res)
915 2 : ads_msgfree(ads, res);
916 2 : ads_destroy(&ads);
917 2 : SAFE_FREE(ou_str);
918 2 : return rc;
919 : }
920 :
921 0 : static int ads_user_info(struct net_context *c, int argc, const char **argv)
922 : {
923 0 : ADS_STRUCT *ads = NULL;
924 : ADS_STATUS rc;
925 0 : LDAPMessage *res = NULL;
926 : TALLOC_CTX *frame;
927 0 : int ret = 0;
928 : wbcErr wbc_status;
929 0 : const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
930 0 : char *searchstring=NULL;
931 : char **grouplist;
932 : char *primary_group;
933 : char *escaped_user;
934 : struct dom_sid primary_group_sid;
935 : uint32_t group_rid;
936 : enum wbcSidType type;
937 :
938 0 : if (argc < 1 || c->display_usage) {
939 0 : return net_ads_user_usage(c, argc, argv);
940 : }
941 :
942 0 : frame = talloc_new(talloc_tos());
943 0 : if (frame == NULL) {
944 0 : return -1;
945 : }
946 :
947 0 : escaped_user = escape_ldap_string(frame, argv[0]);
948 0 : if (!escaped_user) {
949 0 : d_fprintf(stderr,
950 0 : _("ads_user_info: failed to escape user %s\n"),
951 : argv[0]);
952 0 : return -1;
953 : }
954 :
955 0 : if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
956 0 : ret = -1;
957 0 : goto error;
958 : }
959 :
960 0 : if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
961 0 : ret =-1;
962 0 : goto error;
963 : }
964 0 : rc = ads_search(ads, &res, searchstring, attrs);
965 0 : SAFE_FREE(searchstring);
966 :
967 0 : if (!ADS_ERR_OK(rc)) {
968 0 : d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(rc));
969 0 : ret = -1;
970 0 : goto error;
971 : }
972 :
973 0 : if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
974 0 : d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
975 0 : ret = -1;
976 0 : goto error;
977 : }
978 :
979 0 : rc = ads_domain_sid(ads, &primary_group_sid);
980 0 : if (!ADS_ERR_OK(rc)) {
981 0 : d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(rc));
982 0 : ret = -1;
983 0 : goto error;
984 : }
985 :
986 0 : sid_append_rid(&primary_group_sid, group_rid);
987 :
988 0 : wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
989 : NULL, /* don't look up domain */
990 : &primary_group,
991 : &type);
992 0 : if (!WBC_ERROR_IS_OK(wbc_status)) {
993 0 : d_fprintf(stderr, "wbcLookupSid: %s\n",
994 : wbcErrorString(wbc_status));
995 0 : ret = -1;
996 0 : goto error;
997 : }
998 :
999 0 : d_printf("%s\n", primary_group);
1000 :
1001 0 : wbcFreeMemory(primary_group);
1002 :
1003 0 : grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
1004 : (LDAPMessage *)res, "memberOf");
1005 :
1006 0 : if (grouplist) {
1007 : int i;
1008 : char **groupname;
1009 0 : for (i=0;grouplist[i];i++) {
1010 0 : groupname = ldap_explode_dn(grouplist[i], 1);
1011 0 : d_printf("%s\n", groupname[0]);
1012 0 : ldap_value_free(groupname);
1013 : }
1014 0 : ldap_value_free(grouplist);
1015 : }
1016 :
1017 0 : error:
1018 0 : if (res) ads_msgfree(ads, res);
1019 0 : if (ads) ads_destroy(&ads);
1020 0 : TALLOC_FREE(frame);
1021 0 : return ret;
1022 : }
1023 :
1024 0 : static int ads_user_delete(struct net_context *c, int argc, const char **argv)
1025 : {
1026 : ADS_STRUCT *ads;
1027 : ADS_STATUS rc;
1028 0 : LDAPMessage *res = NULL;
1029 : char *userdn;
1030 :
1031 0 : if (argc < 1) {
1032 0 : return net_ads_user_usage(c, argc, argv);
1033 : }
1034 :
1035 0 : if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1036 0 : return -1;
1037 : }
1038 :
1039 0 : rc = ads_find_user_acct(ads, &res, argv[0]);
1040 0 : if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
1041 0 : d_printf(_("User %s does not exist.\n"), argv[0]);
1042 0 : ads_msgfree(ads, res);
1043 0 : ads_destroy(&ads);
1044 0 : return -1;
1045 : }
1046 0 : userdn = ads_get_dn(ads, talloc_tos(), res);
1047 0 : ads_msgfree(ads, res);
1048 0 : rc = ads_del_dn(ads, userdn);
1049 0 : TALLOC_FREE(userdn);
1050 0 : if (ADS_ERR_OK(rc)) {
1051 0 : d_printf(_("User %s deleted\n"), argv[0]);
1052 0 : ads_destroy(&ads);
1053 0 : return 0;
1054 : }
1055 0 : d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
1056 : ads_errstr(rc));
1057 0 : ads_destroy(&ads);
1058 0 : return -1;
1059 : }
1060 :
1061 2 : int net_ads_user(struct net_context *c, int argc, const char **argv)
1062 : {
1063 2 : struct functable func[] = {
1064 : {
1065 : "add",
1066 : ads_user_add,
1067 : NET_TRANSPORT_ADS,
1068 : N_("Add an AD user"),
1069 : N_("net ads user add\n"
1070 : " Add an AD user")
1071 : },
1072 : {
1073 : "info",
1074 : ads_user_info,
1075 : NET_TRANSPORT_ADS,
1076 : N_("Display information about an AD user"),
1077 : N_("net ads user info\n"
1078 : " Display information about an AD user")
1079 : },
1080 : {
1081 : "delete",
1082 : ads_user_delete,
1083 : NET_TRANSPORT_ADS,
1084 : N_("Delete an AD user"),
1085 : N_("net ads user delete\n"
1086 : " Delete an AD user")
1087 : },
1088 : {NULL, NULL, 0, NULL, NULL}
1089 : };
1090 : ADS_STRUCT *ads;
1091 : ADS_STATUS rc;
1092 2 : const char *shortattrs[] = {"sAMAccountName", NULL};
1093 2 : const char *longattrs[] = {"sAMAccountName", "description", NULL};
1094 2 : char *disp_fields[2] = {NULL, NULL};
1095 :
1096 2 : if (argc == 0) {
1097 0 : if (c->display_usage) {
1098 0 : d_printf( "%s\n"
1099 : "net ads user\n"
1100 : " %s\n",
1101 : _("Usage:"),
1102 : _("List AD users"));
1103 0 : net_display_usage_from_functable(func);
1104 0 : return 0;
1105 : }
1106 :
1107 0 : if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1108 0 : return -1;
1109 : }
1110 :
1111 0 : if (c->opt_long_list_entries)
1112 0 : d_printf(_("\nUser name Comment"
1113 : "\n-----------------------------\n"));
1114 :
1115 0 : rc = ads_do_search_all_fn(ads, ads->config.bind_path,
1116 : LDAP_SCOPE_SUBTREE,
1117 : "(objectCategory=user)",
1118 0 : c->opt_long_list_entries ? longattrs :
1119 : shortattrs, usergrp_display,
1120 : disp_fields);
1121 0 : ads_destroy(&ads);
1122 0 : return ADS_ERR_OK(rc) ? 0 : -1;
1123 : }
1124 :
1125 2 : return net_run_function(c, argc, argv, "net ads user", func);
1126 : }
1127 :
1128 0 : static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
1129 : {
1130 0 : return net_group_usage(c, argc, argv);
1131 : }
1132 :
1133 0 : static int ads_group_add(struct net_context *c, int argc, const char **argv)
1134 : {
1135 : ADS_STRUCT *ads;
1136 : ADS_STATUS status;
1137 0 : LDAPMessage *res=NULL;
1138 0 : int rc = -1;
1139 0 : char *ou_str = NULL;
1140 :
1141 0 : if (argc < 1 || c->display_usage) {
1142 0 : return net_ads_group_usage(c, argc, argv);
1143 : }
1144 :
1145 0 : if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1146 0 : return -1;
1147 : }
1148 :
1149 0 : status = ads_find_user_acct(ads, &res, argv[0]);
1150 :
1151 0 : if (!ADS_ERR_OK(status)) {
1152 0 : d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
1153 0 : goto done;
1154 : }
1155 :
1156 0 : if (ads_count_replies(ads, res)) {
1157 0 : d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
1158 0 : goto done;
1159 : }
1160 :
1161 0 : if (c->opt_container) {
1162 0 : ou_str = SMB_STRDUP(c->opt_container);
1163 : } else {
1164 0 : ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
1165 : }
1166 :
1167 0 : status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
1168 :
1169 0 : if (ADS_ERR_OK(status)) {
1170 0 : d_printf(_("Group %s added\n"), argv[0]);
1171 0 : rc = 0;
1172 : } else {
1173 0 : d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
1174 : ads_errstr(status));
1175 : }
1176 :
1177 0 : done:
1178 0 : if (res)
1179 0 : ads_msgfree(ads, res);
1180 0 : ads_destroy(&ads);
1181 0 : SAFE_FREE(ou_str);
1182 0 : return rc;
1183 : }
1184 :
1185 0 : static int ads_group_delete(struct net_context *c, int argc, const char **argv)
1186 : {
1187 : ADS_STRUCT *ads;
1188 : ADS_STATUS rc;
1189 0 : LDAPMessage *res = NULL;
1190 : char *groupdn;
1191 :
1192 0 : if (argc < 1 || c->display_usage) {
1193 0 : return net_ads_group_usage(c, argc, argv);
1194 : }
1195 :
1196 0 : if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1197 0 : return -1;
1198 : }
1199 :
1200 0 : rc = ads_find_user_acct(ads, &res, argv[0]);
1201 0 : if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
1202 0 : d_printf(_("Group %s does not exist.\n"), argv[0]);
1203 0 : ads_msgfree(ads, res);
1204 0 : ads_destroy(&ads);
1205 0 : return -1;
1206 : }
1207 0 : groupdn = ads_get_dn(ads, talloc_tos(), res);
1208 0 : ads_msgfree(ads, res);
1209 0 : rc = ads_del_dn(ads, groupdn);
1210 0 : TALLOC_FREE(groupdn);
1211 0 : if (ADS_ERR_OK(rc)) {
1212 0 : d_printf(_("Group %s deleted\n"), argv[0]);
1213 0 : ads_destroy(&ads);
1214 0 : return 0;
1215 : }
1216 0 : d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
1217 : ads_errstr(rc));
1218 0 : ads_destroy(&ads);
1219 0 : return -1;
1220 : }
1221 :
1222 0 : int net_ads_group(struct net_context *c, int argc, const char **argv)
1223 : {
1224 0 : struct functable func[] = {
1225 : {
1226 : "add",
1227 : ads_group_add,
1228 : NET_TRANSPORT_ADS,
1229 : N_("Add an AD group"),
1230 : N_("net ads group add\n"
1231 : " Add an AD group")
1232 : },
1233 : {
1234 : "delete",
1235 : ads_group_delete,
1236 : NET_TRANSPORT_ADS,
1237 : N_("Delete an AD group"),
1238 : N_("net ads group delete\n"
1239 : " Delete an AD group")
1240 : },
1241 : {NULL, NULL, 0, NULL, NULL}
1242 : };
1243 : ADS_STRUCT *ads;
1244 : ADS_STATUS rc;
1245 0 : const char *shortattrs[] = {"sAMAccountName", NULL};
1246 0 : const char *longattrs[] = {"sAMAccountName", "description", NULL};
1247 0 : char *disp_fields[2] = {NULL, NULL};
1248 :
1249 0 : if (argc == 0) {
1250 0 : if (c->display_usage) {
1251 0 : d_printf( "%s\n"
1252 : "net ads group\n"
1253 : " %s\n",
1254 : _("Usage:"),
1255 : _("List AD groups"));
1256 0 : net_display_usage_from_functable(func);
1257 0 : return 0;
1258 : }
1259 :
1260 0 : if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1261 0 : return -1;
1262 : }
1263 :
1264 0 : if (c->opt_long_list_entries)
1265 0 : d_printf(_("\nGroup name Comment"
1266 : "\n-----------------------------\n"));
1267 0 : rc = ads_do_search_all_fn(ads, ads->config.bind_path,
1268 : LDAP_SCOPE_SUBTREE,
1269 : "(objectCategory=group)",
1270 0 : c->opt_long_list_entries ? longattrs :
1271 : shortattrs, usergrp_display,
1272 : disp_fields);
1273 :
1274 0 : ads_destroy(&ads);
1275 0 : return ADS_ERR_OK(rc) ? 0 : -1;
1276 : }
1277 0 : return net_run_function(c, argc, argv, "net ads group", func);
1278 : }
1279 :
1280 0 : static int net_ads_status(struct net_context *c, int argc, const char **argv)
1281 : {
1282 : ADS_STRUCT *ads;
1283 : ADS_STATUS rc;
1284 : LDAPMessage *res;
1285 :
1286 0 : if (c->display_usage) {
1287 0 : d_printf( "%s\n"
1288 : "net ads status\n"
1289 : " %s\n",
1290 : _("Usage:"),
1291 : _("Display machine account details"));
1292 0 : return 0;
1293 : }
1294 :
1295 0 : if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1296 0 : return -1;
1297 : }
1298 :
1299 0 : rc = ads_find_machine_acct(ads, &res, lp_netbios_name());
1300 0 : if (!ADS_ERR_OK(rc)) {
1301 0 : d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
1302 0 : ads_destroy(&ads);
1303 0 : return -1;
1304 : }
1305 :
1306 0 : if (ads_count_replies(ads, res) == 0) {
1307 0 : d_fprintf(stderr, _("No machine account for '%s' found\n"), lp_netbios_name());
1308 0 : ads_destroy(&ads);
1309 0 : return -1;
1310 : }
1311 :
1312 0 : ads_dump(ads, res);
1313 0 : ads_destroy(&ads);
1314 0 : return 0;
1315 : }
1316 :
1317 : /*******************************************************************
1318 : Leave an AD domain. Windows XP disables the machine account.
1319 : We'll try the same. The old code would do an LDAP delete.
1320 : That only worked using the machine creds because added the machine
1321 : with full control to the computer object's ACL.
1322 : *******************************************************************/
1323 :
1324 22 : static int net_ads_leave(struct net_context *c, int argc, const char **argv)
1325 : {
1326 : TALLOC_CTX *ctx;
1327 22 : struct libnet_UnjoinCtx *r = NULL;
1328 : WERROR werr;
1329 :
1330 22 : if (c->display_usage) {
1331 0 : d_printf( "%s\n"
1332 : "net ads leave [--keep-account]\n"
1333 : " %s\n",
1334 : _("Usage:"),
1335 : _("Leave an AD domain"));
1336 0 : return 0;
1337 : }
1338 :
1339 22 : if (!*lp_realm()) {
1340 0 : d_fprintf(stderr, _("No realm set, are we joined ?\n"));
1341 0 : return -1;
1342 : }
1343 :
1344 22 : if (!(ctx = talloc_init("net_ads_leave"))) {
1345 0 : d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1346 0 : return -1;
1347 : }
1348 :
1349 22 : if (!c->opt_kerberos) {
1350 20 : use_in_memory_ccache();
1351 : }
1352 :
1353 22 : if (!c->msg_ctx) {
1354 0 : d_fprintf(stderr, _("Could not initialise message context. "
1355 : "Try running as root\n"));
1356 0 : return -1;
1357 : }
1358 :
1359 22 : werr = libnet_init_UnjoinCtx(ctx, &r);
1360 22 : if (!W_ERROR_IS_OK(werr)) {
1361 0 : d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
1362 0 : return -1;
1363 : }
1364 :
1365 22 : r->in.debug = true;
1366 22 : r->in.use_kerberos = c->opt_kerberos;
1367 22 : r->in.dc_name = c->opt_host;
1368 22 : r->in.domain_name = lp_realm();
1369 22 : r->in.admin_account = c->opt_user_name;
1370 22 : r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1371 22 : r->in.modify_config = lp_config_backend_is_registry();
1372 :
1373 : /* Try to delete it, but if that fails, disable it. The
1374 : WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
1375 22 : r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1376 : WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
1377 22 : if (c->opt_keep_account) {
1378 2 : r->in.delete_machine_account = false;
1379 : } else {
1380 20 : r->in.delete_machine_account = true;
1381 : }
1382 :
1383 22 : r->in.msg_ctx = c->msg_ctx;
1384 :
1385 22 : werr = libnet_Unjoin(ctx, r);
1386 22 : if (!W_ERROR_IS_OK(werr)) {
1387 3 : d_printf(_("Failed to leave domain: %s\n"),
1388 3 : r->out.error_string ? r->out.error_string :
1389 0 : get_friendly_werror_msg(werr));
1390 2 : goto done;
1391 : }
1392 :
1393 20 : if (r->out.deleted_machine_account) {
1394 27 : d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1395 27 : r->in.machine_name, r->out.dns_domain_name);
1396 18 : goto done;
1397 : }
1398 :
1399 : /* We couldn't delete it - see if the disable succeeded. */
1400 2 : if (r->out.disabled_machine_account) {
1401 3 : d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1402 3 : r->in.machine_name, r->out.dns_domain_name);
1403 2 : werr = WERR_OK;
1404 2 : goto done;
1405 : }
1406 :
1407 : /* Based on what we requested, we shouldn't get here, but if
1408 : we did, it means the secrets were removed, and therefore
1409 : we have left the domain */
1410 0 : d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1411 0 : r->in.machine_name, r->out.dns_domain_name);
1412 :
1413 22 : done:
1414 22 : TALLOC_FREE(r);
1415 22 : TALLOC_FREE(ctx);
1416 :
1417 22 : if (W_ERROR_IS_OK(werr)) {
1418 20 : return 0;
1419 : }
1420 :
1421 2 : return -1;
1422 : }
1423 :
1424 18 : static NTSTATUS net_ads_join_ok(struct net_context *c)
1425 : {
1426 18 : ADS_STRUCT *ads = NULL;
1427 : ADS_STATUS status;
1428 : fstring dc_name;
1429 : struct sockaddr_storage dcip;
1430 :
1431 18 : if (!secrets_init()) {
1432 0 : DEBUG(1,("Failed to initialise secrets database\n"));
1433 0 : return NT_STATUS_ACCESS_DENIED;
1434 : }
1435 :
1436 18 : net_use_krb_machine_account(c);
1437 :
1438 18 : get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1439 :
1440 18 : status = ads_startup(c, true, &ads);
1441 18 : if (!ADS_ERR_OK(status)) {
1442 0 : return ads_ntstatus(status);
1443 : }
1444 :
1445 18 : ads_destroy(&ads);
1446 18 : return NT_STATUS_OK;
1447 : }
1448 :
1449 : /*
1450 : check that an existing join is OK
1451 : */
1452 18 : int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1453 : {
1454 : NTSTATUS status;
1455 18 : use_in_memory_ccache();
1456 :
1457 18 : if (c->display_usage) {
1458 0 : d_printf( "%s\n"
1459 : "net ads testjoin\n"
1460 : " %s\n",
1461 : _("Usage:"),
1462 : _("Test if the existing join is ok"));
1463 0 : return 0;
1464 : }
1465 :
1466 : /* Display success or failure */
1467 18 : status = net_ads_join_ok(c);
1468 18 : if (!NT_STATUS_IS_OK(status)) {
1469 0 : fprintf(stderr, _("Join to domain is not valid: %s\n"),
1470 : get_friendly_nt_error_msg(status));
1471 0 : return -1;
1472 : }
1473 :
1474 18 : printf(_("Join is OK\n"));
1475 18 : return 0;
1476 : }
1477 :
1478 : /*******************************************************************
1479 : Simple config checks before beginning the join
1480 : ********************************************************************/
1481 :
1482 36 : static WERROR check_ads_config( void )
1483 : {
1484 36 : if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1485 0 : d_printf(_("Host is not configured as a member server.\n"));
1486 0 : return WERR_INVALID_DOMAIN_ROLE;
1487 : }
1488 :
1489 36 : if (strlen(lp_netbios_name()) > 15) {
1490 0 : d_printf(_("Our netbios name can be at most 15 chars long, "
1491 : "\"%s\" is %u chars long\n"), lp_netbios_name(),
1492 0 : (unsigned int)strlen(lp_netbios_name()));
1493 0 : return WERR_INVALID_COMPUTERNAME;
1494 : }
1495 :
1496 36 : if ( lp_security() == SEC_ADS && !*lp_realm()) {
1497 0 : d_fprintf(stderr, _("realm must be set in in %s for ADS "
1498 : "join to succeed.\n"), get_dyn_CONFIGFILE());
1499 0 : return WERR_INVALID_PARAMETER;
1500 : }
1501 :
1502 36 : return WERR_OK;
1503 : }
1504 :
1505 : /*******************************************************************
1506 : Send a DNS update request
1507 : *******************************************************************/
1508 :
1509 : #if defined(HAVE_KRB5)
1510 : #include "../lib/addns/dns.h"
1511 :
1512 46 : static NTSTATUS net_update_dns_internal(struct net_context *c,
1513 : TALLOC_CTX *ctx, ADS_STRUCT *ads,
1514 : const char *machine_name,
1515 : const struct sockaddr_storage *addrs,
1516 : int num_addrs, bool remove_host)
1517 : {
1518 46 : struct dns_rr_ns *nameservers = NULL;
1519 46 : size_t ns_count = 0, i;
1520 46 : NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1521 : DNS_ERROR dns_err;
1522 : fstring dns_server;
1523 46 : const char *dnsdomain = NULL;
1524 46 : char *root_domain = NULL;
1525 :
1526 46 : if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1527 20 : d_printf(_("No DNS domain configured for %s. "
1528 : "Unable to perform DNS Update.\n"), machine_name);
1529 20 : status = NT_STATUS_INVALID_PARAMETER;
1530 20 : goto done;
1531 : }
1532 26 : dnsdomain++;
1533 :
1534 26 : status = ads_dns_lookup_ns(ctx,
1535 : dnsdomain,
1536 : &nameservers,
1537 : &ns_count);
1538 26 : if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1539 : /* Child domains often do not have NS records. Look
1540 : for the NS record for the forest root domain
1541 : (rootDomainNamingContext in therootDSE) */
1542 :
1543 2 : const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1544 2 : LDAPMessage *msg = NULL;
1545 : char *root_dn;
1546 : ADS_STATUS ads_status;
1547 :
1548 2 : if ( !ads->ldap.ld ) {
1549 2 : ads_status = ads_connect( ads );
1550 2 : if ( !ADS_ERR_OK(ads_status) ) {
1551 0 : DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1552 0 : goto done;
1553 : }
1554 : }
1555 :
1556 2 : ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1557 : "(objectclass=*)", rootname_attrs, &msg);
1558 2 : if (!ADS_ERR_OK(ads_status)) {
1559 0 : goto done;
1560 : }
1561 :
1562 2 : root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1563 2 : if ( !root_dn ) {
1564 0 : ads_msgfree( ads, msg );
1565 0 : goto done;
1566 : }
1567 :
1568 2 : root_domain = ads_build_domain( root_dn );
1569 :
1570 : /* cleanup */
1571 2 : ads_msgfree( ads, msg );
1572 :
1573 : /* try again for NS servers */
1574 :
1575 2 : status = ads_dns_lookup_ns(ctx,
1576 : root_domain,
1577 : &nameservers,
1578 : &ns_count);
1579 :
1580 2 : if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1581 0 : DEBUG(3,("net_update_dns_internal: Failed to find name server for the %s "
1582 : "realm\n", ads->config.realm));
1583 0 : if (ns_count == 0) {
1584 0 : status = NT_STATUS_UNSUCCESSFUL;
1585 : }
1586 0 : goto done;
1587 : }
1588 :
1589 2 : dnsdomain = root_domain;
1590 :
1591 : }
1592 :
1593 39 : for (i=0; i < ns_count; i++) {
1594 :
1595 26 : uint32_t flags = DNS_UPDATE_SIGNED |
1596 : DNS_UPDATE_UNSIGNED |
1597 : DNS_UPDATE_UNSIGNED_SUFFICIENT |
1598 : DNS_UPDATE_PROBE |
1599 : DNS_UPDATE_PROBE_SUFFICIENT;
1600 :
1601 26 : if (c->opt_force) {
1602 0 : flags &= ~DNS_UPDATE_PROBE_SUFFICIENT;
1603 0 : flags &= ~DNS_UPDATE_UNSIGNED_SUFFICIENT;
1604 : }
1605 :
1606 : /*
1607 : * Do not return after PROBE completion if this function
1608 : * is called for DNS removal.
1609 : */
1610 26 : if (remove_host) {
1611 4 : flags &= ~DNS_UPDATE_PROBE_SUFFICIENT;
1612 : }
1613 :
1614 26 : status = NT_STATUS_UNSUCCESSFUL;
1615 :
1616 : /* Now perform the dns update - we'll try non-secure and if we fail,
1617 : we'll follow it up with a secure update */
1618 :
1619 26 : fstrcpy( dns_server, nameservers[i].hostname );
1620 :
1621 26 : dns_err = DoDNSUpdate(dns_server,
1622 : dnsdomain,
1623 : machine_name,
1624 : addrs,
1625 : num_addrs,
1626 : flags,
1627 : remove_host);
1628 26 : if (ERR_DNS_IS_OK(dns_err)) {
1629 22 : status = NT_STATUS_OK;
1630 22 : goto done;
1631 : }
1632 :
1633 6 : if (ERR_DNS_EQUAL(dns_err, ERROR_DNS_INVALID_NAME_SERVER) ||
1634 6 : ERR_DNS_EQUAL(dns_err, ERROR_DNS_CONNECTION_FAILED) ||
1635 4 : ERR_DNS_EQUAL(dns_err, ERROR_DNS_SOCKET_ERROR)) {
1636 0 : DEBUG(1,("retrying DNS update with next nameserver after receiving %s\n",
1637 : dns_errstr(dns_err)));
1638 0 : continue;
1639 : }
1640 :
1641 4 : d_printf(_("DNS Update for %s failed: %s\n"),
1642 : machine_name, dns_errstr(dns_err));
1643 4 : status = NT_STATUS_UNSUCCESSFUL;
1644 4 : goto done;
1645 : }
1646 :
1647 0 : done:
1648 :
1649 46 : SAFE_FREE( root_domain );
1650 :
1651 46 : return status;
1652 : }
1653 :
1654 46 : static NTSTATUS net_update_dns_ext(struct net_context *c,
1655 : TALLOC_CTX *mem_ctx, ADS_STRUCT *ads,
1656 : const char *hostname,
1657 : struct sockaddr_storage *iplist,
1658 : int num_addrs, bool remove_host)
1659 : {
1660 46 : struct sockaddr_storage *iplist_alloc = NULL;
1661 : fstring machine_name;
1662 : NTSTATUS status;
1663 :
1664 46 : if (hostname) {
1665 12 : fstrcpy(machine_name, hostname);
1666 : } else {
1667 34 : name_to_fqdn( machine_name, lp_netbios_name() );
1668 : }
1669 46 : if (!strlower_m( machine_name )) {
1670 0 : return NT_STATUS_INVALID_PARAMETER;
1671 : }
1672 :
1673 : /*
1674 : * If remove_host is true, then remove all IP addresses associated with
1675 : * this hostname from the AD server.
1676 : */
1677 46 : if (!remove_host && (num_addrs == 0 || iplist == NULL)) {
1678 : /*
1679 : * Get our ip address
1680 : * (not the 127.0.0.x address but a real ip address)
1681 : */
1682 34 : num_addrs = get_my_ip_address(&iplist_alloc);
1683 34 : if ( num_addrs <= 0 ) {
1684 0 : DEBUG(4, ("net_update_dns_ext: Failed to find my "
1685 : "non-loopback IP addresses!\n"));
1686 0 : return NT_STATUS_INVALID_PARAMETER;
1687 : }
1688 34 : iplist = iplist_alloc;
1689 : }
1690 :
1691 46 : status = net_update_dns_internal(c, mem_ctx, ads, machine_name,
1692 : iplist, num_addrs, remove_host);
1693 :
1694 46 : SAFE_FREE(iplist_alloc);
1695 46 : return status;
1696 : }
1697 :
1698 34 : static NTSTATUS net_update_dns(struct net_context *c, TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, const char *hostname)
1699 : {
1700 : NTSTATUS status;
1701 :
1702 34 : status = net_update_dns_ext(c, mem_ctx, ads, hostname, NULL, 0, false);
1703 34 : return status;
1704 : }
1705 : #endif
1706 :
1707 :
1708 : /*******************************************************************
1709 : ********************************************************************/
1710 :
1711 0 : static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1712 : {
1713 0 : d_printf(_("net ads join [--no-dns-updates] [options]\n"
1714 : "Valid options:\n"));
1715 0 : d_printf(_(" dnshostname=FQDN Set the dnsHostName attribute during the join.\n"
1716 : " The default is in the form netbiosname.dnsdomain\n"));
1717 0 : d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1718 : " The default UPN is in the form host/netbiosname@REALM.\n"));
1719 0 : d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1720 : " The OU string read from top to bottom without RDNs\n"
1721 : " and delimited by a '/'.\n"
1722 : " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1723 : " NB: A backslash '\\' is used as escape at multiple\n"
1724 : " levels and may need to be doubled or even\n"
1725 : " quadrupled. It is not used as a separator.\n"));
1726 0 : d_printf(_(" machinepass=PASS Set the machine password to a specific value during\n"
1727 : " the join. The default password is random.\n"));
1728 0 : d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1729 0 : d_printf(_(" osVer=string Set the operatingSystemVersion attribute during join.\n"
1730 : " NB: osName and osVer must be specified together for\n"
1731 : " either to take effect. The operatingSystemService\n"
1732 : " attribute is then also set along with the two\n"
1733 : " other attributes.\n"));
1734 0 : d_printf(_(" osServicePack=string Set the operatingSystemServicePack attribute\n"
1735 : " during the join.\n"
1736 : " NB: If not specified then by default the samba\n"
1737 : " version string is used instead.\n"));
1738 0 : return -1;
1739 : }
1740 :
1741 :
1742 34 : static void _net_ads_join_dns_updates(struct net_context *c, TALLOC_CTX *ctx, struct libnet_JoinCtx *r)
1743 : {
1744 : #if defined(HAVE_KRB5)
1745 34 : ADS_STRUCT *ads_dns = NULL;
1746 : int ret;
1747 : NTSTATUS status;
1748 :
1749 : /*
1750 : * In a clustered environment, don't do dynamic dns updates:
1751 : * Registering the set of ip addresses that are assigned to
1752 : * the interfaces of the node that performs the join does usually
1753 : * not have the desired effect, since the local interfaces do not
1754 : * carry the complete set of the cluster's public IP addresses.
1755 : * And it can also contain internal addresses that should not
1756 : * be visible to the outside at all.
1757 : * In order to do dns updates in a clustererd setup, use
1758 : * net ads dns register.
1759 : */
1760 34 : if (lp_clustering()) {
1761 0 : d_fprintf(stderr, _("Not doing automatic DNS update in a "
1762 : "clustered setup.\n"));
1763 0 : return;
1764 : }
1765 :
1766 34 : if (!r->out.domain_is_ad) {
1767 0 : return;
1768 : }
1769 :
1770 : /*
1771 : * We enter this block with user creds.
1772 : * kinit with the machine password to do dns update.
1773 : */
1774 :
1775 34 : ads_dns = ads_init(lp_realm(), NULL, r->in.dc_name, ADS_SASL_PLAIN);
1776 :
1777 34 : if (ads_dns == NULL) {
1778 0 : d_fprintf(stderr, _("DNS update failed: out of memory!\n"));
1779 0 : goto done;
1780 : }
1781 :
1782 34 : use_in_memory_ccache();
1783 :
1784 34 : ret = asprintf(&ads_dns->auth.user_name, "%s$", lp_netbios_name());
1785 34 : if (ret == -1) {
1786 0 : d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1787 0 : goto done;
1788 : }
1789 :
1790 34 : ads_dns->auth.password = secrets_fetch_machine_password(
1791 : r->out.netbios_domain_name, NULL, NULL);
1792 34 : if (ads_dns->auth.password == NULL) {
1793 0 : d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1794 0 : goto done;
1795 : }
1796 :
1797 34 : ads_dns->auth.realm = SMB_STRDUP(r->out.dns_domain_name);
1798 34 : if (ads_dns->auth.realm == NULL) {
1799 0 : d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1800 0 : goto done;
1801 : }
1802 :
1803 34 : if (!strupper_m(ads_dns->auth.realm)) {
1804 0 : d_fprintf(stderr, _("strupper_m %s failed\n"), ads_dns->auth.realm);
1805 0 : goto done;
1806 : }
1807 :
1808 34 : ret = ads_kinit_password(ads_dns);
1809 34 : if (ret != 0) {
1810 0 : d_fprintf(stderr,
1811 0 : _("DNS update failed: kinit failed: %s\n"),
1812 : error_message(ret));
1813 0 : goto done;
1814 : }
1815 :
1816 34 : status = net_update_dns(c, ctx, ads_dns, NULL);
1817 34 : if (!NT_STATUS_IS_OK(status)) {
1818 22 : d_fprintf( stderr, _("DNS update failed: %s\n"),
1819 : nt_errstr(status));
1820 : }
1821 :
1822 29 : done:
1823 34 : ads_destroy(&ads_dns);
1824 : #endif
1825 :
1826 34 : return;
1827 : }
1828 :
1829 :
1830 36 : int net_ads_join(struct net_context *c, int argc, const char **argv)
1831 : {
1832 36 : TALLOC_CTX *ctx = NULL;
1833 36 : struct libnet_JoinCtx *r = NULL;
1834 36 : const char *domain = lp_realm();
1835 36 : WERROR werr = WERR_NERR_SETUPNOTJOINED;
1836 36 : bool createupn = false;
1837 36 : const char *dnshostname = NULL;
1838 36 : const char *machineupn = NULL;
1839 36 : const char *machine_password = NULL;
1840 36 : const char *create_in_ou = NULL;
1841 : int i;
1842 36 : const char *os_name = NULL;
1843 36 : const char *os_version = NULL;
1844 36 : const char *os_servicepack = NULL;
1845 36 : bool modify_config = lp_config_backend_is_registry();
1846 36 : enum libnetjoin_JoinDomNameType domain_name_type = JoinDomNameTypeDNS;
1847 :
1848 36 : if (c->display_usage)
1849 0 : return net_ads_join_usage(c, argc, argv);
1850 :
1851 36 : if (!modify_config) {
1852 :
1853 36 : werr = check_ads_config();
1854 36 : if (!W_ERROR_IS_OK(werr)) {
1855 0 : d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1856 0 : goto fail;
1857 : }
1858 : }
1859 :
1860 36 : if (!(ctx = talloc_init("net_ads_join"))) {
1861 0 : d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1862 0 : werr = WERR_NOT_ENOUGH_MEMORY;
1863 0 : goto fail;
1864 : }
1865 :
1866 36 : if (!c->opt_kerberos) {
1867 28 : use_in_memory_ccache();
1868 : }
1869 :
1870 36 : werr = libnet_init_JoinCtx(ctx, &r);
1871 36 : if (!W_ERROR_IS_OK(werr)) {
1872 0 : goto fail;
1873 : }
1874 :
1875 : /* process additional command line args */
1876 :
1877 42 : for ( i=0; i<argc; i++ ) {
1878 6 : if ( !strncasecmp_m(argv[i], "dnshostname", strlen("dnshostname")) ) {
1879 2 : dnshostname = get_string_param(argv[i]);
1880 : }
1881 4 : else if ( !strncasecmp_m(argv[i], "createupn", strlen("createupn")) ) {
1882 2 : createupn = true;
1883 2 : machineupn = get_string_param(argv[i]);
1884 : }
1885 2 : else if ( !strncasecmp_m(argv[i], "createcomputer", strlen("createcomputer")) ) {
1886 2 : if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1887 0 : d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1888 0 : werr = WERR_INVALID_PARAMETER;
1889 0 : goto fail;
1890 : }
1891 : }
1892 0 : else if ( !strncasecmp_m(argv[i], "osName", strlen("osName")) ) {
1893 0 : if ( (os_name = get_string_param(argv[i])) == NULL ) {
1894 0 : d_fprintf(stderr, _("Please supply a operating system name.\n"));
1895 0 : werr = WERR_INVALID_PARAMETER;
1896 0 : goto fail;
1897 : }
1898 : }
1899 0 : else if ( !strncasecmp_m(argv[i], "osVer", strlen("osVer")) ) {
1900 0 : if ( (os_version = get_string_param(argv[i])) == NULL ) {
1901 0 : d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1902 0 : werr = WERR_INVALID_PARAMETER;
1903 0 : goto fail;
1904 : }
1905 : }
1906 0 : else if ( !strncasecmp_m(argv[i], "osServicePack", strlen("osServicePack")) ) {
1907 0 : if ( (os_servicepack = get_string_param(argv[i])) == NULL ) {
1908 0 : d_fprintf(stderr, _("Please supply a valid servicepack identifier.\n"));
1909 0 : werr = WERR_INVALID_PARAMETER;
1910 0 : goto fail;
1911 : }
1912 : }
1913 0 : else if ( !strncasecmp_m(argv[i], "machinepass", strlen("machinepass")) ) {
1914 0 : if ( (machine_password = get_string_param(argv[i])) == NULL ) {
1915 0 : d_fprintf(stderr, _("Please supply a valid password to set as trust account password.\n"));
1916 0 : werr = WERR_INVALID_PARAMETER;
1917 0 : goto fail;
1918 : }
1919 : }
1920 : else {
1921 0 : domain = argv[i];
1922 0 : if (strchr(domain, '.') == NULL) {
1923 0 : domain_name_type = JoinDomNameTypeUnknown;
1924 : } else {
1925 0 : domain_name_type = JoinDomNameTypeDNS;
1926 : }
1927 : }
1928 : }
1929 :
1930 36 : if (!*domain) {
1931 0 : d_fprintf(stderr, _("Please supply a valid domain name\n"));
1932 0 : werr = WERR_INVALID_PARAMETER;
1933 0 : goto fail;
1934 : }
1935 :
1936 36 : if (!c->msg_ctx) {
1937 0 : d_fprintf(stderr, _("Could not initialise message context. "
1938 : "Try running as root\n"));
1939 0 : werr = WERR_ACCESS_DENIED;
1940 0 : goto fail;
1941 : }
1942 :
1943 : /* Do the domain join here */
1944 :
1945 36 : r->in.domain_name = domain;
1946 36 : r->in.domain_name_type = domain_name_type;
1947 36 : r->in.create_upn = createupn;
1948 36 : r->in.upn = machineupn;
1949 36 : r->in.dnshostname = dnshostname;
1950 36 : r->in.account_ou = create_in_ou;
1951 36 : r->in.os_name = os_name;
1952 36 : r->in.os_version = os_version;
1953 36 : r->in.os_servicepack = os_servicepack;
1954 36 : r->in.dc_name = c->opt_host;
1955 36 : r->in.admin_account = c->opt_user_name;
1956 36 : r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1957 36 : r->in.machine_password = machine_password;
1958 36 : r->in.debug = true;
1959 36 : r->in.use_kerberos = c->opt_kerberos;
1960 36 : r->in.modify_config = modify_config;
1961 36 : r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1962 : WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1963 : WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1964 36 : r->in.msg_ctx = c->msg_ctx;
1965 :
1966 36 : werr = libnet_Join(ctx, r);
1967 38 : if (W_ERROR_EQUAL(werr, WERR_NERR_DCNOTFOUND) &&
1968 2 : strequal(domain, lp_realm())) {
1969 2 : r->in.domain_name = lp_workgroup();
1970 2 : r->in.domain_name_type = JoinDomNameTypeNBT;
1971 2 : werr = libnet_Join(ctx, r);
1972 : }
1973 36 : if (!W_ERROR_IS_OK(werr)) {
1974 2 : goto fail;
1975 : }
1976 :
1977 : /* Check the short name of the domain */
1978 :
1979 34 : if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1980 0 : d_printf(_("The workgroup in %s does not match the short\n"
1981 : "domain name obtained from the server.\n"
1982 : "Using the name [%s] from the server.\n"
1983 : "You should set \"workgroup = %s\" in %s.\n"),
1984 0 : get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1985 0 : r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1986 : }
1987 :
1988 34 : d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1989 :
1990 34 : if (r->out.dns_domain_name) {
1991 34 : d_printf(_("Joined '%s' to dns domain '%s'\n"), r->in.machine_name,
1992 34 : r->out.dns_domain_name);
1993 : } else {
1994 0 : d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1995 0 : r->out.netbios_domain_name);
1996 : }
1997 :
1998 : /* print out informative error string in case there is one */
1999 34 : if (r->out.error_string != NULL) {
2000 0 : d_printf("%s\n", r->out.error_string);
2001 : }
2002 :
2003 : /*
2004 : * We try doing the dns update (if it was compiled in
2005 : * and if it was not disabled on the command line).
2006 : * If the dns update fails, we still consider the join
2007 : * operation as succeeded if we came this far.
2008 : */
2009 34 : if (!c->opt_no_dns_updates) {
2010 34 : _net_ads_join_dns_updates(c, ctx, r);
2011 : }
2012 :
2013 34 : TALLOC_FREE(r);
2014 34 : TALLOC_FREE( ctx );
2015 :
2016 34 : return 0;
2017 :
2018 2 : fail:
2019 : /* issue an overall failure message at the end. */
2020 3 : d_printf(_("Failed to join domain: %s\n"),
2021 3 : r && r->out.error_string ? r->out.error_string :
2022 0 : get_friendly_werror_msg(werr));
2023 2 : TALLOC_FREE( ctx );
2024 :
2025 2 : return -1;
2026 : }
2027 :
2028 : /*******************************************************************
2029 : ********************************************************************/
2030 :
2031 8 : static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
2032 : {
2033 : #if defined(HAVE_KRB5)
2034 : ADS_STRUCT *ads;
2035 : ADS_STATUS status;
2036 : NTSTATUS ntstatus;
2037 : TALLOC_CTX *ctx;
2038 8 : const char *hostname = NULL;
2039 8 : const char **addrs_list = NULL;
2040 8 : struct sockaddr_storage *addrs = NULL;
2041 8 : int num_addrs = 0;
2042 : int count;
2043 :
2044 : #ifdef DEVELOPER
2045 8 : talloc_enable_leak_report();
2046 : #endif
2047 :
2048 8 : if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
2049 0 : d_fprintf(stderr, _("Refusing DNS updates with automatic "
2050 : "detection of addresses in a clustered "
2051 : "setup.\n"));
2052 0 : c->display_usage = true;
2053 : }
2054 :
2055 8 : if (c->display_usage) {
2056 0 : d_printf( "%s\n"
2057 : "net ads dns register [hostname [IP [IP...]]]\n"
2058 : " %s\n",
2059 : _("Usage:"),
2060 : _("Register hostname with DNS\n"));
2061 0 : return -1;
2062 : }
2063 :
2064 8 : if (!(ctx = talloc_init("net_ads_dns"))) {
2065 0 : d_fprintf(stderr, _("Could not initialise talloc context\n"));
2066 0 : return -1;
2067 : }
2068 :
2069 8 : if (argc >= 1) {
2070 8 : hostname = argv[0];
2071 : }
2072 :
2073 8 : if (argc > 1) {
2074 8 : num_addrs = argc - 1;
2075 8 : addrs_list = &argv[1];
2076 0 : } else if (lp_clustering()) {
2077 0 : addrs_list = lp_cluster_addresses();
2078 0 : num_addrs = str_list_length(addrs_list);
2079 : }
2080 :
2081 8 : if (num_addrs > 0) {
2082 8 : addrs = talloc_zero_array(ctx, struct sockaddr_storage, num_addrs);
2083 8 : if (addrs == NULL) {
2084 0 : d_fprintf(stderr, _("Error allocating memory!\n"));
2085 0 : talloc_free(ctx);
2086 0 : return -1;
2087 : }
2088 : }
2089 :
2090 18 : for (count = 0; count < num_addrs; count++) {
2091 10 : if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
2092 0 : d_fprintf(stderr, "%s '%s'.\n",
2093 : _("Cannot interpret address"),
2094 0 : addrs_list[count]);
2095 0 : talloc_free(ctx);
2096 0 : return -1;
2097 : }
2098 : }
2099 :
2100 8 : status = ads_startup(c, true, &ads);
2101 8 : if ( !ADS_ERR_OK(status) ) {
2102 0 : DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
2103 0 : TALLOC_FREE(ctx);
2104 0 : return -1;
2105 : }
2106 :
2107 8 : ntstatus = net_update_dns_ext(c, ctx, ads, hostname, addrs, num_addrs, false);
2108 8 : if (!NT_STATUS_IS_OK(ntstatus)) {
2109 2 : d_fprintf( stderr, _("DNS update failed!\n") );
2110 2 : ads_destroy( &ads );
2111 2 : TALLOC_FREE( ctx );
2112 2 : return -1;
2113 : }
2114 :
2115 6 : d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
2116 :
2117 6 : ads_destroy(&ads);
2118 6 : TALLOC_FREE( ctx );
2119 :
2120 6 : return 0;
2121 : #else
2122 : d_fprintf(stderr,
2123 : _("DNS update support not enabled at compile time!\n"));
2124 : return -1;
2125 : #endif
2126 : }
2127 :
2128 4 : static int net_ads_dns_unregister(struct net_context *c,
2129 : int argc,
2130 : const char **argv)
2131 : {
2132 : #if defined(HAVE_KRB5)
2133 : ADS_STRUCT *ads;
2134 : ADS_STATUS status;
2135 : NTSTATUS ntstatus;
2136 : TALLOC_CTX *ctx;
2137 4 : const char *hostname = NULL;
2138 :
2139 : #ifdef DEVELOPER
2140 4 : talloc_enable_leak_report();
2141 : #endif
2142 :
2143 4 : if (argc != 1) {
2144 0 : c->display_usage = true;
2145 : }
2146 :
2147 4 : if (c->display_usage) {
2148 0 : d_printf( "%s\n"
2149 : "net ads dns unregister [hostname]\n"
2150 : " %s\n",
2151 : _("Usage:"),
2152 : _("Remove all IP Address entires for a given\n"
2153 : " hostname from the Active Directory server.\n"));
2154 0 : return -1;
2155 : }
2156 :
2157 4 : if (!(ctx = talloc_init("net_ads_dns"))) {
2158 0 : d_fprintf(stderr, _("Could not initialise talloc context\n"));
2159 0 : return -1;
2160 : }
2161 :
2162 : /* Get the hostname for un-registering */
2163 4 : hostname = argv[0];
2164 :
2165 4 : status = ads_startup(c, true, &ads);
2166 4 : if ( !ADS_ERR_OK(status) ) {
2167 0 : DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
2168 0 : TALLOC_FREE(ctx);
2169 0 : return -1;
2170 : }
2171 :
2172 4 : ntstatus = net_update_dns_ext(c, ctx, ads, hostname, NULL, 0, true);
2173 4 : if (!NT_STATUS_IS_OK(ntstatus)) {
2174 0 : d_fprintf( stderr, _("DNS update failed!\n") );
2175 0 : ads_destroy( &ads );
2176 0 : TALLOC_FREE( ctx );
2177 0 : return -1;
2178 : }
2179 :
2180 4 : d_fprintf( stderr, _("Successfully un-registered hostname from DNS\n"));
2181 :
2182 4 : ads_destroy(&ads);
2183 4 : TALLOC_FREE( ctx );
2184 :
2185 4 : return 0;
2186 : #else
2187 : d_fprintf(stderr,
2188 : _("DNS update support not enabled at compile time!\n"));
2189 : return -1;
2190 : #endif
2191 : }
2192 :
2193 :
2194 2 : static int net_ads_dns_async(struct net_context *c, int argc, const char **argv)
2195 : {
2196 2 : size_t num_names = 0;
2197 2 : char **hostnames = NULL;
2198 2 : size_t i = 0;
2199 2 : struct samba_sockaddr *addrs = NULL;
2200 : NTSTATUS status;
2201 :
2202 2 : if (argc != 1 || c->display_usage) {
2203 0 : d_printf( "%s\n"
2204 : " %s\n"
2205 : " %s\n",
2206 : _("Usage:"),
2207 : _("net ads dns async <name>\n"),
2208 : _(" Async look up hostname from the DNS server\n"
2209 : " hostname\tName to look up\n"));
2210 0 : return -1;
2211 : }
2212 :
2213 2 : status = ads_dns_lookup_a(talloc_tos(),
2214 : argv[0],
2215 : &num_names,
2216 : &hostnames,
2217 : &addrs);
2218 2 : if (!NT_STATUS_IS_OK(status)) {
2219 0 : d_printf("Looking up A record for %s got error %s\n",
2220 : argv[0],
2221 : nt_errstr(status));
2222 0 : return -1;
2223 : }
2224 2 : d_printf("Async A record lookup - got %u names for %s\n",
2225 : (unsigned int)num_names,
2226 : argv[0]);
2227 4 : for (i = 0; i < num_names; i++) {
2228 : char addr_buf[INET6_ADDRSTRLEN];
2229 2 : print_sockaddr(addr_buf,
2230 : sizeof(addr_buf),
2231 2 : &addrs[i].u.ss);
2232 2 : d_printf("hostname[%u] = %s, IPv4addr = %s\n",
2233 : (unsigned int)i,
2234 2 : hostnames[i],
2235 : addr_buf);
2236 : }
2237 :
2238 : #if defined(HAVE_IPV6)
2239 2 : status = ads_dns_lookup_aaaa(talloc_tos(),
2240 : argv[0],
2241 : &num_names,
2242 : &hostnames,
2243 : &addrs);
2244 2 : if (!NT_STATUS_IS_OK(status)) {
2245 0 : d_printf("Looking up AAAA record for %s got error %s\n",
2246 : argv[0],
2247 : nt_errstr(status));
2248 0 : return -1;
2249 : }
2250 2 : d_printf("Async AAAA record lookup - got %u names for %s\n",
2251 : (unsigned int)num_names,
2252 : argv[0]);
2253 4 : for (i = 0; i < num_names; i++) {
2254 : char addr_buf[INET6_ADDRSTRLEN];
2255 2 : print_sockaddr(addr_buf,
2256 : sizeof(addr_buf),
2257 2 : &addrs[i].u.ss);
2258 2 : d_printf("hostname[%u] = %s, IPv6addr = %s\n",
2259 : (unsigned int)i,
2260 2 : hostnames[i],
2261 : addr_buf);
2262 : }
2263 : #endif
2264 2 : return 0;
2265 : }
2266 :
2267 :
2268 14 : static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
2269 : {
2270 14 : struct functable func[] = {
2271 : {
2272 : "register",
2273 : net_ads_dns_register,
2274 : NET_TRANSPORT_ADS,
2275 : N_("Add host dns entry to AD"),
2276 : N_("net ads dns register\n"
2277 : " Add host dns entry to AD")
2278 : },
2279 : {
2280 : "unregister",
2281 : net_ads_dns_unregister,
2282 : NET_TRANSPORT_ADS,
2283 : N_("Remove host dns entry from AD"),
2284 : N_("net ads dns unregister\n"
2285 : " Remove host dns entry from AD")
2286 : },
2287 : {
2288 : "async",
2289 : net_ads_dns_async,
2290 : NET_TRANSPORT_ADS,
2291 : N_("Look up host"),
2292 : N_("net ads dns async\n"
2293 : " Look up host using async DNS")
2294 : },
2295 : {NULL, NULL, 0, NULL, NULL}
2296 : };
2297 :
2298 14 : return net_run_function(c, argc, argv, "net ads dns", func);
2299 : }
2300 :
2301 : /*******************************************************************
2302 : ********************************************************************/
2303 :
2304 0 : int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
2305 : {
2306 0 : d_printf(_(
2307 : "\nnet ads printer search <printer>"
2308 : "\n\tsearch for a printer in the directory\n"
2309 : "\nnet ads printer info <printer> <server>"
2310 : "\n\tlookup info in directory for printer on server"
2311 : "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
2312 : "\nnet ads printer publish <printername>"
2313 : "\n\tpublish printer in directory"
2314 : "\n\t(note: printer name is required)\n"
2315 : "\nnet ads printer remove <printername>"
2316 : "\n\tremove printer from directory"
2317 : "\n\t(note: printer name is required)\n"));
2318 0 : return -1;
2319 : }
2320 :
2321 : /*******************************************************************
2322 : ********************************************************************/
2323 :
2324 0 : static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
2325 : {
2326 : ADS_STRUCT *ads;
2327 : ADS_STATUS rc;
2328 0 : LDAPMessage *res = NULL;
2329 :
2330 0 : if (c->display_usage) {
2331 0 : d_printf( "%s\n"
2332 : "net ads printer search\n"
2333 : " %s\n",
2334 : _("Usage:"),
2335 : _("List printers in the AD"));
2336 0 : return 0;
2337 : }
2338 :
2339 0 : if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2340 0 : return -1;
2341 : }
2342 :
2343 0 : rc = ads_find_printers(ads, &res);
2344 :
2345 0 : if (!ADS_ERR_OK(rc)) {
2346 0 : d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
2347 0 : ads_msgfree(ads, res);
2348 0 : ads_destroy(&ads);
2349 0 : return -1;
2350 : }
2351 :
2352 0 : if (ads_count_replies(ads, res) == 0) {
2353 0 : d_fprintf(stderr, _("No results found\n"));
2354 0 : ads_msgfree(ads, res);
2355 0 : ads_destroy(&ads);
2356 0 : return -1;
2357 : }
2358 :
2359 0 : ads_dump(ads, res);
2360 0 : ads_msgfree(ads, res);
2361 0 : ads_destroy(&ads);
2362 0 : return 0;
2363 : }
2364 :
2365 0 : static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
2366 : {
2367 : ADS_STRUCT *ads;
2368 : ADS_STATUS rc;
2369 : const char *servername, *printername;
2370 0 : LDAPMessage *res = NULL;
2371 :
2372 0 : if (c->display_usage) {
2373 0 : d_printf("%s\n%s",
2374 : _("Usage:"),
2375 : _("net ads printer info [printername [servername]]\n"
2376 : " Display printer info from AD\n"
2377 : " printername\tPrinter name or wildcard\n"
2378 : " servername\tName of the print server\n"));
2379 0 : return 0;
2380 : }
2381 :
2382 0 : if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2383 0 : return -1;
2384 : }
2385 :
2386 0 : if (argc > 0) {
2387 0 : printername = argv[0];
2388 : } else {
2389 0 : printername = "*";
2390 : }
2391 :
2392 0 : if (argc > 1) {
2393 0 : servername = argv[1];
2394 : } else {
2395 0 : servername = lp_netbios_name();
2396 : }
2397 :
2398 0 : rc = ads_find_printer_on_server(ads, &res, printername, servername);
2399 :
2400 0 : if (!ADS_ERR_OK(rc)) {
2401 0 : d_fprintf(stderr, _("Server '%s' not found: %s\n"),
2402 : servername, ads_errstr(rc));
2403 0 : ads_msgfree(ads, res);
2404 0 : ads_destroy(&ads);
2405 0 : return -1;
2406 : }
2407 :
2408 0 : if (ads_count_replies(ads, res) == 0) {
2409 0 : d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
2410 0 : ads_msgfree(ads, res);
2411 0 : ads_destroy(&ads);
2412 0 : return -1;
2413 : }
2414 :
2415 0 : ads_dump(ads, res);
2416 0 : ads_msgfree(ads, res);
2417 0 : ads_destroy(&ads);
2418 :
2419 0 : return 0;
2420 : }
2421 :
2422 0 : static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
2423 : {
2424 : ADS_STRUCT *ads;
2425 : ADS_STATUS rc;
2426 : const char *servername, *printername;
2427 0 : struct cli_state *cli = NULL;
2428 0 : struct rpc_pipe_client *pipe_hnd = NULL;
2429 : struct sockaddr_storage server_ss;
2430 : NTSTATUS nt_status;
2431 0 : TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
2432 0 : ADS_MODLIST mods = ads_init_mods(mem_ctx);
2433 : char *prt_dn, *srv_dn, **srv_cn;
2434 0 : char *srv_cn_escaped = NULL, *printername_escaped = NULL;
2435 0 : LDAPMessage *res = NULL;
2436 : bool ok;
2437 :
2438 0 : if (argc < 1 || c->display_usage) {
2439 0 : d_printf("%s\n%s",
2440 : _("Usage:"),
2441 : _("net ads printer publish <printername> [servername]\n"
2442 : " Publish printer in AD\n"
2443 : " printername\tName of the printer\n"
2444 : " servername\tName of the print server\n"));
2445 0 : talloc_destroy(mem_ctx);
2446 0 : return -1;
2447 : }
2448 :
2449 0 : if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2450 0 : talloc_destroy(mem_ctx);
2451 0 : return -1;
2452 : }
2453 :
2454 0 : printername = argv[0];
2455 :
2456 0 : if (argc == 2) {
2457 0 : servername = argv[1];
2458 : } else {
2459 0 : servername = lp_netbios_name();
2460 : }
2461 :
2462 : /* Get printer data from SPOOLSS */
2463 :
2464 0 : ok = resolve_name(servername, &server_ss, 0x20, false);
2465 0 : if (!ok) {
2466 0 : d_fprintf(stderr, _("Could not find server %s\n"),
2467 : servername);
2468 0 : ads_destroy(&ads);
2469 0 : talloc_destroy(mem_ctx);
2470 0 : return -1;
2471 : }
2472 :
2473 0 : cli_credentials_set_kerberos_state(c->creds,
2474 : CRED_USE_KERBEROS_REQUIRED,
2475 : CRED_SPECIFIED);
2476 :
2477 0 : nt_status = cli_full_connection_creds(&cli, lp_netbios_name(), servername,
2478 : &server_ss, 0,
2479 : "IPC$", "IPC",
2480 : c->creds,
2481 : CLI_FULL_CONNECTION_IPC);
2482 :
2483 0 : if (NT_STATUS_IS_ERR(nt_status)) {
2484 0 : d_fprintf(stderr, _("Unable to open a connection to %s to "
2485 : "obtain data for %s\n"),
2486 : servername, printername);
2487 0 : ads_destroy(&ads);
2488 0 : talloc_destroy(mem_ctx);
2489 0 : return -1;
2490 : }
2491 :
2492 : /* Publish on AD server */
2493 :
2494 0 : ads_find_machine_acct(ads, &res, servername);
2495 :
2496 0 : if (ads_count_replies(ads, res) == 0) {
2497 0 : d_fprintf(stderr, _("Could not find machine account for server "
2498 : "%s\n"),
2499 : servername);
2500 0 : ads_destroy(&ads);
2501 0 : talloc_destroy(mem_ctx);
2502 0 : return -1;
2503 : }
2504 :
2505 0 : srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
2506 0 : srv_cn = ldap_explode_dn(srv_dn, 1);
2507 :
2508 0 : srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
2509 0 : printername_escaped = escape_rdn_val_string_alloc(printername);
2510 0 : if (!srv_cn_escaped || !printername_escaped) {
2511 0 : SAFE_FREE(srv_cn_escaped);
2512 0 : SAFE_FREE(printername_escaped);
2513 0 : d_fprintf(stderr, _("Internal error, out of memory!"));
2514 0 : ads_destroy(&ads);
2515 0 : talloc_destroy(mem_ctx);
2516 0 : return -1;
2517 : }
2518 :
2519 0 : if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
2520 0 : SAFE_FREE(srv_cn_escaped);
2521 0 : SAFE_FREE(printername_escaped);
2522 0 : d_fprintf(stderr, _("Internal error, out of memory!"));
2523 0 : ads_destroy(&ads);
2524 0 : talloc_destroy(mem_ctx);
2525 0 : return -1;
2526 : }
2527 :
2528 0 : SAFE_FREE(srv_cn_escaped);
2529 0 : SAFE_FREE(printername_escaped);
2530 :
2531 0 : nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss, &pipe_hnd);
2532 0 : if (!NT_STATUS_IS_OK(nt_status)) {
2533 0 : d_fprintf(stderr, _("Unable to open a connection to the spoolss pipe on %s\n"),
2534 : servername);
2535 0 : SAFE_FREE(prt_dn);
2536 0 : ads_destroy(&ads);
2537 0 : talloc_destroy(mem_ctx);
2538 0 : return -1;
2539 : }
2540 :
2541 0 : if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
2542 : printername))) {
2543 0 : SAFE_FREE(prt_dn);
2544 0 : ads_destroy(&ads);
2545 0 : talloc_destroy(mem_ctx);
2546 0 : return -1;
2547 : }
2548 :
2549 0 : rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
2550 0 : if (!ADS_ERR_OK(rc)) {
2551 0 : d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
2552 0 : SAFE_FREE(prt_dn);
2553 0 : ads_destroy(&ads);
2554 0 : talloc_destroy(mem_ctx);
2555 0 : return -1;
2556 : }
2557 :
2558 0 : d_printf("published printer\n");
2559 0 : SAFE_FREE(prt_dn);
2560 0 : ads_destroy(&ads);
2561 0 : talloc_destroy(mem_ctx);
2562 :
2563 0 : return 0;
2564 : }
2565 :
2566 0 : static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
2567 : {
2568 : ADS_STRUCT *ads;
2569 : ADS_STATUS rc;
2570 : const char *servername;
2571 : char *prt_dn;
2572 0 : LDAPMessage *res = NULL;
2573 :
2574 0 : if (argc < 1 || c->display_usage) {
2575 0 : d_printf("%s\n%s",
2576 : _("Usage:"),
2577 : _("net ads printer remove <printername> [servername]\n"
2578 : " Remove a printer from the AD\n"
2579 : " printername\tName of the printer\n"
2580 : " servername\tName of the print server\n"));
2581 0 : return -1;
2582 : }
2583 :
2584 0 : if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2585 0 : return -1;
2586 : }
2587 :
2588 0 : if (argc > 1) {
2589 0 : servername = argv[1];
2590 : } else {
2591 0 : servername = lp_netbios_name();
2592 : }
2593 :
2594 0 : rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
2595 :
2596 0 : if (!ADS_ERR_OK(rc)) {
2597 0 : d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
2598 0 : ads_msgfree(ads, res);
2599 0 : ads_destroy(&ads);
2600 0 : return -1;
2601 : }
2602 :
2603 0 : if (ads_count_replies(ads, res) == 0) {
2604 0 : d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
2605 0 : ads_msgfree(ads, res);
2606 0 : ads_destroy(&ads);
2607 0 : return -1;
2608 : }
2609 :
2610 0 : prt_dn = ads_get_dn(ads, talloc_tos(), res);
2611 0 : ads_msgfree(ads, res);
2612 0 : rc = ads_del_dn(ads, prt_dn);
2613 0 : TALLOC_FREE(prt_dn);
2614 :
2615 0 : if (!ADS_ERR_OK(rc)) {
2616 0 : d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
2617 0 : ads_destroy(&ads);
2618 0 : return -1;
2619 : }
2620 :
2621 0 : ads_destroy(&ads);
2622 0 : return 0;
2623 : }
2624 :
2625 0 : static int net_ads_printer(struct net_context *c, int argc, const char **argv)
2626 : {
2627 0 : struct functable func[] = {
2628 : {
2629 : "search",
2630 : net_ads_printer_search,
2631 : NET_TRANSPORT_ADS,
2632 : N_("Search for a printer"),
2633 : N_("net ads printer search\n"
2634 : " Search for a printer")
2635 : },
2636 : {
2637 : "info",
2638 : net_ads_printer_info,
2639 : NET_TRANSPORT_ADS,
2640 : N_("Display printer information"),
2641 : N_("net ads printer info\n"
2642 : " Display printer information")
2643 : },
2644 : {
2645 : "publish",
2646 : net_ads_printer_publish,
2647 : NET_TRANSPORT_ADS,
2648 : N_("Publish a printer"),
2649 : N_("net ads printer publish\n"
2650 : " Publish a printer")
2651 : },
2652 : {
2653 : "remove",
2654 : net_ads_printer_remove,
2655 : NET_TRANSPORT_ADS,
2656 : N_("Delete a printer"),
2657 : N_("net ads printer remove\n"
2658 : " Delete a printer")
2659 : },
2660 : {NULL, NULL, 0, NULL, NULL}
2661 : };
2662 :
2663 0 : return net_run_function(c, argc, argv, "net ads printer", func);
2664 : }
2665 :
2666 :
2667 2 : static int net_ads_password(struct net_context *c, int argc, const char **argv)
2668 : {
2669 : ADS_STRUCT *ads;
2670 2 : const char *auth_principal = cli_credentials_get_username(c->creds);
2671 2 : const char *auth_password = cli_credentials_get_password(c->creds);
2672 2 : const char *realm = NULL;
2673 2 : const char *new_password = NULL;
2674 : char *chr, *prompt;
2675 : const char *user;
2676 2 : char pwd[256] = {0};
2677 : ADS_STATUS ret;
2678 :
2679 2 : if (c->display_usage) {
2680 0 : d_printf("%s\n%s",
2681 : _("Usage:"),
2682 : _("net ads password <username>\n"
2683 : " Change password for user\n"
2684 : " username\tName of user to change password for\n"));
2685 0 : return 0;
2686 : }
2687 :
2688 2 : if (auth_principal == NULL || auth_password == NULL) {
2689 0 : d_fprintf(stderr, _("You must supply an administrator "
2690 : "username/password\n"));
2691 0 : return -1;
2692 : }
2693 :
2694 2 : if (argc < 1) {
2695 0 : d_fprintf(stderr, _("ERROR: You must say which username to "
2696 : "change password for\n"));
2697 0 : return -1;
2698 : }
2699 :
2700 2 : user = argv[0];
2701 2 : if (!strchr_m(user, '@')) {
2702 0 : if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
2703 0 : return -1;
2704 : }
2705 0 : user = chr;
2706 : }
2707 :
2708 2 : use_in_memory_ccache();
2709 2 : chr = strchr_m(auth_principal, '@');
2710 2 : if (chr) {
2711 2 : realm = ++chr;
2712 : } else {
2713 0 : realm = lp_realm();
2714 : }
2715 :
2716 : /* use the realm so we can eventually change passwords for users
2717 : in realms other than default */
2718 2 : ads = ads_init(realm, c->opt_workgroup, c->opt_host, ADS_SASL_PLAIN);
2719 2 : if (ads == NULL) {
2720 0 : return -1;
2721 : }
2722 :
2723 : /* we don't actually need a full connect, but it's the easy way to
2724 : fill in the KDC's addresss */
2725 2 : ads_connect(ads);
2726 :
2727 2 : if (!ads->config.realm) {
2728 0 : d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
2729 0 : ads_destroy(&ads);
2730 0 : return -1;
2731 : }
2732 :
2733 2 : if (argv[1]) {
2734 2 : new_password = (const char *)argv[1];
2735 : } else {
2736 : int rc;
2737 :
2738 0 : if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
2739 0 : return -1;
2740 : }
2741 0 : rc = samba_getpass(prompt, pwd, sizeof(pwd), false, true);
2742 0 : if (rc < 0) {
2743 0 : return -1;
2744 : }
2745 0 : new_password = pwd;
2746 0 : free(prompt);
2747 : }
2748 :
2749 2 : ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2750 2 : auth_password, user, new_password, ads->auth.time_offset);
2751 2 : memset(pwd, '\0', sizeof(pwd));
2752 2 : if (!ADS_ERR_OK(ret)) {
2753 0 : d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2754 0 : ads_destroy(&ads);
2755 0 : return -1;
2756 : }
2757 :
2758 2 : d_printf(_("Password change for %s completed.\n"), user);
2759 2 : ads_destroy(&ads);
2760 :
2761 2 : return 0;
2762 : }
2763 :
2764 4 : int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2765 : {
2766 : ADS_STRUCT *ads;
2767 : char *host_principal;
2768 : fstring my_name;
2769 : ADS_STATUS ret;
2770 :
2771 4 : if (c->display_usage) {
2772 0 : d_printf( "%s\n"
2773 : "net ads changetrustpw\n"
2774 : " %s\n",
2775 : _("Usage:"),
2776 : _("Change the machine account's trust password"));
2777 0 : return 0;
2778 : }
2779 :
2780 4 : if (!secrets_init()) {
2781 0 : DEBUG(1,("Failed to initialise secrets database\n"));
2782 0 : return -1;
2783 : }
2784 :
2785 4 : net_use_krb_machine_account(c);
2786 :
2787 4 : use_in_memory_ccache();
2788 :
2789 4 : if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2790 0 : return -1;
2791 : }
2792 :
2793 4 : fstrcpy(my_name, lp_netbios_name());
2794 4 : if (!strlower_m(my_name)) {
2795 0 : ads_destroy(&ads);
2796 0 : return -1;
2797 : }
2798 :
2799 4 : if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2800 0 : ads_destroy(&ads);
2801 0 : return -1;
2802 : }
2803 4 : d_printf(_("Changing password for principal: %s\n"), host_principal);
2804 :
2805 4 : ret = ads_change_trust_account_password(ads, host_principal);
2806 :
2807 4 : if (!ADS_ERR_OK(ret)) {
2808 0 : d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2809 0 : ads_destroy(&ads);
2810 0 : SAFE_FREE(host_principal);
2811 0 : return -1;
2812 : }
2813 :
2814 4 : d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2815 :
2816 4 : if (USE_SYSTEM_KEYTAB) {
2817 0 : d_printf(_("Attempting to update system keytab with new password.\n"));
2818 0 : if (ads_keytab_create_default(ads)) {
2819 0 : d_printf(_("Failed to update system keytab.\n"));
2820 : }
2821 : }
2822 :
2823 4 : ads_destroy(&ads);
2824 4 : SAFE_FREE(host_principal);
2825 :
2826 4 : return 0;
2827 : }
2828 :
2829 : /*
2830 : help for net ads search
2831 : */
2832 0 : static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2833 : {
2834 0 : d_printf(_(
2835 : "\nnet ads search <expression> <attributes...>\n"
2836 : "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2837 : "The expression is a standard LDAP search expression, and the\n"
2838 : "attributes are a list of LDAP fields to show in the results.\n\n"
2839 : "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2840 : ));
2841 0 : net_common_flags_usage(c, argc, argv);
2842 0 : return -1;
2843 : }
2844 :
2845 :
2846 : /*
2847 : general ADS search function. Useful in diagnosing problems in ADS
2848 : */
2849 20 : static int net_ads_search(struct net_context *c, int argc, const char **argv)
2850 : {
2851 : ADS_STRUCT *ads;
2852 : ADS_STATUS rc;
2853 : const char *ldap_exp;
2854 : const char **attrs;
2855 20 : LDAPMessage *res = NULL;
2856 :
2857 20 : if (argc < 1 || c->display_usage) {
2858 0 : return net_ads_search_usage(c, argc, argv);
2859 : }
2860 :
2861 20 : if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2862 0 : return -1;
2863 : }
2864 :
2865 20 : ldap_exp = argv[0];
2866 20 : attrs = (argv + 1);
2867 :
2868 20 : rc = ads_do_search_retry(ads, ads->config.bind_path,
2869 : LDAP_SCOPE_SUBTREE,
2870 : ldap_exp, attrs, &res);
2871 20 : if (!ADS_ERR_OK(rc)) {
2872 0 : d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2873 0 : ads_destroy(&ads);
2874 0 : return -1;
2875 : }
2876 :
2877 20 : d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2878 :
2879 : /* dump the results */
2880 20 : ads_dump(ads, res);
2881 :
2882 20 : ads_msgfree(ads, res);
2883 20 : ads_destroy(&ads);
2884 :
2885 20 : return 0;
2886 : }
2887 :
2888 :
2889 : /*
2890 : help for net ads search
2891 : */
2892 0 : static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2893 : {
2894 0 : d_printf(_(
2895 : "\nnet ads dn <dn> <attributes...>\n"
2896 : "\nperform a raw LDAP search on a ADS server and dump the results\n"
2897 : "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2898 : "to show in the results\n\n"
2899 : "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2900 : "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2901 : ));
2902 0 : net_common_flags_usage(c, argc, argv);
2903 0 : return -1;
2904 : }
2905 :
2906 :
2907 : /*
2908 : general ADS search function. Useful in diagnosing problems in ADS
2909 : */
2910 0 : static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2911 : {
2912 : ADS_STRUCT *ads;
2913 : ADS_STATUS rc;
2914 : const char *dn;
2915 : const char **attrs;
2916 0 : LDAPMessage *res = NULL;
2917 :
2918 0 : if (argc < 1 || c->display_usage) {
2919 0 : return net_ads_dn_usage(c, argc, argv);
2920 : }
2921 :
2922 0 : if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2923 0 : return -1;
2924 : }
2925 :
2926 0 : dn = argv[0];
2927 0 : attrs = (argv + 1);
2928 :
2929 0 : rc = ads_do_search_all(ads, dn,
2930 : LDAP_SCOPE_BASE,
2931 : "(objectclass=*)", attrs, &res);
2932 0 : if (!ADS_ERR_OK(rc)) {
2933 0 : d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2934 0 : ads_destroy(&ads);
2935 0 : return -1;
2936 : }
2937 :
2938 0 : d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2939 :
2940 : /* dump the results */
2941 0 : ads_dump(ads, res);
2942 :
2943 0 : ads_msgfree(ads, res);
2944 0 : ads_destroy(&ads);
2945 :
2946 0 : return 0;
2947 : }
2948 :
2949 : /*
2950 : help for net ads sid search
2951 : */
2952 0 : static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2953 : {
2954 0 : d_printf(_(
2955 : "\nnet ads sid <sid> <attributes...>\n"
2956 : "\nperform a raw LDAP search on a ADS server and dump the results\n"
2957 : "The SID is in string format, and the attributes are a list of LDAP fields \n"
2958 : "to show in the results\n\n"
2959 : "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2960 : ));
2961 0 : net_common_flags_usage(c, argc, argv);
2962 0 : return -1;
2963 : }
2964 :
2965 :
2966 : /*
2967 : general ADS search function. Useful in diagnosing problems in ADS
2968 : */
2969 0 : static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2970 : {
2971 : ADS_STRUCT *ads;
2972 : ADS_STATUS rc;
2973 : const char *sid_string;
2974 : const char **attrs;
2975 0 : LDAPMessage *res = NULL;
2976 : struct dom_sid sid;
2977 :
2978 0 : if (argc < 1 || c->display_usage) {
2979 0 : return net_ads_sid_usage(c, argc, argv);
2980 : }
2981 :
2982 0 : if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2983 0 : return -1;
2984 : }
2985 :
2986 0 : sid_string = argv[0];
2987 0 : attrs = (argv + 1);
2988 :
2989 0 : if (!string_to_sid(&sid, sid_string)) {
2990 0 : d_fprintf(stderr, _("could not convert sid\n"));
2991 0 : ads_destroy(&ads);
2992 0 : return -1;
2993 : }
2994 :
2995 0 : rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2996 0 : if (!ADS_ERR_OK(rc)) {
2997 0 : d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2998 0 : ads_destroy(&ads);
2999 0 : return -1;
3000 : }
3001 :
3002 0 : d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
3003 :
3004 : /* dump the results */
3005 0 : ads_dump(ads, res);
3006 :
3007 0 : ads_msgfree(ads, res);
3008 0 : ads_destroy(&ads);
3009 :
3010 0 : return 0;
3011 : }
3012 :
3013 0 : static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
3014 : {
3015 : int ret;
3016 : ADS_STRUCT *ads;
3017 :
3018 0 : if (c->display_usage) {
3019 0 : d_printf( "%s\n"
3020 : "net ads keytab flush\n"
3021 : " %s\n",
3022 : _("Usage:"),
3023 : _("Delete the whole keytab"));
3024 0 : return 0;
3025 : }
3026 :
3027 0 : if (!c->opt_user_specified && c->opt_password == NULL) {
3028 0 : net_use_krb_machine_account(c);
3029 : }
3030 :
3031 0 : if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3032 0 : return -1;
3033 : }
3034 0 : ret = ads_keytab_flush(ads);
3035 0 : ads_destroy(&ads);
3036 0 : return ret;
3037 : }
3038 :
3039 16 : static int net_ads_keytab_add(struct net_context *c,
3040 : int argc,
3041 : const char **argv,
3042 : bool update_ads)
3043 : {
3044 : int i;
3045 16 : int ret = 0;
3046 : ADS_STRUCT *ads;
3047 :
3048 16 : if (c->display_usage) {
3049 0 : d_printf("%s\n%s",
3050 : _("Usage:"),
3051 : _("net ads keytab add <principal> [principal ...]\n"
3052 : " Add principals to local keytab\n"
3053 : " principal\tKerberos principal to add to "
3054 : "keytab\n"));
3055 0 : return 0;
3056 : }
3057 :
3058 16 : d_printf(_("Processing principals to add...\n"));
3059 :
3060 16 : if (!c->opt_user_specified && c->opt_password == NULL) {
3061 0 : net_use_krb_machine_account(c);
3062 : }
3063 :
3064 16 : if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3065 0 : return -1;
3066 : }
3067 32 : for (i = 0; i < argc; i++) {
3068 16 : ret |= ads_keytab_add_entry(ads, argv[i], update_ads);
3069 : }
3070 16 : ads_destroy(&ads);
3071 16 : return ret;
3072 : }
3073 :
3074 14 : static int net_ads_keytab_add_default(struct net_context *c,
3075 : int argc,
3076 : const char **argv)
3077 : {
3078 14 : return net_ads_keytab_add(c, argc, argv, false);
3079 : }
3080 :
3081 2 : static int net_ads_keytab_add_update_ads(struct net_context *c,
3082 : int argc,
3083 : const char **argv)
3084 : {
3085 2 : return net_ads_keytab_add(c, argc, argv, true);
3086 : }
3087 :
3088 8 : static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
3089 : {
3090 : ADS_STRUCT *ads;
3091 : int ret;
3092 :
3093 8 : if (c->display_usage) {
3094 0 : d_printf( "%s\n"
3095 : "net ads keytab create\n"
3096 : " %s\n",
3097 : _("Usage:"),
3098 : _("Create new default keytab"));
3099 0 : return 0;
3100 : }
3101 :
3102 8 : if (!c->opt_user_specified && c->opt_password == NULL) {
3103 6 : net_use_krb_machine_account(c);
3104 : }
3105 :
3106 8 : if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3107 0 : return -1;
3108 : }
3109 8 : ret = ads_keytab_create_default(ads);
3110 8 : ads_destroy(&ads);
3111 8 : return ret;
3112 : }
3113 :
3114 30 : static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
3115 : {
3116 30 : const char *keytab = NULL;
3117 :
3118 30 : if (c->display_usage) {
3119 0 : d_printf("%s\n%s",
3120 : _("Usage:"),
3121 : _("net ads keytab list [keytab]\n"
3122 : " List a local keytab\n"
3123 : " keytab\tKeytab to list\n"));
3124 0 : return 0;
3125 : }
3126 :
3127 30 : if (argc >= 1) {
3128 2 : keytab = argv[0];
3129 : }
3130 :
3131 30 : return ads_keytab_list(keytab);
3132 : }
3133 :
3134 :
3135 54 : int net_ads_keytab(struct net_context *c, int argc, const char **argv)
3136 : {
3137 54 : struct functable func[] = {
3138 : {
3139 : "add",
3140 : net_ads_keytab_add_default,
3141 : NET_TRANSPORT_ADS,
3142 : N_("Add a service principal"),
3143 : N_("net ads keytab add\n"
3144 : " Add a service principal, updates keytab file only.")
3145 : },
3146 : {
3147 : "add_update_ads",
3148 : net_ads_keytab_add_update_ads,
3149 : NET_TRANSPORT_ADS,
3150 : N_("Add a service principal"),
3151 : N_("net ads keytab add_update_ads\n"
3152 : " Add a service principal, depending on the param passed may update ADS computer object in addition to the keytab file.")
3153 : },
3154 : {
3155 : "create",
3156 : net_ads_keytab_create,
3157 : NET_TRANSPORT_ADS,
3158 : N_("Create a fresh keytab"),
3159 : N_("net ads keytab create\n"
3160 : " Create a fresh keytab or update existing one.")
3161 : },
3162 : {
3163 : "flush",
3164 : net_ads_keytab_flush,
3165 : NET_TRANSPORT_ADS,
3166 : N_("Remove all keytab entries"),
3167 : N_("net ads keytab flush\n"
3168 : " Remove all keytab entries")
3169 : },
3170 : {
3171 : "list",
3172 : net_ads_keytab_list,
3173 : NET_TRANSPORT_ADS,
3174 : N_("List a keytab"),
3175 : N_("net ads keytab list\n"
3176 : " List a keytab")
3177 : },
3178 : {NULL, NULL, 0, NULL, NULL}
3179 : };
3180 :
3181 54 : if (!USE_KERBEROS_KEYTAB) {
3182 2 : d_printf(_("\nWarning: \"kerberos method\" must be set to a "
3183 : "keytab method to use keytab functions.\n"));
3184 : }
3185 :
3186 54 : return net_run_function(c, argc, argv, "net ads keytab", func);
3187 : }
3188 :
3189 0 : static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
3190 : {
3191 0 : int ret = -1;
3192 :
3193 0 : if (c->display_usage) {
3194 0 : d_printf( "%s\n"
3195 : "net ads kerberos renew\n"
3196 : " %s\n",
3197 : _("Usage:"),
3198 : _("Renew TGT from existing credential cache"));
3199 0 : return 0;
3200 : }
3201 :
3202 0 : ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
3203 0 : if (ret) {
3204 0 : d_printf(_("failed to renew kerberos ticket: %s\n"),
3205 : error_message(ret));
3206 : }
3207 0 : return ret;
3208 : }
3209 :
3210 0 : static int net_ads_kerberos_pac_common(struct net_context *c, int argc, const char **argv,
3211 : struct PAC_DATA_CTR **pac_data_ctr)
3212 : {
3213 : NTSTATUS status;
3214 0 : int ret = -1;
3215 0 : const char *impersonate_princ_s = NULL;
3216 0 : const char *local_service = NULL;
3217 : int i;
3218 :
3219 0 : for (i=0; i<argc; i++) {
3220 0 : if (strnequal(argv[i], "impersonate", strlen("impersonate"))) {
3221 0 : impersonate_princ_s = get_string_param(argv[i]);
3222 0 : if (impersonate_princ_s == NULL) {
3223 0 : return -1;
3224 : }
3225 : }
3226 0 : if (strnequal(argv[i], "local_service", strlen("local_service"))) {
3227 0 : local_service = get_string_param(argv[i]);
3228 0 : if (local_service == NULL) {
3229 0 : return -1;
3230 : }
3231 : }
3232 : }
3233 :
3234 0 : if (local_service == NULL) {
3235 0 : local_service = talloc_asprintf(c, "%s$@%s",
3236 : lp_netbios_name(), lp_realm());
3237 0 : if (local_service == NULL) {
3238 0 : goto out;
3239 : }
3240 : }
3241 :
3242 0 : c->opt_password = net_prompt_pass(c, c->opt_user_name);
3243 :
3244 0 : status = kerberos_return_pac(c,
3245 : c->opt_user_name,
3246 : c->opt_password,
3247 : 0,
3248 : NULL,
3249 : NULL,
3250 : NULL,
3251 : true,
3252 : true,
3253 : 2592000, /* one month */
3254 : impersonate_princ_s,
3255 : local_service,
3256 : pac_data_ctr);
3257 0 : if (!NT_STATUS_IS_OK(status)) {
3258 0 : d_printf(_("failed to query kerberos PAC: %s\n"),
3259 : nt_errstr(status));
3260 0 : goto out;
3261 : }
3262 :
3263 0 : ret = 0;
3264 0 : out:
3265 0 : return ret;
3266 : }
3267 :
3268 0 : static int net_ads_kerberos_pac_dump(struct net_context *c, int argc, const char **argv)
3269 : {
3270 0 : struct PAC_DATA_CTR *pac_data_ctr = NULL;
3271 : int i, num_buffers;
3272 0 : int ret = -1;
3273 0 : enum PAC_TYPE type = 0;
3274 :
3275 0 : if (c->display_usage) {
3276 0 : d_printf( "%s\n"
3277 : "net ads kerberos pac dump [impersonate=string] [local_service=string] [pac_buffer_type=int]\n"
3278 : " %s\n",
3279 : _("Usage:"),
3280 : _("Dump the Kerberos PAC"));
3281 0 : return -1;
3282 : }
3283 :
3284 0 : for (i=0; i<argc; i++) {
3285 0 : if (strnequal(argv[i], "pac_buffer_type", strlen("pac_buffer_type"))) {
3286 0 : type = get_int_param(argv[i]);
3287 : }
3288 : }
3289 :
3290 0 : ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3291 0 : if (ret) {
3292 0 : return ret;
3293 : }
3294 :
3295 0 : if (type == 0) {
3296 :
3297 0 : char *s = NULL;
3298 :
3299 0 : s = NDR_PRINT_STRUCT_STRING(c, PAC_DATA,
3300 : pac_data_ctr->pac_data);
3301 0 : if (s != NULL) {
3302 0 : d_printf(_("The Pac: %s\n"), s);
3303 0 : talloc_free(s);
3304 : }
3305 :
3306 0 : return 0;
3307 : }
3308 :
3309 0 : num_buffers = pac_data_ctr->pac_data->num_buffers;
3310 :
3311 0 : for (i=0; i<num_buffers; i++) {
3312 :
3313 0 : char *s = NULL;
3314 :
3315 0 : if (pac_data_ctr->pac_data->buffers[i].type != type) {
3316 0 : continue;
3317 : }
3318 :
3319 0 : s = NDR_PRINT_UNION_STRING(c, PAC_INFO, type,
3320 : pac_data_ctr->pac_data->buffers[i].info);
3321 0 : if (s != NULL) {
3322 0 : d_printf(_("The Pac: %s\n"), s);
3323 0 : talloc_free(s);
3324 : }
3325 0 : break;
3326 : }
3327 :
3328 0 : return 0;
3329 : }
3330 :
3331 0 : static int net_ads_kerberos_pac_save(struct net_context *c, int argc, const char **argv)
3332 : {
3333 0 : struct PAC_DATA_CTR *pac_data_ctr = NULL;
3334 0 : char *filename = NULL;
3335 0 : int ret = -1;
3336 : int i;
3337 :
3338 0 : if (c->display_usage) {
3339 0 : d_printf( "%s\n"
3340 : "net ads kerberos pac save [impersonate=string] [local_service=string] [filename=string]\n"
3341 : " %s\n",
3342 : _("Usage:"),
3343 : _("Save the Kerberos PAC"));
3344 0 : return -1;
3345 : }
3346 :
3347 0 : for (i=0; i<argc; i++) {
3348 0 : if (strnequal(argv[i], "filename", strlen("filename"))) {
3349 0 : filename = get_string_param(argv[i]);
3350 0 : if (filename == NULL) {
3351 0 : return -1;
3352 : }
3353 : }
3354 : }
3355 :
3356 0 : ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3357 0 : if (ret) {
3358 0 : return ret;
3359 : }
3360 :
3361 0 : if (filename == NULL) {
3362 0 : d_printf(_("please define \"filename=<filename>\" to save the PAC\n"));
3363 0 : return -1;
3364 : }
3365 :
3366 : /* save the raw format */
3367 0 : if (!file_save(filename, pac_data_ctr->pac_blob.data, pac_data_ctr->pac_blob.length)) {
3368 0 : d_printf(_("failed to save PAC in %s\n"), filename);
3369 0 : return -1;
3370 : }
3371 :
3372 0 : return 0;
3373 : }
3374 :
3375 0 : static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
3376 : {
3377 0 : struct functable func[] = {
3378 : {
3379 : "dump",
3380 : net_ads_kerberos_pac_dump,
3381 : NET_TRANSPORT_ADS,
3382 : N_("Dump Kerberos PAC"),
3383 : N_("net ads kerberos pac dump\n"
3384 : " Dump a Kerberos PAC to stdout")
3385 : },
3386 : {
3387 : "save",
3388 : net_ads_kerberos_pac_save,
3389 : NET_TRANSPORT_ADS,
3390 : N_("Save Kerberos PAC"),
3391 : N_("net ads kerberos pac save\n"
3392 : " Save a Kerberos PAC in a file")
3393 : },
3394 :
3395 : {NULL, NULL, 0, NULL, NULL}
3396 : };
3397 :
3398 0 : return net_run_function(c, argc, argv, "net ads kerberos pac", func);
3399 : }
3400 :
3401 0 : static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
3402 : {
3403 0 : TALLOC_CTX *mem_ctx = NULL;
3404 0 : int ret = -1;
3405 : NTSTATUS status;
3406 :
3407 0 : if (c->display_usage) {
3408 0 : d_printf( "%s\n"
3409 : "net ads kerberos kinit\n"
3410 : " %s\n",
3411 : _("Usage:"),
3412 : _("Get Ticket Granting Ticket (TGT) for the user"));
3413 0 : return 0;
3414 : }
3415 :
3416 0 : mem_ctx = talloc_init("net_ads_kerberos_kinit");
3417 0 : if (!mem_ctx) {
3418 0 : goto out;
3419 : }
3420 :
3421 0 : c->opt_password = net_prompt_pass(c, c->opt_user_name);
3422 :
3423 0 : ret = kerberos_kinit_password_ext(c->opt_user_name,
3424 : c->opt_password,
3425 : 0,
3426 : NULL,
3427 : NULL,
3428 : NULL,
3429 : true,
3430 : true,
3431 : 2592000, /* one month */
3432 : NULL,
3433 : NULL,
3434 : NULL,
3435 : &status);
3436 0 : if (ret) {
3437 0 : d_printf(_("failed to kinit password: %s\n"),
3438 : nt_errstr(status));
3439 : }
3440 0 : out:
3441 0 : return ret;
3442 : }
3443 :
3444 0 : int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3445 : {
3446 0 : struct functable func[] = {
3447 : {
3448 : "kinit",
3449 : net_ads_kerberos_kinit,
3450 : NET_TRANSPORT_ADS,
3451 : N_("Retrieve Ticket Granting Ticket (TGT)"),
3452 : N_("net ads kerberos kinit\n"
3453 : " Receive Ticket Granting Ticket (TGT)")
3454 : },
3455 : {
3456 : "renew",
3457 : net_ads_kerberos_renew,
3458 : NET_TRANSPORT_ADS,
3459 : N_("Renew Ticket Granting Ticket from credential cache"),
3460 : N_("net ads kerberos renew\n"
3461 : " Renew Ticket Granting Ticket (TGT) from "
3462 : "credential cache")
3463 : },
3464 : {
3465 : "pac",
3466 : net_ads_kerberos_pac,
3467 : NET_TRANSPORT_ADS,
3468 : N_("Dump Kerberos PAC"),
3469 : N_("net ads kerberos pac\n"
3470 : " Dump Kerberos PAC")
3471 : },
3472 : {NULL, NULL, 0, NULL, NULL}
3473 : };
3474 :
3475 0 : return net_run_function(c, argc, argv, "net ads kerberos", func);
3476 : }
3477 :
3478 12 : static int net_ads_setspn_list(struct net_context *c, int argc, const char **argv)
3479 : {
3480 12 : int ret = 0;
3481 12 : bool ok = false;
3482 12 : ADS_STRUCT *ads = NULL;
3483 12 : if (c->display_usage) {
3484 0 : d_printf("%s\n%s",
3485 : _("Usage:"),
3486 : _("net ads setspn list <machinename>\n"));
3487 0 : ret = 0;
3488 0 : goto done;
3489 : }
3490 12 : if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3491 0 : ret = -1;
3492 0 : goto done;
3493 : }
3494 12 : if (argc) {
3495 2 : ok = ads_setspn_list(ads, argv[0]);
3496 : } else {
3497 10 : ok = ads_setspn_list(ads, lp_netbios_name());
3498 : }
3499 12 : if (!ok) {
3500 0 : ret = -1;
3501 : }
3502 18 : done:
3503 12 : if (ads) {
3504 12 : ads_destroy(&ads);
3505 : }
3506 12 : return ret;
3507 : }
3508 :
3509 6 : static int net_ads_setspn_add(struct net_context *c, int argc, const char **argv)
3510 : {
3511 6 : int ret = 0;
3512 6 : bool ok = false;
3513 6 : ADS_STRUCT *ads = NULL;
3514 6 : if (c->display_usage || argc < 1) {
3515 0 : d_printf("%s\n%s",
3516 : _("Usage:"),
3517 : _("net ads setspn add <machinename> SPN\n"));
3518 0 : ret = 0;
3519 0 : goto done;
3520 : }
3521 6 : if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3522 0 : ret = -1;
3523 0 : goto done;
3524 : }
3525 6 : if (argc > 1) {
3526 0 : ok = ads_setspn_add(ads, argv[0], argv[1]);
3527 : } else {
3528 6 : ok = ads_setspn_add(ads, lp_netbios_name(), argv[0]);
3529 : }
3530 6 : if (!ok) {
3531 4 : ret = -1;
3532 : }
3533 5 : done:
3534 6 : if (ads) {
3535 6 : ads_destroy(&ads);
3536 : }
3537 6 : return ret;
3538 : }
3539 :
3540 2 : static int net_ads_setspn_delete(struct net_context *c, int argc, const char **argv)
3541 : {
3542 2 : int ret = 0;
3543 2 : bool ok = false;
3544 2 : ADS_STRUCT *ads = NULL;
3545 2 : if (c->display_usage || argc < 1) {
3546 0 : d_printf("%s\n%s",
3547 : _("Usage:"),
3548 : _("net ads setspn delete <machinename> SPN\n"));
3549 0 : ret = 0;
3550 0 : goto done;
3551 : }
3552 2 : if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3553 0 : ret = -1;
3554 0 : goto done;
3555 : }
3556 2 : if (argc > 1) {
3557 0 : ok = ads_setspn_delete(ads, argv[0], argv[1]);
3558 : } else {
3559 2 : ok = ads_setspn_delete(ads, lp_netbios_name(), argv[0]);
3560 : }
3561 2 : if (!ok) {
3562 0 : ret = -1;
3563 : }
3564 3 : done:
3565 2 : if (ads) {
3566 2 : ads_destroy(&ads);
3567 : }
3568 2 : return ret;
3569 : }
3570 :
3571 20 : int net_ads_setspn(struct net_context *c, int argc, const char **argv)
3572 : {
3573 20 : struct functable func[] = {
3574 : {
3575 : "list",
3576 : net_ads_setspn_list,
3577 : NET_TRANSPORT_ADS,
3578 : N_("List Service Principal Names (SPN)"),
3579 : N_("net ads setspn list machine\n"
3580 : " List Service Principal Names (SPN)")
3581 : },
3582 : {
3583 : "add",
3584 : net_ads_setspn_add,
3585 : NET_TRANSPORT_ADS,
3586 : N_("Add Service Principal Names (SPN)"),
3587 : N_("net ads setspn add machine spn\n"
3588 : " Add Service Principal Names (SPN)")
3589 : },
3590 : {
3591 : "delete",
3592 : net_ads_setspn_delete,
3593 : NET_TRANSPORT_ADS,
3594 : N_("Delete Service Principal Names (SPN)"),
3595 : N_("net ads setspn delete machine spn\n"
3596 : " Delete Service Principal Names (SPN)")
3597 : },
3598 : {NULL, NULL, 0, NULL, NULL}
3599 : };
3600 :
3601 20 : return net_run_function(c, argc, argv, "net ads setspn", func);
3602 : }
3603 :
3604 0 : static int net_ads_enctype_lookup_account(struct net_context *c,
3605 : ADS_STRUCT *ads,
3606 : const char *account,
3607 : LDAPMessage **res,
3608 : const char **enctype_str)
3609 : {
3610 : const char *filter;
3611 0 : const char *attrs[] = {
3612 : "msDS-SupportedEncryptionTypes",
3613 : NULL
3614 : };
3615 : int count;
3616 0 : int ret = -1;
3617 : ADS_STATUS status;
3618 :
3619 0 : filter = talloc_asprintf(c, "(&(objectclass=user)(sAMAccountName=%s))",
3620 : account);
3621 0 : if (filter == NULL) {
3622 0 : goto done;
3623 : }
3624 :
3625 0 : status = ads_search(ads, res, filter, attrs);
3626 0 : if (!ADS_ERR_OK(status)) {
3627 0 : d_printf(_("no account found with filter: %s\n"), filter);
3628 0 : goto done;
3629 : }
3630 :
3631 0 : count = ads_count_replies(ads, *res);
3632 0 : switch (count) {
3633 0 : case 1:
3634 0 : break;
3635 0 : case 0:
3636 0 : d_printf(_("no account found with filter: %s\n"), filter);
3637 0 : goto done;
3638 0 : default:
3639 0 : d_printf(_("multiple accounts found with filter: %s\n"), filter);
3640 0 : goto done;
3641 : }
3642 :
3643 0 : if (enctype_str) {
3644 0 : *enctype_str = ads_pull_string(ads, c, *res,
3645 : "msDS-SupportedEncryptionTypes");
3646 0 : if (*enctype_str == NULL) {
3647 0 : d_printf(_("no msDS-SupportedEncryptionTypes attribute found\n"));
3648 0 : goto done;
3649 : }
3650 : }
3651 :
3652 0 : ret = 0;
3653 0 : done:
3654 0 : return ret;
3655 : }
3656 :
3657 0 : static void net_ads_enctype_dump_enctypes(const char *username,
3658 : const char *enctype_str)
3659 : {
3660 0 : int enctypes = atoi(enctype_str);
3661 :
3662 0 : d_printf(_("'%s' uses \"msDS-SupportedEncryptionTypes\": %d (0x%08x)\n"),
3663 : username, enctypes, enctypes);
3664 :
3665 0 : printf("[%s] 0x%08x DES-CBC-CRC\n",
3666 0 : enctypes & ENC_CRC32 ? "X" : " ",
3667 : ENC_CRC32);
3668 0 : printf("[%s] 0x%08x DES-CBC-MD5\n",
3669 0 : enctypes & ENC_RSA_MD5 ? "X" : " ",
3670 : ENC_RSA_MD5);
3671 0 : printf("[%s] 0x%08x RC4-HMAC\n",
3672 0 : enctypes & ENC_RC4_HMAC_MD5 ? "X" : " ",
3673 : ENC_RC4_HMAC_MD5);
3674 0 : printf("[%s] 0x%08x AES128-CTS-HMAC-SHA1-96\n",
3675 0 : enctypes & ENC_HMAC_SHA1_96_AES128 ? "X" : " ",
3676 : ENC_HMAC_SHA1_96_AES128);
3677 0 : printf("[%s] 0x%08x AES256-CTS-HMAC-SHA1-96\n",
3678 0 : enctypes & ENC_HMAC_SHA1_96_AES256 ? "X" : " ",
3679 : ENC_HMAC_SHA1_96_AES256);
3680 0 : }
3681 :
3682 0 : static int net_ads_enctypes_list(struct net_context *c, int argc, const char **argv)
3683 : {
3684 0 : int ret = -1;
3685 : ADS_STATUS status;
3686 0 : ADS_STRUCT *ads = NULL;
3687 0 : LDAPMessage *res = NULL;
3688 0 : const char *str = NULL;
3689 :
3690 0 : if (c->display_usage || (argc < 1)) {
3691 0 : d_printf( "%s\n"
3692 : "net ads enctypes list\n"
3693 : " %s\n",
3694 : _("Usage:"),
3695 : _("List supported enctypes"));
3696 0 : return 0;
3697 : }
3698 :
3699 0 : status = ads_startup(c, false, &ads);
3700 0 : if (!ADS_ERR_OK(status)) {
3701 0 : printf("startup failed\n");
3702 0 : return ret;
3703 : }
3704 :
3705 0 : ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3706 0 : if (ret) {
3707 0 : goto done;
3708 : }
3709 :
3710 0 : net_ads_enctype_dump_enctypes(argv[0], str);
3711 :
3712 0 : ret = 0;
3713 0 : done:
3714 0 : ads_msgfree(ads, res);
3715 0 : ads_destroy(&ads);
3716 :
3717 0 : return ret;
3718 : }
3719 :
3720 0 : static int net_ads_enctypes_set(struct net_context *c, int argc, const char **argv)
3721 : {
3722 0 : int ret = -1;
3723 : ADS_STATUS status;
3724 : ADS_STRUCT *ads;
3725 0 : LDAPMessage *res = NULL;
3726 : const char *etype_list_str;
3727 : const char *dn;
3728 : ADS_MODLIST mods;
3729 : uint32_t etype_list;
3730 : const char *str;
3731 :
3732 0 : if (c->display_usage || argc < 1) {
3733 0 : d_printf( "%s\n"
3734 : "net ads enctypes set <sAMAccountName> [enctypes]\n"
3735 : " %s\n",
3736 : _("Usage:"),
3737 : _("Set supported enctypes"));
3738 0 : return 0;
3739 : }
3740 :
3741 0 : status = ads_startup(c, false, &ads);
3742 0 : if (!ADS_ERR_OK(status)) {
3743 0 : printf("startup failed\n");
3744 0 : return ret;
3745 : }
3746 :
3747 0 : ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3748 0 : if (ret) {
3749 0 : goto done;
3750 : }
3751 :
3752 0 : dn = ads_get_dn(ads, c, res);
3753 0 : if (dn == NULL) {
3754 0 : goto done;
3755 : }
3756 :
3757 0 : etype_list = ENC_CRC32 | ENC_RSA_MD5 | ENC_RC4_HMAC_MD5;
3758 : #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
3759 0 : etype_list |= ENC_HMAC_SHA1_96_AES128;
3760 : #endif
3761 : #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
3762 0 : etype_list |= ENC_HMAC_SHA1_96_AES256;
3763 : #endif
3764 :
3765 0 : if (argv[1] != NULL) {
3766 0 : sscanf(argv[1], "%i", &etype_list);
3767 : }
3768 :
3769 0 : etype_list_str = talloc_asprintf(c, "%d", etype_list);
3770 0 : if (!etype_list_str) {
3771 0 : goto done;
3772 : }
3773 :
3774 0 : mods = ads_init_mods(c);
3775 0 : if (!mods) {
3776 0 : goto done;
3777 : }
3778 :
3779 0 : status = ads_mod_str(c, &mods, "msDS-SupportedEncryptionTypes",
3780 : etype_list_str);
3781 0 : if (!ADS_ERR_OK(status)) {
3782 0 : goto done;
3783 : }
3784 :
3785 0 : status = ads_gen_mod(ads, dn, mods);
3786 0 : if (!ADS_ERR_OK(status)) {
3787 0 : d_printf(_("failed to add msDS-SupportedEncryptionTypes: %s\n"),
3788 : ads_errstr(status));
3789 0 : goto done;
3790 : }
3791 :
3792 0 : ads_msgfree(ads, res);
3793 :
3794 0 : ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3795 0 : if (ret) {
3796 0 : goto done;
3797 : }
3798 :
3799 0 : net_ads_enctype_dump_enctypes(argv[0], str);
3800 :
3801 0 : ret = 0;
3802 0 : done:
3803 0 : ads_msgfree(ads, res);
3804 0 : ads_destroy(&ads);
3805 :
3806 0 : return ret;
3807 : }
3808 :
3809 0 : static int net_ads_enctypes_delete(struct net_context *c, int argc, const char **argv)
3810 : {
3811 0 : int ret = -1;
3812 : ADS_STATUS status;
3813 : ADS_STRUCT *ads;
3814 0 : LDAPMessage *res = NULL;
3815 : const char *dn;
3816 : ADS_MODLIST mods;
3817 :
3818 0 : if (c->display_usage || argc < 1) {
3819 0 : d_printf( "%s\n"
3820 : "net ads enctypes delete <sAMAccountName>\n"
3821 : " %s\n",
3822 : _("Usage:"),
3823 : _("Delete supported enctypes"));
3824 0 : return 0;
3825 : }
3826 :
3827 0 : status = ads_startup(c, false, &ads);
3828 0 : if (!ADS_ERR_OK(status)) {
3829 0 : printf("startup failed\n");
3830 0 : return ret;
3831 : }
3832 :
3833 0 : ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3834 0 : if (ret) {
3835 0 : goto done;
3836 : }
3837 :
3838 0 : dn = ads_get_dn(ads, c, res);
3839 0 : if (dn == NULL) {
3840 0 : goto done;
3841 : }
3842 :
3843 0 : mods = ads_init_mods(c);
3844 0 : if (!mods) {
3845 0 : goto done;
3846 : }
3847 :
3848 0 : status = ads_mod_str(c, &mods, "msDS-SupportedEncryptionTypes", NULL);
3849 0 : if (!ADS_ERR_OK(status)) {
3850 0 : goto done;
3851 : }
3852 :
3853 0 : status = ads_gen_mod(ads, dn, mods);
3854 0 : if (!ADS_ERR_OK(status)) {
3855 0 : d_printf(_("failed to remove msDS-SupportedEncryptionTypes: %s\n"),
3856 : ads_errstr(status));
3857 0 : goto done;
3858 : }
3859 :
3860 0 : ret = 0;
3861 :
3862 0 : done:
3863 0 : ads_msgfree(ads, res);
3864 0 : ads_destroy(&ads);
3865 0 : return ret;
3866 : }
3867 :
3868 0 : static int net_ads_enctypes(struct net_context *c, int argc, const char **argv)
3869 : {
3870 0 : struct functable func[] = {
3871 : {
3872 : "list",
3873 : net_ads_enctypes_list,
3874 : NET_TRANSPORT_ADS,
3875 : N_("List the supported encryption types"),
3876 : N_("net ads enctypes list\n"
3877 : " List the supported encryption types")
3878 : },
3879 : {
3880 : "set",
3881 : net_ads_enctypes_set,
3882 : NET_TRANSPORT_ADS,
3883 : N_("Set the supported encryption types"),
3884 : N_("net ads enctypes set\n"
3885 : " Set the supported encryption types")
3886 : },
3887 : {
3888 : "delete",
3889 : net_ads_enctypes_delete,
3890 : NET_TRANSPORT_ADS,
3891 : N_("Delete the supported encryption types"),
3892 : N_("net ads enctypes delete\n"
3893 : " Delete the supported encryption types")
3894 : },
3895 :
3896 : {NULL, NULL, 0, NULL, NULL}
3897 : };
3898 :
3899 0 : return net_run_function(c, argc, argv, "net ads enctypes", func);
3900 : }
3901 :
3902 :
3903 182 : int net_ads(struct net_context *c, int argc, const char **argv)
3904 : {
3905 182 : struct functable func[] = {
3906 : {
3907 : "info",
3908 : net_ads_info,
3909 : NET_TRANSPORT_ADS,
3910 : N_("Display details on remote ADS server"),
3911 : N_("net ads info\n"
3912 : " Display details on remote ADS server")
3913 : },
3914 : {
3915 : "join",
3916 : net_ads_join,
3917 : NET_TRANSPORT_ADS,
3918 : N_("Join the local machine to ADS realm"),
3919 : N_("net ads join\n"
3920 : " Join the local machine to ADS realm")
3921 : },
3922 : {
3923 : "testjoin",
3924 : net_ads_testjoin,
3925 : NET_TRANSPORT_ADS,
3926 : N_("Validate machine account"),
3927 : N_("net ads testjoin\n"
3928 : " Validate machine account")
3929 : },
3930 : {
3931 : "leave",
3932 : net_ads_leave,
3933 : NET_TRANSPORT_ADS,
3934 : N_("Remove the local machine from ADS"),
3935 : N_("net ads leave\n"
3936 : " Remove the local machine from ADS")
3937 : },
3938 : {
3939 : "status",
3940 : net_ads_status,
3941 : NET_TRANSPORT_ADS,
3942 : N_("Display machine account details"),
3943 : N_("net ads status\n"
3944 : " Display machine account details")
3945 : },
3946 : {
3947 : "user",
3948 : net_ads_user,
3949 : NET_TRANSPORT_ADS,
3950 : N_("List/modify users"),
3951 : N_("net ads user\n"
3952 : " List/modify users")
3953 : },
3954 : {
3955 : "group",
3956 : net_ads_group,
3957 : NET_TRANSPORT_ADS,
3958 : N_("List/modify groups"),
3959 : N_("net ads group\n"
3960 : " List/modify groups")
3961 : },
3962 : {
3963 : "dns",
3964 : net_ads_dns,
3965 : NET_TRANSPORT_ADS,
3966 : N_("Issue dynamic DNS update"),
3967 : N_("net ads dns\n"
3968 : " Issue dynamic DNS update")
3969 : },
3970 : {
3971 : "password",
3972 : net_ads_password,
3973 : NET_TRANSPORT_ADS,
3974 : N_("Change user passwords"),
3975 : N_("net ads password\n"
3976 : " Change user passwords")
3977 : },
3978 : {
3979 : "changetrustpw",
3980 : net_ads_changetrustpw,
3981 : NET_TRANSPORT_ADS,
3982 : N_("Change trust account password"),
3983 : N_("net ads changetrustpw\n"
3984 : " Change trust account password")
3985 : },
3986 : {
3987 : "printer",
3988 : net_ads_printer,
3989 : NET_TRANSPORT_ADS,
3990 : N_("List/modify printer entries"),
3991 : N_("net ads printer\n"
3992 : " List/modify printer entries")
3993 : },
3994 : {
3995 : "search",
3996 : net_ads_search,
3997 : NET_TRANSPORT_ADS,
3998 : N_("Issue LDAP search using filter"),
3999 : N_("net ads search\n"
4000 : " Issue LDAP search using filter")
4001 : },
4002 : {
4003 : "dn",
4004 : net_ads_dn,
4005 : NET_TRANSPORT_ADS,
4006 : N_("Issue LDAP search by DN"),
4007 : N_("net ads dn\n"
4008 : " Issue LDAP search by DN")
4009 : },
4010 : {
4011 : "sid",
4012 : net_ads_sid,
4013 : NET_TRANSPORT_ADS,
4014 : N_("Issue LDAP search by SID"),
4015 : N_("net ads sid\n"
4016 : " Issue LDAP search by SID")
4017 : },
4018 : {
4019 : "workgroup",
4020 : net_ads_workgroup,
4021 : NET_TRANSPORT_ADS,
4022 : N_("Display workgroup name"),
4023 : N_("net ads workgroup\n"
4024 : " Display the workgroup name")
4025 : },
4026 : {
4027 : "lookup",
4028 : net_ads_lookup,
4029 : NET_TRANSPORT_ADS,
4030 : N_("Perform CLDAP query on DC"),
4031 : N_("net ads lookup\n"
4032 : " Find the ADS DC using CLDAP lookups")
4033 : },
4034 : {
4035 : "keytab",
4036 : net_ads_keytab,
4037 : NET_TRANSPORT_ADS,
4038 : N_("Manage local keytab file"),
4039 : N_("net ads keytab\n"
4040 : " Manage local keytab file")
4041 : },
4042 : {
4043 : "setspn",
4044 : net_ads_setspn,
4045 : NET_TRANSPORT_ADS,
4046 : N_("Manage Service Principal Names (SPN)s"),
4047 : N_("net ads spnset\n"
4048 : " Manage Service Principal Names (SPN)s")
4049 : },
4050 : {
4051 : "gpo",
4052 : net_ads_gpo,
4053 : NET_TRANSPORT_ADS,
4054 : N_("Manage group policy objects"),
4055 : N_("net ads gpo\n"
4056 : " Manage group policy objects")
4057 : },
4058 : {
4059 : "kerberos",
4060 : net_ads_kerberos,
4061 : NET_TRANSPORT_ADS,
4062 : N_("Manage kerberos keytab"),
4063 : N_("net ads kerberos\n"
4064 : " Manage kerberos keytab")
4065 : },
4066 : {
4067 : "enctypes",
4068 : net_ads_enctypes,
4069 : NET_TRANSPORT_ADS,
4070 : N_("List/modify supported encryption types"),
4071 : N_("net ads enctypes\n"
4072 : " List/modify enctypes")
4073 : },
4074 : {NULL, NULL, 0, NULL, NULL}
4075 : };
4076 :
4077 182 : return net_run_function(c, argc, argv, "net ads", func);
4078 : }
4079 :
4080 : #else
4081 :
4082 0 : static int net_ads_noads(void)
4083 : {
4084 0 : d_fprintf(stderr, _("ADS support not compiled in\n"));
4085 0 : return -1;
4086 : }
4087 :
4088 0 : int net_ads_keytab(struct net_context *c, int argc, const char **argv)
4089 : {
4090 0 : return net_ads_noads();
4091 : }
4092 :
4093 0 : int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
4094 : {
4095 0 : return net_ads_noads();
4096 : }
4097 :
4098 0 : int net_ads_setspn(struct net_context *c, int argc, const char **argv)
4099 : {
4100 0 : return net_ads_noads();
4101 : }
4102 :
4103 0 : int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
4104 : {
4105 0 : return net_ads_noads();
4106 : }
4107 :
4108 0 : int net_ads_join(struct net_context *c, int argc, const char **argv)
4109 : {
4110 0 : return net_ads_noads();
4111 : }
4112 :
4113 0 : int net_ads_user(struct net_context *c, int argc, const char **argv)
4114 : {
4115 0 : return net_ads_noads();
4116 : }
4117 :
4118 0 : int net_ads_group(struct net_context *c, int argc, const char **argv)
4119 : {
4120 0 : return net_ads_noads();
4121 : }
4122 :
4123 0 : int net_ads_gpo(struct net_context *c, int argc, const char **argv)
4124 : {
4125 0 : return net_ads_noads();
4126 : }
4127 :
4128 : /* this one shouldn't display a message */
4129 0 : int net_ads_check(struct net_context *c)
4130 : {
4131 0 : return -1;
4132 : }
4133 :
4134 0 : int net_ads_check_our_domain(struct net_context *c)
4135 : {
4136 0 : return -1;
4137 : }
4138 :
4139 0 : int net_ads(struct net_context *c, int argc, const char **argv)
4140 : {
4141 0 : return net_ads_noads();
4142 : }
4143 :
4144 : #endif /* HAVE_ADS */
|