s3:client: Fix old-style function definition
[Samba.git] / source3 / utils / net_ads.c
blob9b2cc50aa31fb996ce61203fdcca9a8ea7de3411
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)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "utils/net.h"
25 #include "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"
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] */
52 #ifdef HAVE_ADS
54 /* when we do not have sufficient input parameters to contact a remote domain
55 * we always fall back to our own realm - Guenther*/
57 static const char *assume_own_realm(struct net_context *c)
59 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
60 return lp_realm();
63 return NULL;
66 #ifdef HAVE_JANSSON
69 * note: JSON output deliberately bypasses gettext so as to provide the same
70 * output irrespective of the locale.
73 static int output_json(const struct json_object *jsobj)
75 TALLOC_CTX *ctx = NULL;
76 char *json = NULL;
78 if (json_is_invalid(jsobj)) {
79 return -1;
82 ctx = talloc_new(NULL);
83 if (ctx == NULL) {
84 d_fprintf(stderr, _("Out of memory\n"));
85 return -1;
88 json = json_to_string(ctx, jsobj);
89 if (!json) {
90 d_fprintf(stderr, _("error encoding to JSON\n"));
91 return -1;
94 d_printf("%s\n", json);
95 TALLOC_FREE(ctx);
97 return 0;
100 static int net_ads_cldap_netlogon_json
101 (ADS_STRUCT *ads,
102 const char *addr,
103 const struct NETLOGON_SAM_LOGON_RESPONSE_EX *reply)
105 struct json_object jsobj = json_new_object();
106 struct json_object flagsobj = json_new_object();
107 char response_type [32] = { '\0' };
108 int ret = 0;
110 if (json_is_invalid(&jsobj) || json_is_invalid(&flagsobj)) {
111 d_fprintf(stderr, _("error setting up JSON value\n"));
113 goto failure;
116 switch (reply->command) {
117 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
118 strncpy(response_type,
119 "LOGON_SAM_LOGON_USER_UNKNOWN_EX",
120 sizeof(response_type));
121 break;
122 case LOGON_SAM_LOGON_RESPONSE_EX:
123 strncpy(response_type, "LOGON_SAM_LOGON_RESPONSE_EX",
124 sizeof(response_type));
125 break;
126 default:
127 snprintf(response_type, sizeof(response_type), "0x%x",
128 reply->command);
129 break;
132 ret = json_add_string(&jsobj, "Information for Domain Controller",
133 addr);
134 if (ret != 0) {
135 goto failure;
138 ret = json_add_string(&jsobj, "Response Type", response_type);
139 if (ret != 0) {
140 goto failure;
143 ret = json_add_guid(&jsobj, "GUID", &reply->domain_uuid);
144 if (ret != 0) {
145 goto failure;
148 ret = json_add_bool(&flagsobj, "Is a PDC",
149 reply->server_type & NBT_SERVER_PDC);
150 if (ret != 0) {
151 goto failure;
154 ret = json_add_bool(&flagsobj, "Is a GC of the forest",
155 reply->server_type & NBT_SERVER_GC);
156 if (ret != 0) {
157 goto failure;
160 ret = json_add_bool(&flagsobj, "Is an LDAP server",
161 reply->server_type & NBT_SERVER_LDAP);
162 if (ret != 0) {
163 goto failure;
166 ret = json_add_bool(&flagsobj, "Supports DS",
167 reply->server_type & NBT_SERVER_DS);
168 if (ret != 0) {
169 goto failure;
172 ret = json_add_bool(&flagsobj, "Is running a KDC",
173 reply->server_type & NBT_SERVER_KDC);
174 if (ret != 0) {
175 goto failure;
178 ret = json_add_bool(&flagsobj, "Is running time services",
179 reply->server_type & NBT_SERVER_TIMESERV);
180 if (ret != 0) {
181 goto failure;
184 ret = json_add_bool(&flagsobj, "Is the closest DC",
185 reply->server_type & NBT_SERVER_CLOSEST);
186 if (ret != 0) {
187 goto failure;
190 ret = json_add_bool(&flagsobj, "Is writable",
191 reply->server_type & NBT_SERVER_WRITABLE);
192 if (ret != 0) {
193 goto failure;
196 ret = json_add_bool(&flagsobj, "Has a hardware clock",
197 reply->server_type & NBT_SERVER_GOOD_TIMESERV);
198 if (ret != 0) {
199 goto failure;
202 ret = json_add_bool(&flagsobj,
203 "Is a non-domain NC serviced by LDAP server",
204 reply->server_type & NBT_SERVER_NDNC);
205 if (ret != 0) {
206 goto failure;
209 ret = json_add_bool
210 (&flagsobj, "Is NT6 DC that has some secrets",
211 reply->server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6);
212 if (ret != 0) {
213 goto failure;
216 ret = json_add_bool
217 (&flagsobj, "Is NT6 DC that has all secrets",
218 reply->server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6);
219 if (ret != 0) {
220 goto failure;
223 ret = json_add_bool(&flagsobj, "Runs Active Directory Web Services",
224 reply->server_type & NBT_SERVER_ADS_WEB_SERVICE);
225 if (ret != 0) {
226 goto failure;
229 ret = json_add_bool(&flagsobj, "Runs on Windows 2012 or later",
230 reply->server_type & NBT_SERVER_DS_8);
231 if (ret != 0) {
232 goto failure;
235 ret = json_add_string(&jsobj, "Forest", reply->forest);
236 if (ret != 0) {
237 goto failure;
240 ret = json_add_string(&jsobj, "Domain", reply->dns_domain);
241 if (ret != 0) {
242 goto failure;
245 ret = json_add_string(&jsobj, "Domain Controller", reply->pdc_dns_name);
246 if (ret != 0) {
247 goto failure;
251 ret = json_add_string(&jsobj, "Pre-Win2k Domain", reply->domain_name);
252 if (ret != 0) {
253 goto failure;
256 ret = json_add_string(&jsobj, "Pre-Win2k Hostname", reply->pdc_name);
257 if (ret != 0) {
258 goto failure;
261 if (*reply->user_name) {
262 ret = json_add_string(&jsobj, "User name", reply->user_name);
263 if (ret != 0) {
264 goto failure;
268 ret = json_add_string(&jsobj, "Server Site Name", reply->server_site);
269 if (ret != 0) {
270 goto failure;
273 ret = json_add_string(&jsobj, "Client Site Name", reply->client_site);
274 if (ret != 0) {
275 goto failure;
278 ret = json_add_int(&jsobj, "NT Version", reply->nt_version);
279 if (ret != 0) {
280 goto failure;
283 ret = json_add_int(&jsobj, "LMNT Token", reply->lmnt_token);
284 if (ret != 0) {
285 goto failure;
288 ret = json_add_int(&jsobj, "LM20 Token", reply->lm20_token);
289 if (ret != 0) {
290 goto failure;
293 ret = json_add_object(&jsobj, "Flags", &flagsobj);
294 if (ret != 0) {
295 goto failure;
298 ret = output_json(&jsobj);
299 json_free(&jsobj); /* frees flagsobj recursively */
301 return ret;
303 failure:
304 json_free(&flagsobj);
305 json_free(&jsobj);
307 return ret;
310 #else /* [HAVE_JANSSON] */
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)
317 d_fprintf(stderr, _("JSON support not available\n"));
319 return -1;
322 #endif /* [HAVE_JANSSON] */
325 do a cldap netlogon query
327 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
329 char addr[INET6_ADDRSTRLEN];
330 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
332 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
334 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads->ldap.ss, ads->server.realm, &reply ) ) {
335 d_fprintf(stderr, _("CLDAP query failed!\n"));
336 return -1;
339 if (c->opt_json) {
340 return net_ads_cldap_netlogon_json(ads, addr, &reply);
343 d_printf(_("Information for Domain Controller: %s\n\n"),
344 addr);
346 d_printf(_("Response Type: "));
347 switch (reply.command) {
348 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
349 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
350 break;
351 case LOGON_SAM_LOGON_RESPONSE_EX:
352 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
353 break;
354 default:
355 d_printf("0x%x\n", reply.command);
356 break;
359 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
361 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 (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
377 (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
378 (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
379 (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
380 (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
381 (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
382 (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
383 (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
384 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
385 (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
386 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
387 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"),
388 (reply.server_type & NBT_SERVER_ADS_WEB_SERVICE) ? _("yes") : _("no"),
389 (reply.server_type & NBT_SERVER_DS_8) ? _("yes") : _("no"));
392 printf(_("Forest: %s\n"), reply.forest);
393 printf(_("Domain: %s\n"), reply.dns_domain);
394 printf(_("Domain Controller: %s\n"), reply.pdc_dns_name);
396 printf(_("Pre-Win2k Domain: %s\n"), reply.domain_name);
397 printf(_("Pre-Win2k Hostname: %s\n"), reply.pdc_name);
399 if (*reply.user_name) printf(_("User name: %s\n"), reply.user_name);
401 printf(_("Server Site Name: %s\n"), reply.server_site);
402 printf(_("Client Site Name: %s\n"), reply.client_site);
404 d_printf(_("NT Version: %d\n"), reply.nt_version);
405 d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
406 d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
408 return 0;
412 this implements the CLDAP based netlogon lookup requests
413 for finding the domain controller of a ADS domain
415 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
417 TALLOC_CTX *tmp_ctx = talloc_stackframe();
418 ADS_STRUCT *ads = NULL;
419 ADS_STATUS status;
420 int ret = -1;
422 if (c->display_usage) {
423 d_printf("%s\n"
424 "net ads lookup\n"
425 " %s",
426 _("Usage:"),
427 _("Find the ADS DC using CLDAP lookup.\n"));
428 TALLOC_FREE(tmp_ctx);
429 return -1;
432 status = ads_startup_nobind(c, false, tmp_ctx, &ads);
433 if (!ADS_ERR_OK(status)) {
434 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
435 goto out;
438 if (!ads->config.realm) {
439 ads->config.realm = talloc_strdup(ads, c->opt_target_workgroup);
440 if (ads->config.realm == NULL) {
441 d_fprintf(stderr, _("Out of memory\n"));
442 goto out;
444 ads->ldap.port = 389;
447 ret = net_ads_cldap_netlogon(c, ads);
448 out:
449 TALLOC_FREE(tmp_ctx);
450 return ret;
454 #ifdef HAVE_JANSSON
456 static int net_ads_info_json(ADS_STRUCT *ads)
458 int ret = 0;
459 char addr[INET6_ADDRSTRLEN];
460 time_t pass_time;
461 struct json_object jsobj = json_new_object();
463 if (json_is_invalid(&jsobj)) {
464 d_fprintf(stderr, _("error setting up JSON value\n"));
466 goto failure;
469 pass_time = secrets_fetch_pass_last_set_time(ads->server.workgroup);
471 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
473 ret = json_add_string (&jsobj, "LDAP server", addr);
474 if (ret != 0) {
475 goto failure;
478 ret = json_add_string (&jsobj, "LDAP server name",
479 ads->config.ldap_server_name);
480 if (ret != 0) {
481 goto failure;
484 ret = json_add_string (&jsobj, "Realm", ads->config.realm);
485 if (ret != 0) {
486 goto failure;
489 ret = json_add_string (&jsobj, "Bind Path", ads->config.bind_path);
490 if (ret != 0) {
491 goto failure;
494 ret = json_add_int (&jsobj, "LDAP port", ads->ldap.port);
495 if (ret != 0) {
496 goto failure;
499 ret = json_add_int (&jsobj, "Server time", ads->config.current_time);
500 if (ret != 0) {
501 goto failure;
504 ret = json_add_string (&jsobj, "KDC server", ads->auth.kdc_server);
505 if (ret != 0) {
506 goto failure;
509 ret = json_add_int (&jsobj, "Server time offset",
510 ads->auth.time_offset);
511 if (ret != 0) {
512 goto failure;
515 ret = json_add_int (&jsobj, "Last machine account password change",
516 pass_time);
517 if (ret != 0) {
518 goto failure;
521 ret = output_json(&jsobj);
522 failure:
523 json_free(&jsobj);
525 return ret;
528 #else /* [HAVE_JANSSON] */
530 static int net_ads_info_json(ADS_STRUCT *ads)
532 d_fprintf(stderr, _("JSON support not available\n"));
534 return -1;
537 #endif /* [HAVE_JANSSON] */
541 static int net_ads_info(struct net_context *c, int argc, const char **argv)
543 TALLOC_CTX *tmp_ctx = talloc_stackframe();
544 ADS_STRUCT *ads = NULL;
545 ADS_STATUS status;
546 char addr[INET6_ADDRSTRLEN];
547 time_t pass_time;
548 int ret = -1;
550 if (c->display_usage) {
551 d_printf("%s\n"
552 "net ads info\n"
553 " %s",
554 _("Usage:"),
555 _("Display information about an Active Directory "
556 "server.\n"));
557 TALLOC_FREE(tmp_ctx);
558 return -1;
561 status = ads_startup_nobind(c, false, tmp_ctx, &ads);
562 if (!ADS_ERR_OK(status)) {
563 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
564 goto out;
567 if (!ads || !ads->config.realm) {
568 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
569 goto out;
572 /* Try to set the server's current time since we didn't do a full
573 TCP LDAP session initially */
575 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
576 d_fprintf( stderr, _("Failed to get server's current time!\n"));
579 if (c->opt_json) {
580 ret = net_ads_info_json(ads);
581 goto out;
584 pass_time = secrets_fetch_pass_last_set_time(ads->server.workgroup);
586 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
588 d_printf(_("LDAP server: %s\n"), addr);
589 d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
590 d_printf(_("Realm: %s\n"), ads->config.realm);
591 d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
592 d_printf(_("LDAP port: %d\n"), ads->ldap.port);
593 d_printf(_("Server time: %s\n"),
594 http_timestring(tmp_ctx, ads->config.current_time));
596 d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
597 d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
599 d_printf(_("Last machine account password change: %s\n"),
600 http_timestring(tmp_ctx, pass_time));
602 ret = 0;
603 out:
604 TALLOC_FREE(tmp_ctx);
605 return ret;
608 static ADS_STATUS ads_startup_int(struct net_context *c,
609 bool only_own_domain,
610 uint32_t auth_flags,
611 TALLOC_CTX *mem_ctx,
612 ADS_STRUCT **ads_ret)
614 ADS_STRUCT *ads = NULL;
615 ADS_STATUS status;
616 bool need_password = false;
617 bool second_time = false;
618 char *cp;
619 const char *realm = NULL;
620 bool tried_closest_dc = false;
621 enum credentials_use_kerberos krb5_state =
622 CRED_USE_KERBEROS_DISABLED;
624 /* lp_realm() should be handled by a command line param,
625 However, the join requires that realm be set in smb.conf
626 and compares our realm with the remote server's so this is
627 ok until someone needs more flexibility */
629 *ads_ret = NULL;
631 retry_connect:
632 if (only_own_domain) {
633 realm = lp_realm();
634 } else {
635 realm = assume_own_realm(c);
638 ads = ads_init(mem_ctx,
639 realm,
640 c->opt_target_workgroup,
641 c->opt_host,
642 ADS_SASL_PLAIN);
643 if (ads == NULL) {
644 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
647 if (!c->opt_user_name) {
648 c->opt_user_name = "administrator";
651 if (c->opt_user_specified) {
652 need_password = true;
655 retry:
656 if (!c->opt_password && need_password && !c->opt_machine_pass) {
657 c->opt_password = net_prompt_pass(c, c->opt_user_name);
658 if (!c->opt_password) {
659 TALLOC_FREE(ads);
660 return ADS_ERROR(LDAP_NO_MEMORY);
664 if (c->opt_password) {
665 use_in_memory_ccache();
666 TALLOC_FREE(ads->auth.password);
667 ads->auth.password = talloc_strdup(ads, c->opt_password);
668 if (ads->auth.password == NULL) {
669 TALLOC_FREE(ads);
670 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
674 TALLOC_FREE(ads->auth.user_name);
675 ads->auth.user_name = talloc_strdup(ads, c->opt_user_name);
676 if (ads->auth.user_name == NULL) {
677 TALLOC_FREE(ads);
678 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
681 ads->auth.flags |= auth_flags;
683 /* The ADS code will handle FIPS mode */
684 krb5_state = cli_credentials_get_kerberos_state(c->creds);
685 switch (krb5_state) {
686 case CRED_USE_KERBEROS_REQUIRED:
687 ads->auth.flags &= ~ADS_AUTH_DISABLE_KERBEROS;
688 ads->auth.flags &= ~ADS_AUTH_ALLOW_NTLMSSP;
689 break;
690 case CRED_USE_KERBEROS_DESIRED:
691 ads->auth.flags &= ~ADS_AUTH_DISABLE_KERBEROS;
692 ads->auth.flags |= ADS_AUTH_ALLOW_NTLMSSP;
693 break;
694 case CRED_USE_KERBEROS_DISABLED:
695 ads->auth.flags |= ADS_AUTH_DISABLE_KERBEROS;
696 ads->auth.flags |= ADS_AUTH_ALLOW_NTLMSSP;
697 break;
701 * If the username is of the form "name@realm",
702 * extract the realm and convert to upper case.
703 * This is only used to establish the connection.
705 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
706 *cp++ = '\0';
707 TALLOC_FREE(ads->auth.realm);
708 ads->auth.realm = talloc_asprintf_strupper_m(ads, "%s", cp);
709 if (ads->auth.realm == NULL) {
710 TALLOC_FREE(ads);
711 return ADS_ERROR(LDAP_NO_MEMORY);
715 status = ads_connect(ads);
717 if (!ADS_ERR_OK(status)) {
719 if (NT_STATUS_EQUAL(ads_ntstatus(status),
720 NT_STATUS_NO_LOGON_SERVERS)) {
721 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
722 TALLOC_FREE(ads);
723 return status;
726 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
727 need_password = true;
728 second_time = true;
729 goto retry;
730 } else {
731 TALLOC_FREE(ads);
732 return status;
736 /* when contacting our own domain, make sure we use the closest DC.
737 * This is done by reconnecting to ADS because only the first call to
738 * ads_connect will give us our own sitename */
740 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
742 tried_closest_dc = true; /* avoid loop */
744 if (!ads_closest_dc(ads)) {
746 namecache_delete(ads->server.realm, 0x1C);
747 namecache_delete(ads->server.workgroup, 0x1C);
749 TALLOC_FREE(ads);
751 goto retry_connect;
755 *ads_ret = talloc_move(mem_ctx, &ads);
756 return status;
759 ADS_STATUS ads_startup(struct net_context *c,
760 bool only_own_domain,
761 TALLOC_CTX *mem_ctx,
762 ADS_STRUCT **ads)
764 return ads_startup_int(c, only_own_domain, 0, mem_ctx, ads);
767 ADS_STATUS ads_startup_nobind(struct net_context *c,
768 bool only_own_domain,
769 TALLOC_CTX *mem_ctx,
770 ADS_STRUCT **ads)
772 return ads_startup_int(c,
773 only_own_domain,
774 ADS_AUTH_NO_BIND,
775 mem_ctx,
776 ads);
780 Check to see if connection can be made via ads.
781 ads_startup() stores the password in opt_password if it needs to so
782 that rpc or rap can use it without re-prompting.
784 static int net_ads_check_int(struct net_context *c,
785 const char *realm,
786 const char *workgroup,
787 const char *host)
789 TALLOC_CTX *tmp_ctx = talloc_stackframe();
790 ADS_STRUCT *ads;
791 ADS_STATUS status;
792 int ret = -1;
794 ads = ads_init(tmp_ctx, realm, workgroup, host, ADS_SASL_PLAIN);
795 if (ads == NULL) {
796 goto out;
799 ads->auth.flags |= ADS_AUTH_NO_BIND;
801 status = ads_connect(ads);
802 if ( !ADS_ERR_OK(status) ) {
803 goto out;
806 ret = 0;
807 out:
808 TALLOC_FREE(tmp_ctx);
809 return ret;
812 int net_ads_check_our_domain(struct net_context *c)
814 return net_ads_check_int(c, lp_realm(), lp_workgroup(), NULL);
817 int net_ads_check(struct net_context *c)
819 return net_ads_check_int(c, NULL, c->opt_workgroup, c->opt_host);
823 determine the netbios workgroup name for a domain
825 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
827 TALLOC_CTX *tmp_ctx = talloc_stackframe();
828 ADS_STRUCT *ads = NULL;
829 ADS_STATUS status;
830 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
831 bool ok = false;
832 int ret = -1;
834 if (c->display_usage) {
835 d_printf ("%s\n"
836 "net ads workgroup\n"
837 " %s\n",
838 _("Usage:"),
839 _("Print the workgroup name"));
840 TALLOC_FREE(tmp_ctx);
841 return -1;
844 status = ads_startup_nobind(c, false, tmp_ctx, &ads);
845 if (!ADS_ERR_OK(status)) {
846 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
847 goto out;
850 if (!ads->config.realm) {
851 ads->config.realm = talloc_strdup(ads, c->opt_target_workgroup);
852 if (ads->config.realm == NULL) {
853 d_fprintf(stderr, _("Out of memory\n"));
854 goto out;
856 ads->ldap.port = 389;
859 ok = ads_cldap_netlogon_5(tmp_ctx,
860 &ads->ldap.ss, ads->server.realm, &reply);
861 if (!ok) {
862 d_fprintf(stderr, _("CLDAP query failed!\n"));
863 goto out;
866 d_printf(_("Workgroup: %s\n"), reply.domain_name);
868 ret = 0;
869 out:
870 TALLOC_FREE(tmp_ctx);
872 return ret;
877 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
879 char **disp_fields = (char **) data_area;
881 if (!field) { /* must be end of record */
882 if (disp_fields[0]) {
883 if (!strchr_m(disp_fields[0], '$')) {
884 if (disp_fields[1])
885 d_printf("%-21.21s %s\n",
886 disp_fields[0], disp_fields[1]);
887 else
888 d_printf("%s\n", disp_fields[0]);
891 SAFE_FREE(disp_fields[0]);
892 SAFE_FREE(disp_fields[1]);
893 return true;
895 if (!values) /* must be new field, indicate string field */
896 return true;
897 if (strcasecmp_m(field, "sAMAccountName") == 0) {
898 disp_fields[0] = SMB_STRDUP((char *) values[0]);
900 if (strcasecmp_m(field, "description") == 0)
901 disp_fields[1] = SMB_STRDUP((char *) values[0]);
902 return true;
905 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
907 return net_user_usage(c, argc, argv);
910 static int ads_user_add(struct net_context *c, int argc, const char **argv)
912 TALLOC_CTX *tmp_ctx = talloc_stackframe();
913 ADS_STRUCT *ads = NULL;
914 ADS_STATUS status;
915 char *upn, *userdn;
916 LDAPMessage *res=NULL;
917 int rc = -1;
918 char *ou_str = NULL;
920 if (argc < 1 || c->display_usage) {
921 TALLOC_FREE(tmp_ctx);
922 return net_ads_user_usage(c, argc, argv);
925 status = ads_startup(c, false, tmp_ctx, &ads);
926 if (!ADS_ERR_OK(status)) {
927 goto done;
930 status = ads_find_user_acct(ads, &res, argv[0]);
931 if (!ADS_ERR_OK(status)) {
932 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
933 goto done;
936 if (ads_count_replies(ads, res)) {
937 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
938 argv[0]);
939 goto done;
942 if (c->opt_container) {
943 ou_str = SMB_STRDUP(c->opt_container);
944 } else {
945 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
948 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
949 if (!ADS_ERR_OK(status)) {
950 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
951 ads_errstr(status));
952 goto done;
955 /* if no password is to be set, we're done */
956 if (argc == 1) {
957 d_printf(_("User %s added\n"), argv[0]);
958 rc = 0;
959 goto done;
962 /* try setting the password */
963 upn = talloc_asprintf(tmp_ctx,
964 "%s@%s",
965 argv[0],
966 ads->config.realm);
967 if (upn == NULL) {
968 goto done;
971 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
972 ads->auth.time_offset);
973 if (ADS_ERR_OK(status)) {
974 d_printf(_("User %s added\n"), argv[0]);
975 rc = 0;
976 goto done;
978 TALLOC_FREE(upn);
980 /* password didn't set, delete account */
981 d_fprintf(stderr, _("Could not add user %s. "
982 "Error setting password %s\n"),
983 argv[0], ads_errstr(status));
985 ads_msgfree(ads, res);
986 res = NULL;
988 status=ads_find_user_acct(ads, &res, argv[0]);
989 if (ADS_ERR_OK(status)) {
990 userdn = ads_get_dn(ads, tmp_ctx, res);
991 ads_del_dn(ads, userdn);
992 TALLOC_FREE(userdn);
995 done:
996 ads_msgfree(ads, res);
997 SAFE_FREE(ou_str);
998 TALLOC_FREE(tmp_ctx);
999 return rc;
1002 static int ads_user_info(struct net_context *c, int argc, const char **argv)
1004 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1005 ADS_STRUCT *ads = NULL;
1006 ADS_STATUS status;
1007 LDAPMessage *res = NULL;
1008 int ret = -1;
1009 wbcErr wbc_status;
1010 const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
1011 char *searchstring = NULL;
1012 char **grouplist = NULL;
1013 char *primary_group = NULL;
1014 char *escaped_user = NULL;
1015 struct dom_sid primary_group_sid;
1016 uint32_t group_rid;
1017 enum wbcSidType type;
1019 if (argc < 1 || c->display_usage) {
1020 TALLOC_FREE(tmp_ctx);
1021 return net_ads_user_usage(c, argc, argv);
1024 escaped_user = escape_ldap_string(tmp_ctx, argv[0]);
1025 if (!escaped_user) {
1026 d_fprintf(stderr,
1027 _("ads_user_info: failed to escape user %s\n"),
1028 argv[0]);
1029 goto out;
1032 status = ads_startup(c, false, tmp_ctx, &ads);
1033 if (!ADS_ERR_OK(status)) {
1034 goto out;
1037 searchstring = talloc_asprintf(tmp_ctx,
1038 "(sAMAccountName=%s)",
1039 escaped_user);
1040 if (searchstring == NULL) {
1041 goto out;
1044 status = ads_search(ads, &res, searchstring, attrs);
1045 if (!ADS_ERR_OK(status)) {
1046 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(status));
1047 goto out;
1050 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
1051 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
1052 goto out;
1055 status = ads_domain_sid(ads, &primary_group_sid);
1056 if (!ADS_ERR_OK(status)) {
1057 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(status));
1058 goto out;
1061 sid_append_rid(&primary_group_sid, group_rid);
1063 wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
1064 NULL, /* don't look up domain */
1065 &primary_group,
1066 &type);
1067 if (!WBC_ERROR_IS_OK(wbc_status)) {
1068 d_fprintf(stderr, "wbcLookupSid: %s\n",
1069 wbcErrorString(wbc_status));
1070 goto out;
1073 d_printf("%s\n", primary_group);
1075 wbcFreeMemory(primary_group);
1077 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
1078 (LDAPMessage *)res, "memberOf");
1080 if (grouplist) {
1081 int i;
1082 char **groupname;
1083 for (i=0;grouplist[i];i++) {
1084 groupname = ldap_explode_dn(grouplist[i], 1);
1085 d_printf("%s\n", groupname[0]);
1086 ldap_value_free(groupname);
1088 ldap_value_free(grouplist);
1091 ret = 0;
1092 out:
1093 ads_msgfree(ads, res);
1094 TALLOC_FREE(tmp_ctx);
1095 return ret;
1098 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
1100 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1101 ADS_STRUCT *ads = NULL;
1102 ADS_STATUS status;
1103 LDAPMessage *res = NULL;
1104 char *userdn = NULL;
1105 int ret = -1;
1107 if (argc < 1) {
1108 TALLOC_FREE(tmp_ctx);
1109 return net_ads_user_usage(c, argc, argv);
1112 status = ads_startup(c, false, tmp_ctx, &ads);
1113 if (!ADS_ERR_OK(status)) {
1114 goto out;
1117 status = ads_find_user_acct(ads, &res, argv[0]);
1118 if (!ADS_ERR_OK(status) || ads_count_replies(ads, res) != 1) {
1119 d_printf(_("User %s does not exist.\n"), argv[0]);
1120 goto out;
1123 userdn = ads_get_dn(ads, tmp_ctx, res);
1124 if (userdn == NULL) {
1125 goto out;
1128 status = ads_del_dn(ads, userdn);
1129 if (!ADS_ERR_OK(status)) {
1130 d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
1131 ads_errstr(status));
1132 goto out;
1135 d_printf(_("User %s deleted\n"), argv[0]);
1137 ret = 0;
1138 out:
1139 ads_msgfree(ads, res);
1140 TALLOC_FREE(tmp_ctx);
1141 return ret;
1144 int net_ads_user(struct net_context *c, int argc, const char **argv)
1146 struct functable func[] = {
1148 "add",
1149 ads_user_add,
1150 NET_TRANSPORT_ADS,
1151 N_("Add an AD user"),
1152 N_("net ads user add\n"
1153 " Add an AD user")
1156 "info",
1157 ads_user_info,
1158 NET_TRANSPORT_ADS,
1159 N_("Display information about an AD user"),
1160 N_("net ads user info\n"
1161 " Display information about an AD user")
1164 "delete",
1165 ads_user_delete,
1166 NET_TRANSPORT_ADS,
1167 N_("Delete an AD user"),
1168 N_("net ads user delete\n"
1169 " Delete an AD user")
1171 {NULL, NULL, 0, NULL, NULL}
1173 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1174 ADS_STRUCT *ads = NULL;
1175 ADS_STATUS status;
1176 const char *shortattrs[] = {"sAMAccountName", NULL};
1177 const char *longattrs[] = {"sAMAccountName", "description", NULL};
1178 char *disp_fields[2] = {NULL, NULL};
1179 int ret = -1;
1181 if (argc > 0) {
1182 TALLOC_FREE(tmp_ctx);
1183 return net_run_function(c, argc, argv, "net ads user", func);
1186 if (c->display_usage) {
1187 d_printf( "%s\n"
1188 "net ads user\n"
1189 " %s\n",
1190 _("Usage:"),
1191 _("List AD users"));
1192 net_display_usage_from_functable(func);
1193 TALLOC_FREE(tmp_ctx);
1194 return -1;
1197 status = ads_startup(c, false, tmp_ctx, &ads);
1198 if (!ADS_ERR_OK(status)) {
1199 goto out;
1202 if (c->opt_long_list_entries)
1203 d_printf(_("\nUser name Comment"
1204 "\n-----------------------------\n"));
1206 status = ads_do_search_all_fn(ads,
1207 ads->config.bind_path,
1208 LDAP_SCOPE_SUBTREE,
1209 "(objectCategory=user)",
1210 c->opt_long_list_entries ?
1211 longattrs : shortattrs,
1212 usergrp_display,
1213 disp_fields);
1214 if (!ADS_ERR_OK(status)) {
1215 goto out;
1218 ret = 0;
1219 out:
1220 TALLOC_FREE(tmp_ctx);
1221 return ret;
1224 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
1226 return net_group_usage(c, argc, argv);
1229 static int ads_group_add(struct net_context *c, int argc, const char **argv)
1231 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1232 ADS_STRUCT *ads = NULL;
1233 ADS_STATUS status;
1234 LDAPMessage *res = NULL;
1235 int ret = -1;
1236 char *ou_str = NULL;
1238 if (argc < 1 || c->display_usage) {
1239 TALLOC_FREE(tmp_ctx);
1240 return net_ads_group_usage(c, argc, argv);
1243 status = ads_startup(c, false, tmp_ctx, &ads);
1244 if (!ADS_ERR_OK(status)) {
1245 goto out;
1248 status = ads_find_user_acct(ads, &res, argv[0]);
1249 if (!ADS_ERR_OK(status)) {
1250 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
1251 goto out;
1254 if (ads_count_replies(ads, res)) {
1255 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
1256 goto out;
1259 if (c->opt_container) {
1260 ou_str = SMB_STRDUP(c->opt_container);
1261 } else {
1262 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
1265 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
1266 if (!ADS_ERR_OK(status)) {
1267 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
1268 ads_errstr(status));
1269 goto out;
1272 d_printf(_("Group %s added\n"), argv[0]);
1274 ret = 0;
1275 out:
1276 ads_msgfree(ads, res);
1277 SAFE_FREE(ou_str);
1278 TALLOC_FREE(tmp_ctx);
1279 return ret;
1282 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
1284 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1285 ADS_STRUCT *ads = NULL;
1286 ADS_STATUS status;
1287 LDAPMessage *res = NULL;
1288 char *groupdn = NULL;
1289 int ret = -1;
1291 if (argc < 1 || c->display_usage) {
1292 TALLOC_FREE(tmp_ctx);
1293 return net_ads_group_usage(c, argc, argv);
1296 status = ads_startup(c, false, tmp_ctx, &ads);
1297 if (!ADS_ERR_OK(status)) {
1298 goto out;
1301 status = ads_find_user_acct(ads, &res, argv[0]);
1302 if (!ADS_ERR_OK(status) || ads_count_replies(ads, res) != 1) {
1303 d_printf(_("Group %s does not exist.\n"), argv[0]);
1304 goto out;
1307 groupdn = ads_get_dn(ads, tmp_ctx, res);
1308 if (groupdn == NULL) {
1309 goto out;
1312 status = ads_del_dn(ads, groupdn);
1313 if (!ADS_ERR_OK(status)) {
1314 d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
1315 ads_errstr(status));
1316 goto out;
1318 d_printf(_("Group %s deleted\n"), argv[0]);
1320 ret = 0;
1321 out:
1322 ads_msgfree(ads, res);
1323 TALLOC_FREE(tmp_ctx);
1324 return ret;
1327 int net_ads_group(struct net_context *c, int argc, const char **argv)
1329 struct functable func[] = {
1331 "add",
1332 ads_group_add,
1333 NET_TRANSPORT_ADS,
1334 N_("Add an AD group"),
1335 N_("net ads group add\n"
1336 " Add an AD group")
1339 "delete",
1340 ads_group_delete,
1341 NET_TRANSPORT_ADS,
1342 N_("Delete an AD group"),
1343 N_("net ads group delete\n"
1344 " Delete an AD group")
1346 {NULL, NULL, 0, NULL, NULL}
1348 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1349 ADS_STRUCT *ads = NULL;
1350 ADS_STATUS status;
1351 const char *shortattrs[] = {"sAMAccountName", NULL};
1352 const char *longattrs[] = {"sAMAccountName", "description", NULL};
1353 char *disp_fields[2] = {NULL, NULL};
1354 int ret = -1;
1356 if (argc >= 0) {
1357 TALLOC_FREE(tmp_ctx);
1358 return net_run_function(c, argc, argv, "net ads group", func);
1361 if (c->display_usage) {
1362 d_printf( "%s\n"
1363 "net ads group\n"
1364 " %s\n",
1365 _("Usage:"),
1366 _("List AD groups"));
1367 net_display_usage_from_functable(func);
1368 TALLOC_FREE(tmp_ctx);
1369 return -1;
1372 status = ads_startup(c, false, tmp_ctx, &ads);
1373 if (!ADS_ERR_OK(status)) {
1374 goto out;
1377 if (c->opt_long_list_entries)
1378 d_printf(_("\nGroup name Comment"
1379 "\n-----------------------------\n"));
1381 status = ads_do_search_all_fn(ads,
1382 ads->config.bind_path,
1383 LDAP_SCOPE_SUBTREE,
1384 "(objectCategory=group)",
1385 c->opt_long_list_entries ?
1386 longattrs : shortattrs,
1387 usergrp_display,
1388 disp_fields);
1389 if (!ADS_ERR_OK(status)) {
1390 goto out;
1393 ret = 0;
1394 out:
1395 TALLOC_FREE(tmp_ctx);
1396 return ret;
1399 static int net_ads_status(struct net_context *c, int argc, const char **argv)
1401 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1402 ADS_STRUCT *ads = NULL;
1403 ADS_STATUS status;
1404 LDAPMessage *res = NULL;
1405 int ret = -1;
1407 if (c->display_usage) {
1408 d_printf( "%s\n"
1409 "net ads status\n"
1410 " %s\n",
1411 _("Usage:"),
1412 _("Display machine account details"));
1413 TALLOC_FREE(tmp_ctx);
1414 return -1;
1417 status = ads_startup(c, true, tmp_ctx, &ads);
1418 if (!ADS_ERR_OK(status)) {
1419 goto out;
1422 status = ads_find_machine_acct(ads, &res, lp_netbios_name());
1423 if (!ADS_ERR_OK(status)) {
1424 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"),
1425 ads_errstr(status));
1426 goto out;
1429 if (ads_count_replies(ads, res) == 0) {
1430 d_fprintf(stderr, _("No machine account for '%s' found\n"),
1431 lp_netbios_name());
1432 goto out;
1435 ads_dump(ads, res);
1437 ret = 0;
1438 out:
1439 ads_msgfree(ads, res);
1440 TALLOC_FREE(tmp_ctx);
1441 return ret;
1444 /*******************************************************************
1445 Leave an AD domain. Windows XP disables the machine account.
1446 We'll try the same. The old code would do an LDAP delete.
1447 That only worked using the machine creds because added the machine
1448 with full control to the computer object's ACL.
1449 *******************************************************************/
1451 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
1453 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1454 struct libnet_UnjoinCtx *r = NULL;
1455 WERROR werr;
1456 int ret = -1;
1458 if (c->display_usage) {
1459 d_printf( "%s\n"
1460 "net ads leave [--keep-account]\n"
1461 " %s\n",
1462 _("Usage:"),
1463 _("Leave an AD domain"));
1464 TALLOC_FREE(tmp_ctx);
1465 return -1;
1468 if (!*lp_realm()) {
1469 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
1470 TALLOC_FREE(tmp_ctx);
1471 return -1;
1474 if (!c->opt_kerberos) {
1475 use_in_memory_ccache();
1478 if (!c->msg_ctx) {
1479 d_fprintf(stderr, _("Could not initialise message context. "
1480 "Try running as root\n"));
1481 goto done;
1484 werr = libnet_init_UnjoinCtx(tmp_ctx, &r);
1485 if (!W_ERROR_IS_OK(werr)) {
1486 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
1487 goto done;
1490 r->in.debug = true;
1491 r->in.use_kerberos = c->opt_kerberos;
1492 r->in.dc_name = c->opt_host;
1493 r->in.domain_name = lp_realm();
1494 r->in.admin_account = c->opt_user_name;
1495 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1496 r->in.modify_config = lp_config_backend_is_registry();
1498 /* Try to delete it, but if that fails, disable it. The
1499 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
1500 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1501 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
1502 if (c->opt_keep_account) {
1503 r->in.delete_machine_account = false;
1504 } else {
1505 r->in.delete_machine_account = true;
1508 r->in.msg_ctx = c->msg_ctx;
1510 werr = libnet_Unjoin(tmp_ctx, r);
1511 if (!W_ERROR_IS_OK(werr)) {
1512 d_printf(_("Failed to leave domain: %s\n"),
1513 r->out.error_string ? r->out.error_string :
1514 get_friendly_werror_msg(werr));
1515 goto done;
1518 if (r->out.deleted_machine_account) {
1519 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1520 r->in.machine_name, r->out.dns_domain_name);
1521 ret = 0;
1522 goto done;
1525 /* We couldn't delete it - see if the disable succeeded. */
1526 if (r->out.disabled_machine_account) {
1527 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1528 r->in.machine_name, r->out.dns_domain_name);
1529 ret = 0;
1530 goto done;
1533 /* Based on what we requested, we shouldn't get here, but if
1534 we did, it means the secrets were removed, and therefore
1535 we have left the domain */
1536 d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1537 r->in.machine_name, r->out.dns_domain_name);
1539 ret = 0;
1540 done:
1541 TALLOC_FREE(tmp_ctx);
1542 return ret;
1545 static ADS_STATUS net_ads_join_ok(struct net_context *c)
1547 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1548 ADS_STRUCT *ads = NULL;
1549 ADS_STATUS status;
1550 fstring dc_name;
1551 struct sockaddr_storage dcip;
1553 if (!secrets_init()) {
1554 DEBUG(1,("Failed to initialise secrets database\n"));
1555 TALLOC_FREE(tmp_ctx);
1556 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
1559 net_use_krb_machine_account(c);
1561 get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1563 status = ads_startup(c, true, tmp_ctx, &ads);
1564 if (!ADS_ERR_OK(status)) {
1565 goto out;
1568 status = ADS_ERROR_NT(NT_STATUS_OK);
1569 out:
1570 TALLOC_FREE(tmp_ctx);
1571 return status;
1575 check that an existing join is OK
1577 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1579 ADS_STATUS status;
1580 use_in_memory_ccache();
1582 if (c->display_usage) {
1583 d_printf( "%s\n"
1584 "net ads testjoin\n"
1585 " %s\n",
1586 _("Usage:"),
1587 _("Test if the existing join is ok"));
1588 return -1;
1591 /* Display success or failure */
1592 status = net_ads_join_ok(c);
1593 if (!ADS_ERR_OK(status)) {
1594 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1595 get_friendly_nt_error_msg(ads_ntstatus(status)));
1596 return -1;
1599 printf(_("Join is OK\n"));
1600 return 0;
1603 /*******************************************************************
1604 Simple config checks before beginning the join
1605 ********************************************************************/
1607 static WERROR check_ads_config( void )
1609 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1610 d_printf(_("Host is not configured as a member server.\n"));
1611 return WERR_INVALID_DOMAIN_ROLE;
1614 if (strlen(lp_netbios_name()) > 15) {
1615 d_printf(_("Our netbios name can be at most 15 chars long, "
1616 "\"%s\" is %u chars long\n"), lp_netbios_name(),
1617 (unsigned int)strlen(lp_netbios_name()));
1618 return WERR_INVALID_COMPUTERNAME;
1621 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1622 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1623 "join to succeed.\n"), get_dyn_CONFIGFILE());
1624 return WERR_INVALID_PARAMETER;
1627 return WERR_OK;
1630 /*******************************************************************
1631 ********************************************************************/
1633 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1635 d_printf(_("net ads join [--no-dns-updates] [options]\n"
1636 "Valid options:\n"));
1637 d_printf(_(" dnshostname=FQDN Set the dnsHostName attribute during the join.\n"
1638 " The default is in the form netbiosname.dnsdomain\n"));
1639 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1640 " The default UPN is in the form host/netbiosname@REALM.\n"));
1641 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1642 " The OU string read from top to bottom without RDNs\n"
1643 " and delimited by a '/'.\n"
1644 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1645 " NB: A backslash '\\' is used as escape at multiple\n"
1646 " levels and may need to be doubled or even\n"
1647 " quadrupled. It is not used as a separator.\n"));
1648 d_printf(_(" machinepass=PASS Set the machine password to a specific value during\n"
1649 " the join. The default password is random.\n"));
1650 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1651 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during join.\n"
1652 " NB: osName and osVer must be specified together for\n"
1653 " either to take effect. The operatingSystemService\n"
1654 " attribute is then also set along with the two\n"
1655 " other attributes.\n"));
1656 d_printf(_(" osServicePack=string Set the operatingSystemServicePack attribute\n"
1657 " during the join.\n"
1658 " NB: If not specified then by default the samba\n"
1659 " version string is used instead.\n"));
1660 return -1;
1664 int net_ads_join(struct net_context *c, int argc, const char **argv)
1666 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1667 struct libnet_JoinCtx *r = NULL;
1668 const char *domain = lp_realm();
1669 WERROR werr = WERR_NERR_SETUPNOTJOINED;
1670 bool createupn = false;
1671 const char *dnshostname = NULL;
1672 const char *machineupn = NULL;
1673 const char *machine_password = NULL;
1674 const char *create_in_ou = NULL;
1675 int i;
1676 const char *os_name = NULL;
1677 const char *os_version = NULL;
1678 const char *os_servicepack = NULL;
1679 bool modify_config = lp_config_backend_is_registry();
1680 enum libnetjoin_JoinDomNameType domain_name_type = JoinDomNameTypeDNS;
1681 int ret = -1;
1683 if (c->display_usage) {
1684 TALLOC_FREE(tmp_ctx);
1685 return net_ads_join_usage(c, argc, argv);
1688 if (!modify_config) {
1689 werr = check_ads_config();
1690 if (!W_ERROR_IS_OK(werr)) {
1691 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1692 goto fail;
1696 if (!c->opt_kerberos) {
1697 use_in_memory_ccache();
1700 werr = libnet_init_JoinCtx(tmp_ctx, &r);
1701 if (!W_ERROR_IS_OK(werr)) {
1702 goto fail;
1705 /* process additional command line args */
1707 for ( i=0; i<argc; i++ ) {
1708 if ( !strncasecmp_m(argv[i], "dnshostname", strlen("dnshostname")) ) {
1709 dnshostname = get_string_param(argv[i]);
1711 else if ( !strncasecmp_m(argv[i], "createupn", strlen("createupn")) ) {
1712 createupn = true;
1713 machineupn = get_string_param(argv[i]);
1715 else if ( !strncasecmp_m(argv[i], "createcomputer", strlen("createcomputer")) ) {
1716 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1717 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1718 werr = WERR_INVALID_PARAMETER;
1719 goto fail;
1722 else if ( !strncasecmp_m(argv[i], "osName", strlen("osName")) ) {
1723 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1724 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1725 werr = WERR_INVALID_PARAMETER;
1726 goto fail;
1729 else if ( !strncasecmp_m(argv[i], "osVer", strlen("osVer")) ) {
1730 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1731 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1732 werr = WERR_INVALID_PARAMETER;
1733 goto fail;
1736 else if ( !strncasecmp_m(argv[i], "osServicePack", strlen("osServicePack")) ) {
1737 if ( (os_servicepack = get_string_param(argv[i])) == NULL ) {
1738 d_fprintf(stderr, _("Please supply a valid servicepack identifier.\n"));
1739 werr = WERR_INVALID_PARAMETER;
1740 goto fail;
1743 else if ( !strncasecmp_m(argv[i], "machinepass", strlen("machinepass")) ) {
1744 if ( (machine_password = get_string_param(argv[i])) == NULL ) {
1745 d_fprintf(stderr, _("Please supply a valid password to set as trust account password.\n"));
1746 werr = WERR_INVALID_PARAMETER;
1747 goto fail;
1749 } else {
1750 domain = argv[i];
1751 if (strchr(domain, '.') == NULL) {
1752 domain_name_type = JoinDomNameTypeUnknown;
1753 } else {
1754 domain_name_type = JoinDomNameTypeDNS;
1759 if (!*domain) {
1760 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1761 werr = WERR_INVALID_PARAMETER;
1762 goto fail;
1765 if (!c->msg_ctx) {
1766 d_fprintf(stderr, _("Could not initialise message context. "
1767 "Try running as root\n"));
1768 werr = WERR_ACCESS_DENIED;
1769 goto fail;
1772 /* Do the domain join here */
1774 r->in.domain_name = domain;
1775 r->in.domain_name_type = domain_name_type;
1776 r->in.create_upn = createupn;
1777 r->in.upn = machineupn;
1778 r->in.dnshostname = dnshostname;
1779 r->in.account_ou = create_in_ou;
1780 r->in.os_name = os_name;
1781 r->in.os_version = os_version;
1782 r->in.os_servicepack = os_servicepack;
1783 r->in.dc_name = c->opt_host;
1784 r->in.admin_account = c->opt_user_name;
1785 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1786 r->in.machine_password = machine_password;
1787 r->in.debug = true;
1788 r->in.use_kerberos = c->opt_kerberos;
1789 r->in.modify_config = modify_config;
1790 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1791 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1792 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1793 r->in.msg_ctx = c->msg_ctx;
1795 werr = libnet_Join(tmp_ctx, r);
1796 if (W_ERROR_EQUAL(werr, WERR_NERR_DCNOTFOUND) &&
1797 strequal(domain, lp_realm())) {
1798 r->in.domain_name = lp_workgroup();
1799 r->in.domain_name_type = JoinDomNameTypeNBT;
1800 werr = libnet_Join(tmp_ctx, r);
1802 if (!W_ERROR_IS_OK(werr)) {
1803 goto fail;
1806 /* Check the short name of the domain */
1808 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1809 d_printf(_("The workgroup in %s does not match the short\n"
1810 "domain name obtained from the server.\n"
1811 "Using the name [%s] from the server.\n"
1812 "You should set \"workgroup = %s\" in %s.\n"),
1813 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1814 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1817 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1819 if (r->out.dns_domain_name) {
1820 d_printf(_("Joined '%s' to dns domain '%s'\n"), r->in.machine_name,
1821 r->out.dns_domain_name);
1822 } else {
1823 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1824 r->out.netbios_domain_name);
1827 /* print out informative error string in case there is one */
1828 if (r->out.error_string != NULL) {
1829 d_printf("%s\n", r->out.error_string);
1833 * We try doing the dns update (if it was compiled in
1834 * and if it was not disabled on the command line).
1835 * If the dns update fails, we still consider the join
1836 * operation as succeeded if we came this far.
1838 if (!c->opt_no_dns_updates) {
1839 net_ads_join_dns_updates(c, tmp_ctx, r);
1842 ret = 0;
1844 fail:
1845 if (ret != 0) {
1846 /* issue an overall failure message at the end. */
1847 d_printf(_("Failed to join domain: %s\n"),
1848 r && r->out.error_string ? r->out.error_string :
1849 get_friendly_werror_msg(werr));
1852 TALLOC_FREE(tmp_ctx);
1854 return ret;
1857 /*******************************************************************
1858 ********************************************************************/
1860 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1862 #if defined(HAVE_KRB5)
1863 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1864 ADS_STRUCT *ads = NULL;
1865 ADS_STATUS status;
1866 NTSTATUS ntstatus;
1867 const char *hostname = NULL;
1868 const char **addrs_list = NULL;
1869 struct sockaddr_storage *addrs = NULL;
1870 int num_addrs = 0;
1871 int count;
1872 int ret = -1;
1874 #ifdef DEVELOPER
1875 talloc_enable_leak_report();
1876 #endif
1878 if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
1879 d_fprintf(stderr, _("Refusing DNS updates with automatic "
1880 "detection of addresses in a clustered "
1881 "setup.\n"));
1882 c->display_usage = true;
1885 if (c->display_usage) {
1886 d_printf( "%s\n"
1887 "net ads dns register [hostname [IP [IP...]]]\n"
1888 " %s\n",
1889 _("Usage:"),
1890 _("Register hostname with DNS\n"));
1891 TALLOC_FREE(tmp_ctx);
1892 return -1;
1895 if (argc >= 1) {
1896 hostname = argv[0];
1899 if (argc > 1) {
1900 num_addrs = argc - 1;
1901 addrs_list = &argv[1];
1902 } else if (lp_clustering()) {
1903 addrs_list = lp_cluster_addresses();
1904 num_addrs = str_list_length(addrs_list);
1907 if (num_addrs > 0) {
1908 addrs = talloc_zero_array(tmp_ctx,
1909 struct sockaddr_storage,
1910 num_addrs);
1911 if (addrs == NULL) {
1912 d_fprintf(stderr, _("Error allocating memory!\n"));
1913 goto out;
1917 for (count = 0; count < num_addrs; count++) {
1918 if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
1919 d_fprintf(stderr, "%s '%s'.\n",
1920 _("Cannot interpret address"),
1921 addrs_list[count]);
1922 goto out;
1926 status = ads_startup(c, true, tmp_ctx, &ads);
1927 if ( !ADS_ERR_OK(status) ) {
1928 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1929 goto out;
1932 ntstatus = net_update_dns_ext(c,
1933 tmp_ctx,
1934 ads,
1935 hostname,
1936 addrs,
1937 num_addrs,
1938 false);
1939 if (!NT_STATUS_IS_OK(ntstatus)) {
1940 d_fprintf( stderr, _("DNS update failed!\n") );
1941 goto out;
1944 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1946 ret = 0;
1947 out:
1948 TALLOC_FREE(tmp_ctx);
1950 return ret;
1951 #else
1952 d_fprintf(stderr,
1953 _("DNS update support not enabled at compile time!\n"));
1954 return -1;
1955 #endif
1958 static int net_ads_dns_unregister(struct net_context *c,
1959 int argc,
1960 const char **argv)
1962 #if defined(HAVE_KRB5)
1963 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1964 ADS_STRUCT *ads = NULL;
1965 ADS_STATUS status;
1966 NTSTATUS ntstatus;
1967 const char *hostname = NULL;
1968 int ret = -1;
1970 #ifdef DEVELOPER
1971 talloc_enable_leak_report();
1972 #endif
1974 if (argc != 1) {
1975 c->display_usage = true;
1978 if (c->display_usage) {
1979 d_printf( "%s\n"
1980 "net ads dns unregister [hostname]\n"
1981 " %s\n",
1982 _("Usage:"),
1983 _("Remove all IP Address entires for a given\n"
1984 " hostname from the Active Directory server.\n"));
1985 TALLOC_FREE(tmp_ctx);
1986 return -1;
1989 /* Get the hostname for un-registering */
1990 hostname = argv[0];
1992 status = ads_startup(c, true, tmp_ctx, &ads);
1993 if ( !ADS_ERR_OK(status) ) {
1994 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1995 goto out;
1998 ntstatus = net_update_dns_ext(c,
1999 tmp_ctx,
2000 ads,
2001 hostname,
2002 NULL,
2004 true);
2005 if (!NT_STATUS_IS_OK(ntstatus)) {
2006 d_fprintf( stderr, _("DNS update failed!\n") );
2007 goto out;
2010 d_fprintf( stderr, _("Successfully un-registered hostname from DNS\n"));
2012 ret = 0;
2013 out:
2014 TALLOC_FREE(tmp_ctx);
2016 return ret;
2017 #else
2018 d_fprintf(stderr,
2019 _("DNS update support not enabled at compile time!\n"));
2020 return -1;
2021 #endif
2025 static int net_ads_dns_async(struct net_context *c, int argc, const char **argv)
2027 size_t num_names = 0;
2028 char **hostnames = NULL;
2029 size_t i = 0;
2030 struct samba_sockaddr *addrs = NULL;
2031 NTSTATUS status;
2033 if (argc != 1 || c->display_usage) {
2034 d_printf( "%s\n"
2035 " %s\n"
2036 " %s\n",
2037 _("Usage:"),
2038 _("net ads dns async <name>\n"),
2039 _(" Async look up hostname from the DNS server\n"
2040 " hostname\tName to look up\n"));
2041 return -1;
2044 status = ads_dns_lookup_a(talloc_tos(),
2045 argv[0],
2046 &num_names,
2047 &hostnames,
2048 &addrs);
2049 if (!NT_STATUS_IS_OK(status)) {
2050 d_printf("Looking up A record for %s got error %s\n",
2051 argv[0],
2052 nt_errstr(status));
2053 return -1;
2055 d_printf("Async A record lookup - got %u names for %s\n",
2056 (unsigned int)num_names,
2057 argv[0]);
2058 for (i = 0; i < num_names; i++) {
2059 char addr_buf[INET6_ADDRSTRLEN];
2060 print_sockaddr(addr_buf,
2061 sizeof(addr_buf),
2062 &addrs[i].u.ss);
2063 d_printf("hostname[%u] = %s, IPv4addr = %s\n",
2064 (unsigned int)i,
2065 hostnames[i],
2066 addr_buf);
2069 #if defined(HAVE_IPV6)
2070 status = ads_dns_lookup_aaaa(talloc_tos(),
2071 argv[0],
2072 &num_names,
2073 &hostnames,
2074 &addrs);
2075 if (!NT_STATUS_IS_OK(status)) {
2076 d_printf("Looking up AAAA record for %s got error %s\n",
2077 argv[0],
2078 nt_errstr(status));
2079 return -1;
2081 d_printf("Async AAAA record lookup - got %u names for %s\n",
2082 (unsigned int)num_names,
2083 argv[0]);
2084 for (i = 0; i < num_names; i++) {
2085 char addr_buf[INET6_ADDRSTRLEN];
2086 print_sockaddr(addr_buf,
2087 sizeof(addr_buf),
2088 &addrs[i].u.ss);
2089 d_printf("hostname[%u] = %s, IPv6addr = %s\n",
2090 (unsigned int)i,
2091 hostnames[i],
2092 addr_buf);
2094 #endif
2095 return 0;
2099 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
2101 struct functable func[] = {
2103 "register",
2104 net_ads_dns_register,
2105 NET_TRANSPORT_ADS,
2106 N_("Add host dns entry to AD"),
2107 N_("net ads dns register\n"
2108 " Add host dns entry to AD")
2111 "unregister",
2112 net_ads_dns_unregister,
2113 NET_TRANSPORT_ADS,
2114 N_("Remove host dns entry from AD"),
2115 N_("net ads dns unregister\n"
2116 " Remove host dns entry from AD")
2119 "async",
2120 net_ads_dns_async,
2121 NET_TRANSPORT_ADS,
2122 N_("Look up host"),
2123 N_("net ads dns async\n"
2124 " Look up host using async DNS")
2126 {NULL, NULL, 0, NULL, NULL}
2129 return net_run_function(c, argc, argv, "net ads dns", func);
2132 /*******************************************************************
2133 ********************************************************************/
2135 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
2137 d_printf(_(
2138 "\nnet ads printer search <printer>"
2139 "\n\tsearch for a printer in the directory\n"
2140 "\nnet ads printer info <printer> <server>"
2141 "\n\tlookup info in directory for printer on server"
2142 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
2143 "\nnet ads printer publish <printername>"
2144 "\n\tpublish printer in directory"
2145 "\n\t(note: printer name is required)\n"
2146 "\nnet ads printer remove <printername>"
2147 "\n\tremove printer from directory"
2148 "\n\t(note: printer name is required)\n"));
2149 return -1;
2152 /*******************************************************************
2153 ********************************************************************/
2155 static int net_ads_printer_search(struct net_context *c,
2156 int argc,
2157 const char **argv)
2159 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2160 ADS_STRUCT *ads = NULL;
2161 ADS_STATUS status;
2162 LDAPMessage *res = NULL;
2163 int ret = -1;
2165 if (c->display_usage) {
2166 d_printf( "%s\n"
2167 "net ads printer search\n"
2168 " %s\n",
2169 _("Usage:"),
2170 _("List printers in the AD"));
2171 TALLOC_FREE(tmp_ctx);
2172 return -1;
2175 status = ads_startup(c, false, tmp_ctx, &ads);
2176 if (!ADS_ERR_OK(status)) {
2177 goto out;
2180 status = ads_find_printers(ads, &res);
2181 if (!ADS_ERR_OK(status)) {
2182 d_fprintf(stderr, _("ads_find_printer: %s\n"),
2183 ads_errstr(status));
2184 goto out;
2187 if (ads_count_replies(ads, res) == 0) {
2188 d_fprintf(stderr, _("No results found\n"));
2189 goto out;
2192 ads_dump(ads, res);
2194 ret = 0;
2195 out:
2196 ads_msgfree(ads, res);
2197 TALLOC_FREE(tmp_ctx);
2198 return ret;
2201 static int net_ads_printer_info(struct net_context *c,
2202 int argc,
2203 const char **argv)
2205 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2206 ADS_STRUCT *ads = NULL;
2207 ADS_STATUS status;
2208 const char *servername = NULL;
2209 const char *printername = NULL;
2210 LDAPMessage *res = NULL;
2211 int ret = -1;
2213 if (c->display_usage) {
2214 d_printf("%s\n%s",
2215 _("Usage:"),
2216 _("net ads printer info [printername [servername]]\n"
2217 " Display printer info from AD\n"
2218 " printername\tPrinter name or wildcard\n"
2219 " servername\tName of the print server\n"));
2220 TALLOC_FREE(tmp_ctx);
2221 return -1;
2224 status = ads_startup(c, false, tmp_ctx, &ads);
2225 if (!ADS_ERR_OK(status)) {
2226 goto out;
2229 if (argc > 0) {
2230 printername = argv[0];
2231 } else {
2232 printername = "*";
2235 if (argc > 1) {
2236 servername = argv[1];
2237 } else {
2238 servername = lp_netbios_name();
2241 status = ads_find_printer_on_server(ads, &res, printername, servername);
2242 if (!ADS_ERR_OK(status)) {
2243 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
2244 servername, ads_errstr(status));
2245 goto out;
2248 if (ads_count_replies(ads, res) == 0) {
2249 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
2250 goto out;
2253 ads_dump(ads, res);
2255 ret = 0;
2256 out:
2257 ads_msgfree(ads, res);
2258 TALLOC_FREE(tmp_ctx);
2259 return ret;
2262 static int net_ads_printer_publish(struct net_context *c,
2263 int argc,
2264 const char **argv)
2266 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2267 ADS_STRUCT *ads = NULL;
2268 ADS_STATUS status;
2269 const char *servername = NULL;
2270 const char *printername = NULL;
2271 struct cli_state *cli = NULL;
2272 struct rpc_pipe_client *pipe_hnd = NULL;
2273 struct sockaddr_storage server_ss = { 0 };
2274 NTSTATUS nt_status;
2275 ADS_MODLIST mods = NULL;
2276 char *prt_dn = NULL;
2277 char *srv_dn = NULL;
2278 char **srv_cn = NULL;
2279 char *srv_cn_escaped = NULL;
2280 char *printername_escaped = NULL;
2281 LDAPMessage *res = NULL;
2282 bool ok;
2283 int ret = -1;
2285 if (argc < 1 || c->display_usage) {
2286 d_printf("%s\n%s",
2287 _("Usage:"),
2288 _("net ads printer publish <printername> [servername]\n"
2289 " Publish printer in AD\n"
2290 " printername\tName of the printer\n"
2291 " servername\tName of the print server\n"));
2292 TALLOC_FREE(tmp_ctx);
2293 return -1;
2296 mods = ads_init_mods(tmp_ctx);
2297 if (mods == NULL) {
2298 d_fprintf(stderr, _("Out of memory\n"));
2299 goto out;
2302 status = ads_startup(c, true, tmp_ctx, &ads);
2303 if (!ADS_ERR_OK(status)) {
2304 goto out;
2307 printername = argv[0];
2309 if (argc == 2) {
2310 servername = argv[1];
2311 } else {
2312 servername = lp_netbios_name();
2315 /* Get printer data from SPOOLSS */
2317 ok = resolve_name(servername, &server_ss, 0x20, false);
2318 if (!ok) {
2319 d_fprintf(stderr, _("Could not find server %s\n"),
2320 servername);
2321 goto out;
2324 cli_credentials_set_kerberos_state(c->creds,
2325 CRED_USE_KERBEROS_REQUIRED,
2326 CRED_SPECIFIED);
2328 nt_status = cli_full_connection_creds(&cli, lp_netbios_name(), servername,
2329 &server_ss, 0,
2330 "IPC$", "IPC",
2331 c->creds,
2332 CLI_FULL_CONNECTION_IPC);
2334 if (NT_STATUS_IS_ERR(nt_status)) {
2335 d_fprintf(stderr, _("Unable to open a connection to %s to "
2336 "obtain data for %s\n"),
2337 servername, printername);
2338 goto out;
2341 /* Publish on AD server */
2343 ads_find_machine_acct(ads, &res, servername);
2345 if (ads_count_replies(ads, res) == 0) {
2346 d_fprintf(stderr, _("Could not find machine account for server "
2347 "%s\n"),
2348 servername);
2349 goto out;
2352 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
2353 srv_cn = ldap_explode_dn(srv_dn, 1);
2355 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
2356 printername_escaped = escape_rdn_val_string_alloc(printername);
2357 if (!srv_cn_escaped || !printername_escaped) {
2358 SAFE_FREE(srv_cn_escaped);
2359 SAFE_FREE(printername_escaped);
2360 d_fprintf(stderr, _("Internal error, out of memory!"));
2361 goto out;
2364 prt_dn = talloc_asprintf(tmp_ctx,
2365 "cn=%s-%s,%s",
2366 srv_cn_escaped,
2367 printername_escaped,
2368 srv_dn);
2369 if (prt_dn == NULL) {
2370 SAFE_FREE(srv_cn_escaped);
2371 SAFE_FREE(printername_escaped);
2372 d_fprintf(stderr, _("Internal error, out of memory!"));
2373 goto out;
2376 SAFE_FREE(srv_cn_escaped);
2377 SAFE_FREE(printername_escaped);
2379 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss, &pipe_hnd);
2380 if (!NT_STATUS_IS_OK(nt_status)) {
2381 d_fprintf(stderr, _("Unable to open a connection to the spoolss pipe on %s\n"),
2382 servername);
2383 goto out;
2386 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd,
2387 tmp_ctx,
2388 &mods,
2389 printername))) {
2390 goto out;
2393 status = ads_add_printer_entry(ads, prt_dn, tmp_ctx, &mods);
2394 if (!ADS_ERR_OK(status)) {
2395 d_fprintf(stderr, "ads_publish_printer: %s\n",
2396 ads_errstr(status));
2397 goto out;
2400 d_printf("published printer\n");
2402 ret = 0;
2403 out:
2404 talloc_destroy(tmp_ctx);
2406 return ret;
2409 static int net_ads_printer_remove(struct net_context *c,
2410 int argc,
2411 const char **argv)
2413 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2414 ADS_STRUCT *ads = NULL;
2415 ADS_STATUS status;
2416 const char *servername = NULL;
2417 char *prt_dn = NULL;
2418 LDAPMessage *res = NULL;
2419 int ret = -1;
2421 if (argc < 1 || c->display_usage) {
2422 d_printf("%s\n%s",
2423 _("Usage:"),
2424 _("net ads printer remove <printername> [servername]\n"
2425 " Remove a printer from the AD\n"
2426 " printername\tName of the printer\n"
2427 " servername\tName of the print server\n"));
2428 TALLOC_FREE(tmp_ctx);
2429 return -1;
2432 status = ads_startup(c, true, tmp_ctx, &ads);
2433 if (!ADS_ERR_OK(status)) {
2434 goto out;
2437 if (argc > 1) {
2438 servername = argv[1];
2439 } else {
2440 servername = lp_netbios_name();
2443 status = ads_find_printer_on_server(ads, &res, argv[0], servername);
2444 if (!ADS_ERR_OK(status)) {
2445 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"),
2446 ads_errstr(status));
2447 goto out;
2450 if (ads_count_replies(ads, res) == 0) {
2451 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
2452 goto out;
2455 prt_dn = ads_get_dn(ads, tmp_ctx, res);
2456 if (prt_dn == NULL) {
2457 d_fprintf(stderr, _("Out of memory\n"));
2458 goto out;
2461 status = ads_del_dn(ads, prt_dn);
2462 if (!ADS_ERR_OK(status)) {
2463 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(status));
2464 goto out;
2467 ret = 0;
2468 out:
2469 ads_msgfree(ads, res);
2470 TALLOC_FREE(tmp_ctx);
2471 return ret;
2474 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
2476 struct functable func[] = {
2478 "search",
2479 net_ads_printer_search,
2480 NET_TRANSPORT_ADS,
2481 N_("Search for a printer"),
2482 N_("net ads printer search\n"
2483 " Search for a printer")
2486 "info",
2487 net_ads_printer_info,
2488 NET_TRANSPORT_ADS,
2489 N_("Display printer information"),
2490 N_("net ads printer info\n"
2491 " Display printer information")
2494 "publish",
2495 net_ads_printer_publish,
2496 NET_TRANSPORT_ADS,
2497 N_("Publish a printer"),
2498 N_("net ads printer publish\n"
2499 " Publish a printer")
2502 "remove",
2503 net_ads_printer_remove,
2504 NET_TRANSPORT_ADS,
2505 N_("Delete a printer"),
2506 N_("net ads printer remove\n"
2507 " Delete a printer")
2509 {NULL, NULL, 0, NULL, NULL}
2512 return net_run_function(c, argc, argv, "net ads printer", func);
2516 static int net_ads_password(struct net_context *c, int argc, const char **argv)
2518 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2519 ADS_STRUCT *ads = NULL;
2520 const char *auth_principal = cli_credentials_get_username(c->creds);
2521 const char *auth_password = cli_credentials_get_password(c->creds);
2522 const char *realm = NULL;
2523 char *new_password = NULL;
2524 char *chr = NULL;
2525 char *prompt = NULL;
2526 const char *user = NULL;
2527 char pwd[256] = {0};
2528 ADS_STATUS status;
2529 int ret = 0;
2531 if (c->display_usage) {
2532 d_printf("%s\n%s",
2533 _("Usage:"),
2534 _("net ads password <username>\n"
2535 " Change password for user\n"
2536 " username\tName of user to change password for\n"));
2537 TALLOC_FREE(tmp_ctx);
2538 return -1;
2541 if (auth_principal == NULL || auth_password == NULL) {
2542 d_fprintf(stderr, _("You must supply an administrator "
2543 "username/password\n"));
2544 TALLOC_FREE(tmp_ctx);
2545 return -1;
2548 if (argc < 1) {
2549 d_fprintf(stderr, _("ERROR: You must say which username to "
2550 "change password for\n"));
2551 TALLOC_FREE(tmp_ctx);
2552 return -1;
2555 if (strchr_m(argv[0], '@')) {
2556 user = talloc_strdup(tmp_ctx, argv[0]);
2557 } else {
2558 user = talloc_asprintf(tmp_ctx, "%s@%s", argv[0], lp_realm());
2560 if (user == NULL) {
2561 d_fprintf(stderr, _("Out of memory\n"));
2562 goto out;
2565 use_in_memory_ccache();
2566 chr = strchr_m(auth_principal, '@');
2567 if (chr) {
2568 realm = ++chr;
2569 } else {
2570 realm = lp_realm();
2573 /* use the realm so we can eventually change passwords for users
2574 in realms other than default */
2575 ads = ads_init(tmp_ctx,
2576 realm,
2577 c->opt_workgroup,
2578 c->opt_host,
2579 ADS_SASL_PLAIN);
2580 if (ads == NULL) {
2581 goto out;
2584 /* we don't actually need a full connect, but it's the easy way to
2585 fill in the KDC's addresss */
2586 ads_connect(ads);
2588 if (!ads->config.realm) {
2589 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
2590 goto out;
2593 if (argv[1] != NULL) {
2594 new_password = talloc_strdup(tmp_ctx, argv[1]);
2595 } else {
2596 int rc;
2598 prompt = talloc_asprintf(tmp_ctx, _("Enter new password for %s:"), user);
2599 if (prompt == NULL) {
2600 d_fprintf(stderr, _("Out of memory\n"));
2601 goto out;
2604 rc = samba_getpass(prompt, pwd, sizeof(pwd), false, true);
2605 if (rc < 0) {
2606 goto out;
2608 new_password = talloc_strdup(tmp_ctx, pwd);
2609 memset(pwd, '\0', sizeof(pwd));
2612 if (new_password == NULL) {
2613 d_fprintf(stderr, _("Out of memory\n"));
2614 goto out;
2617 status = kerberos_set_password(ads->auth.kdc_server,
2618 auth_principal,
2619 auth_password,
2620 user,
2621 new_password,
2622 ads->auth.time_offset);
2623 memset(new_password, '\0', strlen(new_password));
2624 if (!ADS_ERR_OK(status)) {
2625 d_fprintf(stderr, _("Password change failed: %s\n"),
2626 ads_errstr(status));
2627 goto out;
2630 d_printf(_("Password change for %s completed.\n"), user);
2632 ret = 0;
2633 out:
2634 TALLOC_FREE(tmp_ctx);
2635 return ret;
2638 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2640 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2641 ADS_STRUCT *ads = NULL;
2642 char *host_principal = NULL;
2643 char *my_name = NULL;
2644 ADS_STATUS status;
2645 int ret = -1;
2647 if (c->display_usage) {
2648 d_printf( "%s\n"
2649 "net ads changetrustpw\n"
2650 " %s\n",
2651 _("Usage:"),
2652 _("Change the machine account's trust password"));
2653 TALLOC_FREE(tmp_ctx);
2654 return -1;
2657 if (!secrets_init()) {
2658 DEBUG(1,("Failed to initialise secrets database\n"));
2659 goto out;
2662 net_use_krb_machine_account(c);
2664 use_in_memory_ccache();
2666 status = ads_startup(c, true, tmp_ctx, &ads);
2667 if (!ADS_ERR_OK(status)) {
2668 goto out;
2671 my_name = talloc_asprintf_strlower_m(tmp_ctx, "%s", lp_netbios_name());
2672 if (my_name == NULL) {
2673 d_fprintf(stderr, _("Out of memory\n"));
2674 goto out;
2677 host_principal = talloc_asprintf(tmp_ctx, "%s$@%s", my_name, ads->config.realm);
2678 if (host_principal == NULL) {
2679 d_fprintf(stderr, _("Out of memory\n"));
2680 goto out;
2683 d_printf(_("Changing password for principal: %s\n"), host_principal);
2685 status = ads_change_trust_account_password(ads, host_principal);
2686 if (!ADS_ERR_OK(status)) {
2687 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(status));
2688 goto out;
2691 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2693 if (USE_SYSTEM_KEYTAB) {
2694 d_printf(_("Attempting to update system keytab with new password.\n"));
2695 if (ads_keytab_create_default(ads)) {
2696 d_printf(_("Failed to update system keytab.\n"));
2700 ret = 0;
2701 out:
2702 TALLOC_FREE(tmp_ctx);
2704 return ret;
2708 help for net ads search
2710 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2712 d_printf(_(
2713 "\nnet ads search <expression> <attributes...>\n"
2714 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2715 "The expression is a standard LDAP search expression, and the\n"
2716 "attributes are a list of LDAP fields to show in the results.\n\n"
2717 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2719 net_common_flags_usage(c, argc, argv);
2720 return -1;
2725 general ADS search function. Useful in diagnosing problems in ADS
2727 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2729 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2730 ADS_STRUCT *ads = NULL;
2731 ADS_STATUS status;
2732 const char *ldap_exp = NULL;
2733 const char **attrs = NULL;
2734 LDAPMessage *res = NULL;
2735 int ret = -1;
2737 if (argc < 1 || c->display_usage) {
2738 TALLOC_FREE(tmp_ctx);
2739 return net_ads_search_usage(c, argc, argv);
2742 status = ads_startup(c, false, tmp_ctx, &ads);
2743 if (!ADS_ERR_OK(status)) {
2744 goto out;
2747 ldap_exp = argv[0];
2748 attrs = (argv + 1);
2750 status = ads_do_search_retry(ads,
2751 ads->config.bind_path,
2752 LDAP_SCOPE_SUBTREE,
2753 ldap_exp,
2754 attrs,
2755 &res);
2756 if (!ADS_ERR_OK(status)) {
2757 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(status));
2758 goto out;
2761 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2763 /* dump the results */
2764 ads_dump(ads, res);
2766 ret = 0;
2767 out:
2768 ads_msgfree(ads, res);
2769 TALLOC_FREE(tmp_ctx);
2770 return ret;
2775 help for net ads search
2777 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2779 d_printf(_(
2780 "\nnet ads dn <dn> <attributes...>\n"
2781 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2782 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2783 "to show in the results\n\n"
2784 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2785 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2787 net_common_flags_usage(c, argc, argv);
2788 return -1;
2793 general ADS search function. Useful in diagnosing problems in ADS
2795 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2797 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2798 ADS_STRUCT *ads = NULL;
2799 ADS_STATUS status;
2800 const char *dn = NULL;
2801 const char **attrs = NULL;
2802 LDAPMessage *res = NULL;
2803 int ret = -1;
2805 if (argc < 1 || c->display_usage) {
2806 TALLOC_FREE(tmp_ctx);
2807 return net_ads_dn_usage(c, argc, argv);
2810 status = ads_startup(c, false, tmp_ctx, &ads);
2811 if (!ADS_ERR_OK(status)) {
2812 goto out;
2815 dn = argv[0];
2816 attrs = (argv + 1);
2818 status = ads_do_search_all(ads,
2820 LDAP_SCOPE_BASE,
2821 "(objectclass=*)",
2822 attrs,
2823 &res);
2824 if (!ADS_ERR_OK(status)) {
2825 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(status));
2826 goto out;
2829 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2831 /* dump the results */
2832 ads_dump(ads, res);
2834 ret = 0;
2835 out:
2836 ads_msgfree(ads, res);
2837 TALLOC_FREE(tmp_ctx);
2838 return ret;
2842 help for net ads sid search
2844 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2846 d_printf(_(
2847 "\nnet ads sid <sid> <attributes...>\n"
2848 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2849 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2850 "to show in the results\n\n"
2851 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2853 net_common_flags_usage(c, argc, argv);
2854 return -1;
2859 general ADS search function. Useful in diagnosing problems in ADS
2861 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2863 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2864 ADS_STRUCT *ads = NULL;
2865 ADS_STATUS status;
2866 const char *sid_string = NULL;
2867 const char **attrs = NULL;
2868 LDAPMessage *res = NULL;
2869 struct dom_sid sid = { 0 };
2870 int ret = -1;
2872 if (argc < 1 || c->display_usage) {
2873 TALLOC_FREE(tmp_ctx);
2874 return net_ads_sid_usage(c, argc, argv);
2877 status = ads_startup(c, false, tmp_ctx, &ads);
2878 if (!ADS_ERR_OK(status)) {
2879 goto out;
2882 sid_string = argv[0];
2883 attrs = (argv + 1);
2885 if (!string_to_sid(&sid, sid_string)) {
2886 d_fprintf(stderr, _("could not convert sid\n"));
2887 goto out;
2890 status = ads_search_retry_sid(ads, &res, &sid, attrs);
2891 if (!ADS_ERR_OK(status)) {
2892 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(status));
2893 goto out;
2896 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2898 /* dump the results */
2899 ads_dump(ads, res);
2901 ret = 0;
2902 out:
2903 ads_msgfree(ads, res);
2904 TALLOC_FREE(tmp_ctx);
2905 return ret;
2908 static int net_ads_keytab_flush(struct net_context *c,
2909 int argc,
2910 const char **argv)
2912 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2913 ADS_STRUCT *ads = NULL;
2914 ADS_STATUS status;
2915 int ret = -1;
2917 if (c->display_usage) {
2918 d_printf( "%s\n"
2919 "net ads keytab flush\n"
2920 " %s\n",
2921 _("Usage:"),
2922 _("Delete the whole keytab"));
2923 TALLOC_FREE(tmp_ctx);
2924 return -1;
2927 if (!c->opt_user_specified && c->opt_password == NULL) {
2928 net_use_krb_machine_account(c);
2931 status = ads_startup(c, true, tmp_ctx, &ads);
2932 if (!ADS_ERR_OK(status)) {
2933 goto out;
2936 ret = ads_keytab_flush(ads);
2937 out:
2938 TALLOC_FREE(tmp_ctx);
2939 return ret;
2942 static int net_ads_keytab_add(struct net_context *c,
2943 int argc,
2944 const char **argv,
2945 bool update_ads)
2947 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2948 ADS_STRUCT *ads = NULL;
2949 ADS_STATUS status;
2950 int i;
2951 int ret = -1;
2953 if (c->display_usage) {
2954 d_printf("%s\n%s",
2955 _("Usage:"),
2956 _("net ads keytab add <principal> [principal ...]\n"
2957 " Add principals to local keytab\n"
2958 " principal\tKerberos principal to add to "
2959 "keytab\n"));
2960 TALLOC_FREE(tmp_ctx);
2961 return -1;
2964 d_printf(_("Processing principals to add...\n"));
2966 if (!c->opt_user_specified && c->opt_password == NULL) {
2967 net_use_krb_machine_account(c);
2970 status = ads_startup(c, true, tmp_ctx, &ads);
2971 if (!ADS_ERR_OK(status)) {
2972 goto out;
2975 for (ret = 0, i = 0; i < argc; i++) {
2976 ret |= ads_keytab_add_entry(ads, argv[i], update_ads);
2978 out:
2979 TALLOC_FREE(tmp_ctx);
2980 return ret;
2983 static int net_ads_keytab_add_default(struct net_context *c,
2984 int argc,
2985 const char **argv)
2987 return net_ads_keytab_add(c, argc, argv, false);
2990 static int net_ads_keytab_add_update_ads(struct net_context *c,
2991 int argc,
2992 const char **argv)
2994 return net_ads_keytab_add(c, argc, argv, true);
2997 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2999 TALLOC_CTX *tmp_ctx = talloc_stackframe();
3000 ADS_STRUCT *ads = NULL;
3001 ADS_STATUS status;
3002 int ret = -1;
3004 if (c->display_usage) {
3005 d_printf( "%s\n"
3006 "net ads keytab create\n"
3007 " %s\n",
3008 _("Usage:"),
3009 _("Create new default keytab"));
3010 TALLOC_FREE(tmp_ctx);
3011 return -1;
3014 if (!c->opt_user_specified && c->opt_password == NULL) {
3015 net_use_krb_machine_account(c);
3018 status = ads_startup(c, true, tmp_ctx, &ads);
3019 if (!ADS_ERR_OK(status)) {
3020 goto out;
3023 ret = ads_keytab_create_default(ads);
3024 out:
3025 TALLOC_FREE(tmp_ctx);
3026 return ret;
3029 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
3031 const char *keytab = NULL;
3033 if (c->display_usage) {
3034 d_printf("%s\n%s",
3035 _("Usage:"),
3036 _("net ads keytab list [keytab]\n"
3037 " List a local keytab\n"
3038 " keytab\tKeytab to list\n"));
3039 return -1;
3042 if (argc >= 1) {
3043 keytab = argv[0];
3046 return ads_keytab_list(keytab);
3050 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
3052 struct functable func[] = {
3054 "add",
3055 net_ads_keytab_add_default,
3056 NET_TRANSPORT_ADS,
3057 N_("Add a service principal"),
3058 N_("net ads keytab add\n"
3059 " Add a service principal, updates keytab file only.")
3062 "add_update_ads",
3063 net_ads_keytab_add_update_ads,
3064 NET_TRANSPORT_ADS,
3065 N_("Add a service principal"),
3066 N_("net ads keytab add_update_ads\n"
3067 " Add a service principal, depending on the param passed may update ADS computer object in addition to the keytab file.")
3070 "create",
3071 net_ads_keytab_create,
3072 NET_TRANSPORT_ADS,
3073 N_("Create a fresh keytab"),
3074 N_("net ads keytab create\n"
3075 " Create a fresh keytab or update existing one.")
3078 "flush",
3079 net_ads_keytab_flush,
3080 NET_TRANSPORT_ADS,
3081 N_("Remove all keytab entries"),
3082 N_("net ads keytab flush\n"
3083 " Remove all keytab entries")
3086 "list",
3087 net_ads_keytab_list,
3088 NET_TRANSPORT_ADS,
3089 N_("List a keytab"),
3090 N_("net ads keytab list\n"
3091 " List a keytab")
3093 {NULL, NULL, 0, NULL, NULL}
3096 if (!USE_KERBEROS_KEYTAB) {
3097 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
3098 "keytab method to use keytab functions.\n"));
3101 return net_run_function(c, argc, argv, "net ads keytab", func);
3104 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
3106 int ret = -1;
3108 if (c->display_usage) {
3109 d_printf( "%s\n"
3110 "net ads kerberos renew\n"
3111 " %s\n",
3112 _("Usage:"),
3113 _("Renew TGT from existing credential cache"));
3114 return -1;
3117 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
3118 if (ret) {
3119 d_printf(_("failed to renew kerberos ticket: %s\n"),
3120 error_message(ret));
3122 return ret;
3125 static int net_ads_kerberos_pac_common(struct net_context *c, int argc, const char **argv,
3126 struct PAC_DATA_CTR **pac_data_ctr)
3128 NTSTATUS status;
3129 int ret = -1;
3130 const char *impersonate_princ_s = NULL;
3131 const char *local_service = NULL;
3132 int i;
3134 for (i=0; i<argc; i++) {
3135 if (strnequal(argv[i], "impersonate", strlen("impersonate"))) {
3136 impersonate_princ_s = get_string_param(argv[i]);
3137 if (impersonate_princ_s == NULL) {
3138 return -1;
3141 if (strnequal(argv[i], "local_service", strlen("local_service"))) {
3142 local_service = get_string_param(argv[i]);
3143 if (local_service == NULL) {
3144 return -1;
3149 if (local_service == NULL) {
3150 local_service = talloc_asprintf(c, "%s$@%s",
3151 lp_netbios_name(), lp_realm());
3152 if (local_service == NULL) {
3153 goto out;
3157 c->opt_password = net_prompt_pass(c, c->opt_user_name);
3159 status = kerberos_return_pac(c,
3160 c->opt_user_name,
3161 c->opt_password,
3163 NULL,
3164 NULL,
3165 NULL,
3166 true,
3167 true,
3168 2592000, /* one month */
3169 impersonate_princ_s,
3170 local_service,
3171 NULL,
3172 NULL,
3173 pac_data_ctr);
3174 if (!NT_STATUS_IS_OK(status)) {
3175 d_printf(_("failed to query kerberos PAC: %s\n"),
3176 nt_errstr(status));
3177 goto out;
3180 ret = 0;
3181 out:
3182 return ret;
3185 static int net_ads_kerberos_pac_dump(struct net_context *c, int argc, const char **argv)
3187 struct PAC_DATA_CTR *pac_data_ctr = NULL;
3188 int i, num_buffers;
3189 int ret = -1;
3190 enum PAC_TYPE type = 0;
3192 if (c->display_usage) {
3193 d_printf( "%s\n"
3194 "net ads kerberos pac dump [impersonate=string] [local_service=string] [pac_buffer_type=int]\n"
3195 " %s\n",
3196 _("Usage:"),
3197 _("Dump the Kerberos PAC"));
3198 return -1;
3201 for (i=0; i<argc; i++) {
3202 if (strnequal(argv[i], "pac_buffer_type", strlen("pac_buffer_type"))) {
3203 type = get_int_param(argv[i]);
3207 ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3208 if (ret) {
3209 return ret;
3212 if (type == 0) {
3214 char *s = NULL;
3216 s = NDR_PRINT_STRUCT_STRING(c, PAC_DATA,
3217 pac_data_ctr->pac_data);
3218 if (s != NULL) {
3219 d_printf(_("The Pac: %s\n"), s);
3220 talloc_free(s);
3223 return 0;
3226 num_buffers = pac_data_ctr->pac_data->num_buffers;
3228 for (i=0; i<num_buffers; i++) {
3230 char *s = NULL;
3232 if (pac_data_ctr->pac_data->buffers[i].type != type) {
3233 continue;
3236 s = NDR_PRINT_UNION_STRING(c, PAC_INFO, type,
3237 pac_data_ctr->pac_data->buffers[i].info);
3238 if (s != NULL) {
3239 d_printf(_("The Pac: %s\n"), s);
3240 talloc_free(s);
3242 break;
3245 return 0;
3248 static int net_ads_kerberos_pac_save(struct net_context *c, int argc, const char **argv)
3250 struct PAC_DATA_CTR *pac_data_ctr = NULL;
3251 char *filename = NULL;
3252 int ret = -1;
3253 int i;
3255 if (c->display_usage) {
3256 d_printf( "%s\n"
3257 "net ads kerberos pac save [impersonate=string] [local_service=string] [filename=string]\n"
3258 " %s\n",
3259 _("Usage:"),
3260 _("Save the Kerberos PAC"));
3261 return -1;
3264 for (i=0; i<argc; i++) {
3265 if (strnequal(argv[i], "filename", strlen("filename"))) {
3266 filename = get_string_param(argv[i]);
3267 if (filename == NULL) {
3268 return -1;
3273 ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3274 if (ret) {
3275 return ret;
3278 if (filename == NULL) {
3279 d_printf(_("please define \"filename=<filename>\" to save the PAC\n"));
3280 return -1;
3283 /* save the raw format */
3284 if (!file_save(filename, pac_data_ctr->pac_blob.data, pac_data_ctr->pac_blob.length)) {
3285 d_printf(_("failed to save PAC in %s\n"), filename);
3286 return -1;
3289 return 0;
3292 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
3294 struct functable func[] = {
3296 "dump",
3297 net_ads_kerberos_pac_dump,
3298 NET_TRANSPORT_ADS,
3299 N_("Dump Kerberos PAC"),
3300 N_("net ads kerberos pac dump\n"
3301 " Dump a Kerberos PAC to stdout")
3304 "save",
3305 net_ads_kerberos_pac_save,
3306 NET_TRANSPORT_ADS,
3307 N_("Save Kerberos PAC"),
3308 N_("net ads kerberos pac save\n"
3309 " Save a Kerberos PAC in a file")
3312 {NULL, NULL, 0, NULL, NULL}
3315 return net_run_function(c, argc, argv, "net ads kerberos pac", func);
3318 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
3320 int ret = -1;
3321 NTSTATUS status;
3323 if (c->display_usage) {
3324 d_printf( "%s\n"
3325 "net ads kerberos kinit\n"
3326 " %s\n",
3327 _("Usage:"),
3328 _("Get Ticket Granting Ticket (TGT) for the user"));
3329 return -1;
3332 c->opt_password = net_prompt_pass(c, c->opt_user_name);
3334 ret = kerberos_kinit_password_ext(c->opt_user_name,
3335 c->opt_password,
3337 NULL,
3338 NULL,
3339 NULL,
3340 true,
3341 true,
3342 2592000, /* one month */
3343 NULL,
3344 NULL,
3345 NULL,
3346 &status);
3347 if (ret) {
3348 d_printf(_("failed to kinit password: %s\n"),
3349 nt_errstr(status));
3351 return ret;
3354 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3356 struct functable func[] = {
3358 "kinit",
3359 net_ads_kerberos_kinit,
3360 NET_TRANSPORT_ADS,
3361 N_("Retrieve Ticket Granting Ticket (TGT)"),
3362 N_("net ads kerberos kinit\n"
3363 " Receive Ticket Granting Ticket (TGT)")
3366 "renew",
3367 net_ads_kerberos_renew,
3368 NET_TRANSPORT_ADS,
3369 N_("Renew Ticket Granting Ticket from credential cache"),
3370 N_("net ads kerberos renew\n"
3371 " Renew Ticket Granting Ticket (TGT) from "
3372 "credential cache")
3375 "pac",
3376 net_ads_kerberos_pac,
3377 NET_TRANSPORT_ADS,
3378 N_("Dump Kerberos PAC"),
3379 N_("net ads kerberos pac\n"
3380 " Dump Kerberos PAC")
3382 {NULL, NULL, 0, NULL, NULL}
3385 return net_run_function(c, argc, argv, "net ads kerberos", func);
3388 static int net_ads_setspn_list(struct net_context *c,
3389 int argc,
3390 const char **argv)
3392 TALLOC_CTX *tmp_ctx = talloc_stackframe();
3393 ADS_STRUCT *ads = NULL;
3394 ADS_STATUS status;
3395 bool ok = false;
3396 int ret = -1;
3398 if (c->display_usage) {
3399 d_printf("%s\n%s",
3400 _("Usage:"),
3401 _("net ads setspn list <machinename>\n"));
3402 TALLOC_FREE(tmp_ctx);
3403 return -1;
3406 status = ads_startup(c, true, tmp_ctx, &ads);
3407 if (!ADS_ERR_OK(status)) {
3408 goto out;
3411 if (argc) {
3412 ok = ads_setspn_list(ads, argv[0]);
3413 } else {
3414 ok = ads_setspn_list(ads, lp_netbios_name());
3417 ret = ok ? 0 : -1;
3418 out:
3419 TALLOC_FREE(tmp_ctx);
3420 return ret;
3423 static int net_ads_setspn_add(struct net_context *c, int argc, const char **argv)
3425 TALLOC_CTX *tmp_ctx = talloc_stackframe();
3426 ADS_STRUCT *ads = NULL;
3427 ADS_STATUS status;
3428 bool ok = false;
3429 int ret = -1;
3431 if (c->display_usage || argc < 1) {
3432 d_printf("%s\n%s",
3433 _("Usage:"),
3434 _("net ads setspn add <machinename> SPN\n"));
3435 TALLOC_FREE(tmp_ctx);
3436 return -1;
3439 status = ads_startup(c, true, tmp_ctx, &ads);
3440 if (!ADS_ERR_OK(status)) {
3441 goto out;
3444 if (argc > 1) {
3445 ok = ads_setspn_add(ads, argv[0], argv[1]);
3446 } else {
3447 ok = ads_setspn_add(ads, lp_netbios_name(), argv[0]);
3450 ret = ok ? 0 : -1;
3451 out:
3452 TALLOC_FREE(tmp_ctx);
3453 return ret;
3456 static int net_ads_setspn_delete(struct net_context *c, int argc, const char **argv)
3458 TALLOC_CTX *tmp_ctx = talloc_stackframe();
3459 ADS_STRUCT *ads = NULL;
3460 ADS_STATUS status;
3461 bool ok = false;
3462 int ret = -1;
3464 if (c->display_usage || argc < 1) {
3465 d_printf("%s\n%s",
3466 _("Usage:"),
3467 _("net ads setspn delete <machinename> SPN\n"));
3468 TALLOC_FREE(tmp_ctx);
3469 return -1;
3472 status = ads_startup(c, true, tmp_ctx, &ads);
3473 if (!ADS_ERR_OK(status)) {
3474 goto out;
3477 if (argc > 1) {
3478 ok = ads_setspn_delete(ads, argv[0], argv[1]);
3479 } else {
3480 ok = ads_setspn_delete(ads, lp_netbios_name(), argv[0]);
3483 ret = ok ? 0 : -1;
3484 out:
3485 TALLOC_FREE(tmp_ctx);
3486 return ret;
3489 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
3491 struct functable func[] = {
3493 "list",
3494 net_ads_setspn_list,
3495 NET_TRANSPORT_ADS,
3496 N_("List Service Principal Names (SPN)"),
3497 N_("net ads setspn list machine\n"
3498 " List Service Principal Names (SPN)")
3501 "add",
3502 net_ads_setspn_add,
3503 NET_TRANSPORT_ADS,
3504 N_("Add Service Principal Names (SPN)"),
3505 N_("net ads setspn add machine spn\n"
3506 " Add Service Principal Names (SPN)")
3509 "delete",
3510 net_ads_setspn_delete,
3511 NET_TRANSPORT_ADS,
3512 N_("Delete Service Principal Names (SPN)"),
3513 N_("net ads setspn delete machine spn\n"
3514 " Delete Service Principal Names (SPN)")
3516 {NULL, NULL, 0, NULL, NULL}
3519 return net_run_function(c, argc, argv, "net ads setspn", func);
3522 static int net_ads_enctype_lookup_account(struct net_context *c,
3523 ADS_STRUCT *ads,
3524 const char *account,
3525 LDAPMessage **res,
3526 const char **enctype_str)
3528 const char *filter;
3529 const char *attrs[] = {
3530 "msDS-SupportedEncryptionTypes",
3531 NULL
3533 int count;
3534 int ret = -1;
3535 ADS_STATUS status;
3537 filter = talloc_asprintf(c, "(&(objectclass=user)(sAMAccountName=%s))",
3538 account);
3539 if (filter == NULL) {
3540 goto done;
3543 status = ads_search(ads, res, filter, attrs);
3544 if (!ADS_ERR_OK(status)) {
3545 d_printf(_("no account found with filter: %s\n"), filter);
3546 goto done;
3549 count = ads_count_replies(ads, *res);
3550 switch (count) {
3551 case 1:
3552 break;
3553 case 0:
3554 d_printf(_("no account found with filter: %s\n"), filter);
3555 goto done;
3556 default:
3557 d_printf(_("multiple accounts found with filter: %s\n"), filter);
3558 goto done;
3561 if (enctype_str) {
3562 *enctype_str = ads_pull_string(ads, c, *res,
3563 "msDS-SupportedEncryptionTypes");
3564 if (*enctype_str == NULL) {
3565 d_printf(_("no msDS-SupportedEncryptionTypes attribute found\n"));
3566 goto done;
3570 ret = 0;
3571 done:
3572 return ret;
3575 static void net_ads_enctype_dump_enctypes(const char *username,
3576 const char *enctype_str)
3578 int enctypes = atoi(enctype_str);
3580 d_printf(_("'%s' uses \"msDS-SupportedEncryptionTypes\": %d (0x%08x)\n"),
3581 username, enctypes, enctypes);
3583 printf("[%s] 0x%08x DES-CBC-CRC\n",
3584 enctypes & ENC_CRC32 ? "X" : " ",
3585 ENC_CRC32);
3586 printf("[%s] 0x%08x DES-CBC-MD5\n",
3587 enctypes & ENC_RSA_MD5 ? "X" : " ",
3588 ENC_RSA_MD5);
3589 printf("[%s] 0x%08x RC4-HMAC\n",
3590 enctypes & ENC_RC4_HMAC_MD5 ? "X" : " ",
3591 ENC_RC4_HMAC_MD5);
3592 printf("[%s] 0x%08x AES128-CTS-HMAC-SHA1-96\n",
3593 enctypes & ENC_HMAC_SHA1_96_AES128 ? "X" : " ",
3594 ENC_HMAC_SHA1_96_AES128);
3595 printf("[%s] 0x%08x AES256-CTS-HMAC-SHA1-96\n",
3596 enctypes & ENC_HMAC_SHA1_96_AES256 ? "X" : " ",
3597 ENC_HMAC_SHA1_96_AES256);
3600 static int net_ads_enctypes_list(struct net_context *c, int argc, const char **argv)
3602 TALLOC_CTX *tmp_ctx = talloc_stackframe();
3603 ADS_STATUS status;
3604 ADS_STRUCT *ads = NULL;
3605 LDAPMessage *res = NULL;
3606 const char *str = NULL;
3607 int ret = -1;
3609 if (c->display_usage || (argc < 1)) {
3610 d_printf( "%s\n"
3611 "net ads enctypes list\n"
3612 " %s\n",
3613 _("Usage:"),
3614 _("List supported enctypes"));
3615 TALLOC_FREE(tmp_ctx);
3616 return -1;
3619 status = ads_startup(c, false, tmp_ctx, &ads);
3620 if (!ADS_ERR_OK(status)) {
3621 goto out;
3624 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3625 if (ret) {
3626 goto out;
3629 net_ads_enctype_dump_enctypes(argv[0], str);
3631 ret = 0;
3632 out:
3633 ads_msgfree(ads, res);
3634 TALLOC_FREE(tmp_ctx);
3635 return ret;
3638 static int net_ads_enctypes_set(struct net_context *c, int argc, const char **argv)
3640 TALLOC_CTX *tmp_ctx = talloc_stackframe();
3641 int ret = -1;
3642 ADS_STATUS status;
3643 ADS_STRUCT *ads = NULL;
3644 LDAPMessage *res = NULL;
3645 const char *etype_list_str = NULL;
3646 const char *dn = NULL;
3647 ADS_MODLIST mods = NULL;
3648 uint32_t etype_list;
3649 const char *str = NULL;
3651 if (c->display_usage || argc < 1) {
3652 d_printf( "%s\n"
3653 "net ads enctypes set <sAMAccountName> [enctypes]\n"
3654 " %s\n",
3655 _("Usage:"),
3656 _("Set supported enctypes"));
3657 TALLOC_FREE(tmp_ctx);
3658 return -1;
3661 status = ads_startup(c, false, tmp_ctx, &ads);
3662 if (!ADS_ERR_OK(status)) {
3663 goto done;
3666 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3667 if (ret) {
3668 goto done;
3671 dn = ads_get_dn(ads, tmp_ctx, res);
3672 if (dn == NULL) {
3673 goto done;
3676 etype_list = ENC_CRC32 | ENC_RSA_MD5 | ENC_RC4_HMAC_MD5;
3677 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
3678 etype_list |= ENC_HMAC_SHA1_96_AES128;
3679 #endif
3680 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
3681 etype_list |= ENC_HMAC_SHA1_96_AES256;
3682 #endif
3684 if (argv[1] != NULL) {
3685 sscanf(argv[1], "%i", &etype_list);
3688 etype_list_str = talloc_asprintf(tmp_ctx, "%d", etype_list);
3689 if (!etype_list_str) {
3690 goto done;
3693 mods = ads_init_mods(tmp_ctx);
3694 if (!mods) {
3695 goto done;
3698 status = ads_mod_str(tmp_ctx, &mods, "msDS-SupportedEncryptionTypes",
3699 etype_list_str);
3700 if (!ADS_ERR_OK(status)) {
3701 goto done;
3704 status = ads_gen_mod(ads, dn, mods);
3705 if (!ADS_ERR_OK(status)) {
3706 d_printf(_("failed to add msDS-SupportedEncryptionTypes: %s\n"),
3707 ads_errstr(status));
3708 goto done;
3711 ads_msgfree(ads, res);
3712 res = NULL;
3714 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3715 if (ret) {
3716 goto done;
3719 net_ads_enctype_dump_enctypes(argv[0], str);
3721 ret = 0;
3722 done:
3723 ads_msgfree(ads, res);
3724 TALLOC_FREE(tmp_ctx);
3725 return ret;
3728 static int net_ads_enctypes_delete(struct net_context *c, int argc, const char **argv)
3730 TALLOC_CTX *tmp_ctx = talloc_stackframe();
3731 int ret = -1;
3732 ADS_STATUS status;
3733 ADS_STRUCT *ads = NULL;
3734 LDAPMessage *res = NULL;
3735 const char *dn = NULL;
3736 ADS_MODLIST mods = NULL;
3738 if (c->display_usage || argc < 1) {
3739 d_printf( "%s\n"
3740 "net ads enctypes delete <sAMAccountName>\n"
3741 " %s\n",
3742 _("Usage:"),
3743 _("Delete supported enctypes"));
3744 TALLOC_FREE(tmp_ctx);
3745 return -1;
3748 status = ads_startup(c, false, tmp_ctx, &ads);
3749 if (!ADS_ERR_OK(status)) {
3750 goto done;
3753 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3754 if (ret) {
3755 goto done;
3758 dn = ads_get_dn(ads, tmp_ctx, res);
3759 if (dn == NULL) {
3760 goto done;
3763 mods = ads_init_mods(tmp_ctx);
3764 if (!mods) {
3765 goto done;
3768 status = ads_mod_str(tmp_ctx, &mods, "msDS-SupportedEncryptionTypes", NULL);
3769 if (!ADS_ERR_OK(status)) {
3770 goto done;
3773 status = ads_gen_mod(ads, dn, mods);
3774 if (!ADS_ERR_OK(status)) {
3775 d_printf(_("failed to remove msDS-SupportedEncryptionTypes: %s\n"),
3776 ads_errstr(status));
3777 goto done;
3780 ret = 0;
3782 done:
3783 ads_msgfree(ads, res);
3784 TALLOC_FREE(tmp_ctx);
3785 return ret;
3788 static int net_ads_enctypes(struct net_context *c, int argc, const char **argv)
3790 struct functable func[] = {
3792 "list",
3793 net_ads_enctypes_list,
3794 NET_TRANSPORT_ADS,
3795 N_("List the supported encryption types"),
3796 N_("net ads enctypes list\n"
3797 " List the supported encryption types")
3800 "set",
3801 net_ads_enctypes_set,
3802 NET_TRANSPORT_ADS,
3803 N_("Set the supported encryption types"),
3804 N_("net ads enctypes set\n"
3805 " Set the supported encryption types")
3808 "delete",
3809 net_ads_enctypes_delete,
3810 NET_TRANSPORT_ADS,
3811 N_("Delete the supported encryption types"),
3812 N_("net ads enctypes delete\n"
3813 " Delete the supported encryption types")
3816 {NULL, NULL, 0, NULL, NULL}
3819 return net_run_function(c, argc, argv, "net ads enctypes", func);
3823 int net_ads(struct net_context *c, int argc, const char **argv)
3825 struct functable func[] = {
3827 "info",
3828 net_ads_info,
3829 NET_TRANSPORT_ADS,
3830 N_("Display details on remote ADS server"),
3831 N_("net ads info\n"
3832 " Display details on remote ADS server")
3835 "join",
3836 net_ads_join,
3837 NET_TRANSPORT_ADS,
3838 N_("Join the local machine to ADS realm"),
3839 N_("net ads join\n"
3840 " Join the local machine to ADS realm")
3843 "testjoin",
3844 net_ads_testjoin,
3845 NET_TRANSPORT_ADS,
3846 N_("Validate machine account"),
3847 N_("net ads testjoin\n"
3848 " Validate machine account")
3851 "leave",
3852 net_ads_leave,
3853 NET_TRANSPORT_ADS,
3854 N_("Remove the local machine from ADS"),
3855 N_("net ads leave\n"
3856 " Remove the local machine from ADS")
3859 "status",
3860 net_ads_status,
3861 NET_TRANSPORT_ADS,
3862 N_("Display machine account details"),
3863 N_("net ads status\n"
3864 " Display machine account details")
3867 "user",
3868 net_ads_user,
3869 NET_TRANSPORT_ADS,
3870 N_("List/modify users"),
3871 N_("net ads user\n"
3872 " List/modify users")
3875 "group",
3876 net_ads_group,
3877 NET_TRANSPORT_ADS,
3878 N_("List/modify groups"),
3879 N_("net ads group\n"
3880 " List/modify groups")
3883 "dns",
3884 net_ads_dns,
3885 NET_TRANSPORT_ADS,
3886 N_("Issue dynamic DNS update"),
3887 N_("net ads dns\n"
3888 " Issue dynamic DNS update")
3891 "password",
3892 net_ads_password,
3893 NET_TRANSPORT_ADS,
3894 N_("Change user passwords"),
3895 N_("net ads password\n"
3896 " Change user passwords")
3899 "changetrustpw",
3900 net_ads_changetrustpw,
3901 NET_TRANSPORT_ADS,
3902 N_("Change trust account password"),
3903 N_("net ads changetrustpw\n"
3904 " Change trust account password")
3907 "printer",
3908 net_ads_printer,
3909 NET_TRANSPORT_ADS,
3910 N_("List/modify printer entries"),
3911 N_("net ads printer\n"
3912 " List/modify printer entries")
3915 "search",
3916 net_ads_search,
3917 NET_TRANSPORT_ADS,
3918 N_("Issue LDAP search using filter"),
3919 N_("net ads search\n"
3920 " Issue LDAP search using filter")
3923 "dn",
3924 net_ads_dn,
3925 NET_TRANSPORT_ADS,
3926 N_("Issue LDAP search by DN"),
3927 N_("net ads dn\n"
3928 " Issue LDAP search by DN")
3931 "sid",
3932 net_ads_sid,
3933 NET_TRANSPORT_ADS,
3934 N_("Issue LDAP search by SID"),
3935 N_("net ads sid\n"
3936 " Issue LDAP search by SID")
3939 "workgroup",
3940 net_ads_workgroup,
3941 NET_TRANSPORT_ADS,
3942 N_("Display workgroup name"),
3943 N_("net ads workgroup\n"
3944 " Display the workgroup name")
3947 "lookup",
3948 net_ads_lookup,
3949 NET_TRANSPORT_ADS,
3950 N_("Perform CLDAP query on DC"),
3951 N_("net ads lookup\n"
3952 " Find the ADS DC using CLDAP lookups")
3955 "keytab",
3956 net_ads_keytab,
3957 NET_TRANSPORT_ADS,
3958 N_("Manage local keytab file"),
3959 N_("net ads keytab\n"
3960 " Manage local keytab file")
3963 "setspn",
3964 net_ads_setspn,
3965 NET_TRANSPORT_ADS,
3966 N_("Manage Service Principal Names (SPN)s"),
3967 N_("net ads spnset\n"
3968 " Manage Service Principal Names (SPN)s")
3971 "gpo",
3972 net_ads_gpo,
3973 NET_TRANSPORT_ADS,
3974 N_("Manage group policy objects"),
3975 N_("net ads gpo\n"
3976 " Manage group policy objects")
3979 "kerberos",
3980 net_ads_kerberos,
3981 NET_TRANSPORT_ADS,
3982 N_("Manage kerberos keytab"),
3983 N_("net ads kerberos\n"
3984 " Manage kerberos keytab")
3987 "enctypes",
3988 net_ads_enctypes,
3989 NET_TRANSPORT_ADS,
3990 N_("List/modify supported encryption types"),
3991 N_("net ads enctypes\n"
3992 " List/modify enctypes")
3994 {NULL, NULL, 0, NULL, NULL}
3997 return net_run_function(c, argc, argv, "net ads", func);
4000 #else
4002 static int net_ads_noads(void)
4004 d_fprintf(stderr, _("ADS support not compiled in\n"));
4005 return -1;
4008 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
4010 return net_ads_noads();
4013 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
4015 return net_ads_noads();
4018 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
4020 return net_ads_noads();
4023 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
4025 return net_ads_noads();
4028 int net_ads_join(struct net_context *c, int argc, const char **argv)
4030 return net_ads_noads();
4033 int net_ads_user(struct net_context *c, int argc, const char **argv)
4035 return net_ads_noads();
4038 int net_ads_group(struct net_context *c, int argc, const char **argv)
4040 return net_ads_noads();
4043 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
4045 return net_ads_noads();
4048 /* this one shouldn't display a message */
4049 int net_ads_check(struct net_context *c)
4051 return -1;
4054 int net_ads_check_our_domain(struct net_context *c)
4056 return -1;
4059 int net_ads(struct net_context *c, int argc, const char **argv)
4061 return net_ads_noads();
4064 #endif /* HAVE_ADS */