2 Samba Unix/Linux SMB client library
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/>.
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"
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"
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"
48 #include "audit_logging.h" /* various JSON helpers */
49 #include "auth/common_auth.h"
50 #endif /* [HAVE_JANSSON] */
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)) {
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;
78 if (json_is_invalid(jsobj)) {
82 ctx = talloc_new(NULL);
84 d_fprintf(stderr, _("Out of memory\n"));
88 json = json_to_string(ctx, jsobj);
90 d_fprintf(stderr, _("error encoding to JSON\n"));
94 d_printf("%s\n", json);
100 static int net_ads_cldap_netlogon_json
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' };
110 if (json_is_invalid(&jsobj) || json_is_invalid(&flagsobj)) {
111 d_fprintf(stderr, _("error setting up JSON value\n"));
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));
122 case LOGON_SAM_LOGON_RESPONSE_EX:
123 strncpy(response_type, "LOGON_SAM_LOGON_RESPONSE_EX",
124 sizeof(response_type));
127 snprintf(response_type, sizeof(response_type), "0x%x",
132 ret = json_add_string(&jsobj, "Information for Domain Controller",
138 ret = json_add_string(&jsobj, "Response Type", response_type);
143 ret = json_add_guid(&jsobj, "GUID", &reply->domain_uuid);
148 ret = json_add_bool(&flagsobj, "Is a PDC",
149 reply->server_type & NBT_SERVER_PDC);
154 ret = json_add_bool(&flagsobj, "Is a GC of the forest",
155 reply->server_type & NBT_SERVER_GC);
160 ret = json_add_bool(&flagsobj, "Is an LDAP server",
161 reply->server_type & NBT_SERVER_LDAP);
166 ret = json_add_bool(&flagsobj, "Supports DS",
167 reply->server_type & NBT_SERVER_DS);
172 ret = json_add_bool(&flagsobj, "Is running a KDC",
173 reply->server_type & NBT_SERVER_KDC);
178 ret = json_add_bool(&flagsobj, "Is running time services",
179 reply->server_type & NBT_SERVER_TIMESERV);
184 ret = json_add_bool(&flagsobj, "Is the closest DC",
185 reply->server_type & NBT_SERVER_CLOSEST);
190 ret = json_add_bool(&flagsobj, "Is writable",
191 reply->server_type & NBT_SERVER_WRITABLE);
196 ret = json_add_bool(&flagsobj, "Has a hardware clock",
197 reply->server_type & NBT_SERVER_GOOD_TIMESERV);
202 ret = json_add_bool(&flagsobj,
203 "Is a non-domain NC serviced by LDAP server",
204 reply->server_type & NBT_SERVER_NDNC);
210 (&flagsobj, "Is NT6 DC that has some secrets",
211 reply->server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6);
217 (&flagsobj, "Is NT6 DC that has all secrets",
218 reply->server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6);
223 ret = json_add_bool(&flagsobj, "Runs Active Directory Web Services",
224 reply->server_type & NBT_SERVER_ADS_WEB_SERVICE);
229 ret = json_add_bool(&flagsobj, "Runs on Windows 2012 or later",
230 reply->server_type & NBT_SERVER_DS_8);
235 ret = json_add_string(&jsobj, "Forest", reply->forest);
240 ret = json_add_string(&jsobj, "Domain", reply->dns_domain);
245 ret = json_add_string(&jsobj, "Domain Controller", reply->pdc_dns_name);
251 ret = json_add_string(&jsobj, "Pre-Win2k Domain", reply->domain_name);
256 ret = json_add_string(&jsobj, "Pre-Win2k Hostname", reply->pdc_name);
261 if (*reply->user_name) {
262 ret = json_add_string(&jsobj, "User name", reply->user_name);
268 ret = json_add_string(&jsobj, "Server Site Name", reply->server_site);
273 ret = json_add_string(&jsobj, "Client Site Name", reply->client_site);
278 ret = json_add_int(&jsobj, "NT Version", reply->nt_version);
283 ret = json_add_int(&jsobj, "LMNT Token", reply->lmnt_token);
288 ret = json_add_int(&jsobj, "LM20 Token", reply->lm20_token);
293 ret = json_add_object(&jsobj, "Flags", &flagsobj);
298 ret = output_json(&jsobj);
299 json_free(&jsobj); /* frees flagsobj recursively */
304 json_free(&flagsobj);
310 #else /* [HAVE_JANSSON] */
312 static int net_ads_cldap_netlogon_json
315 const struct NETLOGON_SAM_LOGON_RESPONSE_EX * reply)
317 d_fprintf(stderr, _("JSON support not available\n"));
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"));
340 return net_ads_cldap_netlogon_json(ads, addr, &reply);
343 d_printf(_("Information for Domain Controller: %s\n\n"),
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");
351 case LOGON_SAM_LOGON_RESPONSE_EX:
352 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
355 d_printf("0x%x\n", reply.command);
359 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
361 d_printf(_("Flags:\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);
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;
422 if (c->display_usage) {
427 _("Find the ADS DC using CLDAP lookup.\n"));
428 TALLOC_FREE(tmp_ctx);
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"));
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"));
444 ads->ldap.port = 389;
447 ret = net_ads_cldap_netlogon(c, ads);
449 TALLOC_FREE(tmp_ctx);
456 static int net_ads_info_json(ADS_STRUCT *ads)
459 char addr[INET6_ADDRSTRLEN];
461 struct json_object jsobj = json_new_object();
463 if (json_is_invalid(&jsobj)) {
464 d_fprintf(stderr, _("error setting up JSON value\n"));
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);
478 ret = json_add_string (&jsobj, "LDAP server name",
479 ads->config.ldap_server_name);
484 ret = json_add_string (&jsobj, "Realm", ads->config.realm);
489 ret = json_add_string (&jsobj, "Bind Path", ads->config.bind_path);
494 ret = json_add_int (&jsobj, "LDAP port", ads->ldap.port);
499 ret = json_add_int (&jsobj, "Server time", ads->config.current_time);
504 ret = json_add_string (&jsobj, "KDC server", ads->auth.kdc_server);
509 ret = json_add_int (&jsobj, "Server time offset",
510 ads->auth.time_offset);
515 ret = json_add_int (&jsobj, "Last machine account password change",
521 ret = output_json(&jsobj);
528 #else /* [HAVE_JANSSON] */
530 static int net_ads_info_json(ADS_STRUCT *ads)
532 d_fprintf(stderr, _("JSON support not available\n"));
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;
546 char addr[INET6_ADDRSTRLEN];
550 if (c->display_usage) {
555 _("Display information about an Active Directory "
557 TALLOC_FREE(tmp_ctx);
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"));
567 if (!ads || !ads->config.realm) {
568 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
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"));
580 ret = net_ads_info_json(ads);
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));
604 TALLOC_FREE(tmp_ctx);
608 static ADS_STATUS ads_startup_int(struct net_context *c,
609 bool only_own_domain,
612 ADS_STRUCT **ads_ret)
614 ADS_STRUCT *ads = NULL;
616 bool need_password = false;
617 bool second_time = false;
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 */
632 if (only_own_domain) {
635 realm = assume_own_realm(c);
638 ads = ads_init(mem_ctx,
640 c->opt_target_workgroup,
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;
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) {
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) {
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) {
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;
690 case CRED_USE_KERBEROS_DESIRED:
691 ads->auth.flags &= ~ADS_AUTH_DISABLE_KERBEROS;
692 ads->auth.flags |= ADS_AUTH_ALLOW_NTLMSSP;
694 case CRED_USE_KERBEROS_DISABLED:
695 ads->auth.flags |= ADS_AUTH_DISABLE_KERBEROS;
696 ads->auth.flags |= ADS_AUTH_ALLOW_NTLMSSP;
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) {
707 TALLOC_FREE(ads->auth.realm);
708 ads->auth.realm = talloc_asprintf_strupper_m(ads, "%s", cp);
709 if (ads->auth.realm == NULL) {
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)));
726 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
727 need_password = true;
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);
755 *ads_ret = talloc_move(mem_ctx, &ads);
759 ADS_STATUS ads_startup(struct net_context *c,
760 bool only_own_domain,
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,
772 return ads_startup_int(c,
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,
786 const char *workgroup,
789 TALLOC_CTX *tmp_ctx = talloc_stackframe();
794 ads = ads_init(tmp_ctx, realm, workgroup, host, ADS_SASL_PLAIN);
799 ads->auth.flags |= ADS_AUTH_NO_BIND;
801 status = ads_connect(ads);
802 if ( !ADS_ERR_OK(status) ) {
808 TALLOC_FREE(tmp_ctx);
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;
830 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
834 if (c->display_usage) {
836 "net ads workgroup\n"
839 _("Print the workgroup name"));
840 TALLOC_FREE(tmp_ctx);
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"));
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"));
856 ads->ldap.port = 389;
859 ok = ads_cldap_netlogon_5(tmp_ctx,
860 &ads->ldap.ss, ads->server.realm, &reply);
862 d_fprintf(stderr, _("CLDAP query failed!\n"));
866 d_printf(_("Workgroup: %s\n"), reply.domain_name);
870 TALLOC_FREE(tmp_ctx);
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], '$')) {
885 d_printf("%-21.21s %s\n",
886 disp_fields[0], disp_fields[1]);
888 d_printf("%s\n", disp_fields[0]);
891 SAFE_FREE(disp_fields[0]);
892 SAFE_FREE(disp_fields[1]);
895 if (!values) /* must be new field, indicate string field */
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]);
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;
916 LDAPMessage *res=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)) {
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));
936 if (ads_count_replies(ads, res)) {
937 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
942 if (c->opt_container) {
943 ou_str = SMB_STRDUP(c->opt_container);
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],
955 /* if no password is to be set, we're done */
957 d_printf(_("User %s added\n"), argv[0]);
962 /* try setting the password */
963 upn = talloc_asprintf(tmp_ctx,
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]);
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);
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);
996 ads_msgfree(ads, res);
998 TALLOC_FREE(tmp_ctx);
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;
1007 LDAPMessage *res = NULL;
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;
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) {
1027 _("ads_user_info: failed to escape user %s\n"),
1032 status = ads_startup(c, false, tmp_ctx, &ads);
1033 if (!ADS_ERR_OK(status)) {
1037 searchstring = talloc_asprintf(tmp_ctx,
1038 "(sAMAccountName=%s)",
1040 if (searchstring == NULL) {
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));
1050 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
1051 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
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));
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 */
1067 if (!WBC_ERROR_IS_OK(wbc_status)) {
1068 d_fprintf(stderr, "wbcLookupSid: %s\n",
1069 wbcErrorString(wbc_status));
1073 d_printf("%s\n", primary_group);
1075 wbcFreeMemory(primary_group);
1077 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
1078 (LDAPMessage *)res, "memberOf");
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);
1093 ads_msgfree(ads, res);
1094 TALLOC_FREE(tmp_ctx);
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;
1103 LDAPMessage *res = NULL;
1104 char *userdn = NULL;
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)) {
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]);
1123 userdn = ads_get_dn(ads, tmp_ctx, res);
1124 if (userdn == NULL) {
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));
1135 d_printf(_("User %s deleted\n"), argv[0]);
1139 ads_msgfree(ads, res);
1140 TALLOC_FREE(tmp_ctx);
1144 int net_ads_user(struct net_context *c, int argc, const char **argv)
1146 struct functable func[] = {
1151 N_("Add an AD user"),
1152 N_("net ads user add\n"
1159 N_("Display information about an AD user"),
1160 N_("net ads user info\n"
1161 " Display information about an AD user")
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;
1176 const char *shortattrs[] = {"sAMAccountName", NULL};
1177 const char *longattrs[] = {"sAMAccountName", "description", NULL};
1178 char *disp_fields[2] = {NULL, NULL};
1182 TALLOC_FREE(tmp_ctx);
1183 return net_run_function(c, argc, argv, "net ads user", func);
1186 if (c->display_usage) {
1191 _("List AD users"));
1192 net_display_usage_from_functable(func);
1193 TALLOC_FREE(tmp_ctx);
1197 status = ads_startup(c, false, tmp_ctx, &ads);
1198 if (!ADS_ERR_OK(status)) {
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,
1209 "(objectCategory=user)",
1210 c->opt_long_list_entries ?
1211 longattrs : shortattrs,
1214 if (!ADS_ERR_OK(status)) {
1220 TALLOC_FREE(tmp_ctx);
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;
1234 LDAPMessage *res = NULL;
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)) {
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));
1254 if (ads_count_replies(ads, res)) {
1255 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
1259 if (c->opt_container) {
1260 ou_str = SMB_STRDUP(c->opt_container);
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));
1272 d_printf(_("Group %s added\n"), argv[0]);
1276 ads_msgfree(ads, res);
1278 TALLOC_FREE(tmp_ctx);
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;
1287 LDAPMessage *res = NULL;
1288 char *groupdn = NULL;
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)) {
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]);
1307 groupdn = ads_get_dn(ads, tmp_ctx, res);
1308 if (groupdn == NULL) {
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));
1318 d_printf(_("Group %s deleted\n"), argv[0]);
1322 ads_msgfree(ads, res);
1323 TALLOC_FREE(tmp_ctx);
1327 int net_ads_group(struct net_context *c, int argc, const char **argv)
1329 struct functable func[] = {
1334 N_("Add an AD group"),
1335 N_("net ads group add\n"
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;
1351 const char *shortattrs[] = {"sAMAccountName", NULL};
1352 const char *longattrs[] = {"sAMAccountName", "description", NULL};
1353 char *disp_fields[2] = {NULL, NULL};
1357 TALLOC_FREE(tmp_ctx);
1358 return net_run_function(c, argc, argv, "net ads group", func);
1361 if (c->display_usage) {
1366 _("List AD groups"));
1367 net_display_usage_from_functable(func);
1368 TALLOC_FREE(tmp_ctx);
1372 status = ads_startup(c, false, tmp_ctx, &ads);
1373 if (!ADS_ERR_OK(status)) {
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,
1384 "(objectCategory=group)",
1385 c->opt_long_list_entries ?
1386 longattrs : shortattrs,
1389 if (!ADS_ERR_OK(status)) {
1395 TALLOC_FREE(tmp_ctx);
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;
1404 LDAPMessage *res = NULL;
1407 if (c->display_usage) {
1412 _("Display machine account details"));
1413 TALLOC_FREE(tmp_ctx);
1417 net_warn_member_options();
1419 status = ads_startup(c, true, tmp_ctx, &ads);
1420 if (!ADS_ERR_OK(status)) {
1424 status = ads_find_machine_acct(ads, &res, lp_netbios_name());
1425 if (!ADS_ERR_OK(status)) {
1426 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"),
1427 ads_errstr(status));
1431 if (ads_count_replies(ads, res) == 0) {
1432 d_fprintf(stderr, _("No machine account for '%s' found\n"),
1441 ads_msgfree(ads, res);
1442 TALLOC_FREE(tmp_ctx);
1446 /*******************************************************************
1447 Leave an AD domain. Windows XP disables the machine account.
1448 We'll try the same. The old code would do an LDAP delete.
1449 That only worked using the machine creds because added the machine
1450 with full control to the computer object's ACL.
1451 *******************************************************************/
1453 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
1455 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1456 struct libnet_UnjoinCtx *r = NULL;
1460 if (c->display_usage) {
1462 "net ads leave [--keep-account]\n"
1465 _("Leave an AD domain"));
1466 TALLOC_FREE(tmp_ctx);
1471 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
1472 TALLOC_FREE(tmp_ctx);
1476 if (!c->opt_kerberos) {
1477 use_in_memory_ccache();
1481 d_fprintf(stderr, _("Could not initialise message context. "
1482 "Try running as root\n"));
1486 werr = libnet_init_UnjoinCtx(tmp_ctx, &r);
1487 if (!W_ERROR_IS_OK(werr)) {
1488 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
1493 r->in.use_kerberos = c->opt_kerberos;
1494 r->in.dc_name = c->opt_host;
1495 r->in.domain_name = lp_realm();
1496 r->in.admin_account = c->opt_user_name;
1497 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1498 r->in.modify_config = lp_config_backend_is_registry();
1500 /* Try to delete it, but if that fails, disable it. The
1501 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
1502 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1503 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
1504 if (c->opt_keep_account) {
1505 r->in.delete_machine_account = false;
1507 r->in.delete_machine_account = true;
1510 r->in.msg_ctx = c->msg_ctx;
1512 werr = libnet_Unjoin(tmp_ctx, r);
1513 if (!W_ERROR_IS_OK(werr)) {
1514 d_printf(_("Failed to leave domain: %s\n"),
1515 r->out.error_string ? r->out.error_string :
1516 get_friendly_werror_msg(werr));
1520 if (r->out.deleted_machine_account) {
1521 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1522 r->in.machine_name, r->out.dns_domain_name);
1527 /* We couldn't delete it - see if the disable succeeded. */
1528 if (r->out.disabled_machine_account) {
1529 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1530 r->in.machine_name, r->out.dns_domain_name);
1535 /* Based on what we requested, we shouldn't get here, but if
1536 we did, it means the secrets were removed, and therefore
1537 we have left the domain */
1538 d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1539 r->in.machine_name, r->out.dns_domain_name);
1543 TALLOC_FREE(tmp_ctx);
1547 static ADS_STATUS net_ads_join_ok(struct net_context *c)
1549 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1550 ADS_STRUCT *ads = NULL;
1553 struct sockaddr_storage dcip;
1555 if (!secrets_init()) {
1556 DEBUG(1,("Failed to initialise secrets database\n"));
1557 TALLOC_FREE(tmp_ctx);
1558 return ADS_ERROR_NT(NT_STATUS_ACCESS_DENIED);
1561 net_warn_member_options();
1563 net_use_krb_machine_account(c);
1565 get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1567 status = ads_startup(c, true, tmp_ctx, &ads);
1568 if (!ADS_ERR_OK(status)) {
1572 status = ADS_ERROR_NT(NT_STATUS_OK);
1574 TALLOC_FREE(tmp_ctx);
1579 check that an existing join is OK
1581 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1584 use_in_memory_ccache();
1586 if (c->display_usage) {
1588 "net ads testjoin\n"
1591 _("Test if the existing join is ok"));
1595 net_warn_member_options();
1597 /* Display success or failure */
1598 status = net_ads_join_ok(c);
1599 if (!ADS_ERR_OK(status)) {
1600 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1601 get_friendly_nt_error_msg(ads_ntstatus(status)));
1605 printf(_("Join is OK\n"));
1609 /*******************************************************************
1610 Simple config checks before beginning the join
1611 ********************************************************************/
1613 static WERROR check_ads_config( void )
1615 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1616 d_printf(_("Host is not configured as a member server.\n"));
1617 return WERR_INVALID_DOMAIN_ROLE;
1620 if (strlen(lp_netbios_name()) > 15) {
1621 d_printf(_("Our netbios name can be at most 15 chars long, "
1622 "\"%s\" is %u chars long\n"), lp_netbios_name(),
1623 (unsigned int)strlen(lp_netbios_name()));
1624 return WERR_INVALID_COMPUTERNAME;
1627 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1628 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1629 "join to succeed.\n"), get_dyn_CONFIGFILE());
1630 return WERR_INVALID_PARAMETER;
1636 /*******************************************************************
1637 ********************************************************************/
1639 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1641 d_printf(_("net ads join [--no-dns-updates] [options]\n"
1642 "Valid options:\n"));
1643 d_printf(_(" dnshostname=FQDN Set the dnsHostName attribute during the join.\n"
1644 " The default is in the form netbiosname.dnsdomain\n"));
1645 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1646 " The default UPN is in the form host/netbiosname@REALM.\n"));
1647 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1648 " The OU string read from top to bottom without RDNs\n"
1649 " and delimited by a '/'.\n"
1650 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1651 " NB: A backslash '\\' is used as escape at multiple\n"
1652 " levels and may need to be doubled or even\n"
1653 " quadrupled. It is not used as a separator.\n"));
1654 d_printf(_(" machinepass=PASS Set the machine password to a specific value during\n"
1655 " the join. The default password is random.\n"));
1656 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1657 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during join.\n"
1658 " NB: osName and osVer must be specified together for\n"
1659 " either to take effect. The operatingSystemService\n"
1660 " attribute is then also set along with the two\n"
1661 " other attributes.\n"));
1662 d_printf(_(" osServicePack=string Set the operatingSystemServicePack attribute\n"
1663 " during the join.\n"
1664 " NB: If not specified then by default the samba\n"
1665 " version string is used instead.\n"));
1670 int net_ads_join(struct net_context *c, int argc, const char **argv)
1672 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1673 struct libnet_JoinCtx *r = NULL;
1674 const char *domain = lp_realm();
1675 WERROR werr = WERR_NERR_SETUPNOTJOINED;
1676 bool createupn = false;
1677 const char *dnshostname = NULL;
1678 const char *machineupn = NULL;
1679 const char *machine_password = NULL;
1680 const char *create_in_ou = NULL;
1682 const char *os_name = NULL;
1683 const char *os_version = NULL;
1684 const char *os_servicepack = NULL;
1685 bool modify_config = lp_config_backend_is_registry();
1686 enum libnetjoin_JoinDomNameType domain_name_type = JoinDomNameTypeDNS;
1689 if (c->display_usage) {
1690 TALLOC_FREE(tmp_ctx);
1691 return net_ads_join_usage(c, argc, argv);
1694 net_warn_member_options();
1696 if (!modify_config) {
1697 werr = check_ads_config();
1698 if (!W_ERROR_IS_OK(werr)) {
1699 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1704 if (!c->opt_kerberos) {
1705 use_in_memory_ccache();
1708 werr = libnet_init_JoinCtx(tmp_ctx, &r);
1709 if (!W_ERROR_IS_OK(werr)) {
1713 /* process additional command line args */
1715 for ( i=0; i<argc; i++ ) {
1716 if ( !strncasecmp_m(argv[i], "dnshostname", strlen("dnshostname")) ) {
1717 dnshostname = get_string_param(argv[i]);
1719 else if ( !strncasecmp_m(argv[i], "createupn", strlen("createupn")) ) {
1721 machineupn = get_string_param(argv[i]);
1723 else if ( !strncasecmp_m(argv[i], "createcomputer", strlen("createcomputer")) ) {
1724 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1725 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1726 werr = WERR_INVALID_PARAMETER;
1730 else if ( !strncasecmp_m(argv[i], "osName", strlen("osName")) ) {
1731 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1732 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1733 werr = WERR_INVALID_PARAMETER;
1737 else if ( !strncasecmp_m(argv[i], "osVer", strlen("osVer")) ) {
1738 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1739 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1740 werr = WERR_INVALID_PARAMETER;
1744 else if ( !strncasecmp_m(argv[i], "osServicePack", strlen("osServicePack")) ) {
1745 if ( (os_servicepack = get_string_param(argv[i])) == NULL ) {
1746 d_fprintf(stderr, _("Please supply a valid servicepack identifier.\n"));
1747 werr = WERR_INVALID_PARAMETER;
1751 else if ( !strncasecmp_m(argv[i], "machinepass", strlen("machinepass")) ) {
1752 if ( (machine_password = get_string_param(argv[i])) == NULL ) {
1753 d_fprintf(stderr, _("Please supply a valid password to set as trust account password.\n"));
1754 werr = WERR_INVALID_PARAMETER;
1759 if (strchr(domain, '.') == NULL) {
1760 domain_name_type = JoinDomNameTypeUnknown;
1762 domain_name_type = JoinDomNameTypeDNS;
1768 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1769 werr = WERR_INVALID_PARAMETER;
1774 d_fprintf(stderr, _("Could not initialise message context. "
1775 "Try running as root\n"));
1776 werr = WERR_ACCESS_DENIED;
1780 /* Do the domain join here */
1782 r->in.domain_name = domain;
1783 r->in.domain_name_type = domain_name_type;
1784 r->in.create_upn = createupn;
1785 r->in.upn = machineupn;
1786 r->in.dnshostname = dnshostname;
1787 r->in.account_ou = create_in_ou;
1788 r->in.os_name = os_name;
1789 r->in.os_version = os_version;
1790 r->in.os_servicepack = os_servicepack;
1791 r->in.dc_name = c->opt_host;
1792 r->in.admin_account = c->opt_user_name;
1793 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1794 r->in.machine_password = machine_password;
1796 r->in.use_kerberos = c->opt_kerberos;
1797 r->in.modify_config = modify_config;
1798 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1799 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1800 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1801 r->in.msg_ctx = c->msg_ctx;
1803 werr = libnet_Join(tmp_ctx, r);
1804 if (W_ERROR_EQUAL(werr, WERR_NERR_DCNOTFOUND) &&
1805 strequal(domain, lp_realm())) {
1806 r->in.domain_name = lp_workgroup();
1807 r->in.domain_name_type = JoinDomNameTypeNBT;
1808 werr = libnet_Join(tmp_ctx, r);
1810 if (!W_ERROR_IS_OK(werr)) {
1814 /* Check the short name of the domain */
1816 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1817 d_printf(_("The workgroup in %s does not match the short\n"
1818 "domain name obtained from the server.\n"
1819 "Using the name [%s] from the server.\n"
1820 "You should set \"workgroup = %s\" in %s.\n"),
1821 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1822 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1825 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1827 if (r->out.dns_domain_name) {
1828 d_printf(_("Joined '%s' to dns domain '%s'\n"), r->in.machine_name,
1829 r->out.dns_domain_name);
1831 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1832 r->out.netbios_domain_name);
1835 /* print out informative error string in case there is one */
1836 if (r->out.error_string != NULL) {
1837 d_printf("%s\n", r->out.error_string);
1841 * We try doing the dns update (if it was compiled in
1842 * and if it was not disabled on the command line).
1843 * If the dns update fails, we still consider the join
1844 * operation as succeeded if we came this far.
1846 if (!c->opt_no_dns_updates) {
1847 net_ads_join_dns_updates(c, tmp_ctx, r);
1854 /* issue an overall failure message at the end. */
1855 d_printf(_("Failed to join domain: %s\n"),
1856 r && r->out.error_string ? r->out.error_string :
1857 get_friendly_werror_msg(werr));
1860 TALLOC_FREE(tmp_ctx);
1865 /*******************************************************************
1866 ********************************************************************/
1868 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1870 #if defined(HAVE_KRB5)
1871 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1872 ADS_STRUCT *ads = NULL;
1875 const char *hostname = NULL;
1876 const char **addrs_list = NULL;
1877 struct sockaddr_storage *addrs = NULL;
1883 talloc_enable_leak_report();
1886 if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
1887 d_fprintf(stderr, _("Refusing DNS updates with automatic "
1888 "detection of addresses in a clustered "
1890 c->display_usage = true;
1893 if (c->display_usage) {
1895 "net ads dns register [hostname [IP [IP...]]]\n"
1898 _("Register hostname with DNS\n"));
1899 TALLOC_FREE(tmp_ctx);
1908 num_addrs = argc - 1;
1909 addrs_list = &argv[1];
1910 } else if (lp_clustering()) {
1911 addrs_list = lp_cluster_addresses();
1912 num_addrs = str_list_length(addrs_list);
1915 if (num_addrs > 0) {
1916 addrs = talloc_zero_array(tmp_ctx,
1917 struct sockaddr_storage,
1919 if (addrs == NULL) {
1920 d_fprintf(stderr, _("Error allocating memory!\n"));
1925 for (count = 0; count < num_addrs; count++) {
1926 if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
1927 d_fprintf(stderr, "%s '%s'.\n",
1928 _("Cannot interpret address"),
1934 status = ads_startup(c, true, tmp_ctx, &ads);
1935 if ( !ADS_ERR_OK(status) ) {
1936 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1940 ntstatus = net_update_dns_ext(c,
1947 if (!NT_STATUS_IS_OK(ntstatus)) {
1948 d_fprintf( stderr, _("DNS update failed!\n") );
1952 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1956 TALLOC_FREE(tmp_ctx);
1961 _("DNS update support not enabled at compile time!\n"));
1966 static int net_ads_dns_unregister(struct net_context *c,
1970 #if defined(HAVE_KRB5)
1971 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1972 ADS_STRUCT *ads = NULL;
1975 const char *hostname = NULL;
1979 talloc_enable_leak_report();
1983 c->display_usage = true;
1986 if (c->display_usage) {
1988 "net ads dns unregister [hostname]\n"
1991 _("Remove all IP Address entires for a given\n"
1992 " hostname from the Active Directory server.\n"));
1993 TALLOC_FREE(tmp_ctx);
1997 /* Get the hostname for un-registering */
2000 status = ads_startup(c, true, tmp_ctx, &ads);
2001 if ( !ADS_ERR_OK(status) ) {
2002 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
2006 ntstatus = net_update_dns_ext(c,
2013 if (!NT_STATUS_IS_OK(ntstatus)) {
2014 d_fprintf( stderr, _("DNS update failed!\n") );
2018 d_fprintf( stderr, _("Successfully un-registered hostname from DNS\n"));
2022 TALLOC_FREE(tmp_ctx);
2027 _("DNS update support not enabled at compile time!\n"));
2033 static int net_ads_dns_async(struct net_context *c, int argc, const char **argv)
2035 size_t num_names = 0;
2036 char **hostnames = NULL;
2038 struct samba_sockaddr *addrs = NULL;
2041 if (argc != 1 || c->display_usage) {
2046 _("net ads dns async <name>\n"),
2047 _(" Async look up hostname from the DNS server\n"
2048 " hostname\tName to look up\n"));
2052 status = ads_dns_lookup_a(talloc_tos(),
2057 if (!NT_STATUS_IS_OK(status)) {
2058 d_printf("Looking up A record for %s got error %s\n",
2063 d_printf("Async A record lookup - got %u names for %s\n",
2064 (unsigned int)num_names,
2066 for (i = 0; i < num_names; i++) {
2067 char addr_buf[INET6_ADDRSTRLEN];
2068 print_sockaddr(addr_buf,
2071 d_printf("hostname[%u] = %s, IPv4addr = %s\n",
2077 #if defined(HAVE_IPV6)
2078 status = ads_dns_lookup_aaaa(talloc_tos(),
2083 if (!NT_STATUS_IS_OK(status)) {
2084 d_printf("Looking up AAAA record for %s got error %s\n",
2089 d_printf("Async AAAA record lookup - got %u names for %s\n",
2090 (unsigned int)num_names,
2092 for (i = 0; i < num_names; i++) {
2093 char addr_buf[INET6_ADDRSTRLEN];
2094 print_sockaddr(addr_buf,
2097 d_printf("hostname[%u] = %s, IPv6addr = %s\n",
2107 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
2109 struct functable func[] = {
2112 net_ads_dns_register,
2114 N_("Add host dns entry to AD"),
2115 N_("net ads dns register\n"
2116 " Add host dns entry to AD")
2120 net_ads_dns_unregister,
2122 N_("Remove host dns entry from AD"),
2123 N_("net ads dns unregister\n"
2124 " Remove host dns entry from AD")
2131 N_("net ads dns async\n"
2132 " Look up host using async DNS")
2134 {NULL, NULL, 0, NULL, NULL}
2137 return net_run_function(c, argc, argv, "net ads dns", func);
2140 /*******************************************************************
2141 ********************************************************************/
2143 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
2146 "\nnet ads printer search <printer>"
2147 "\n\tsearch for a printer in the directory\n"
2148 "\nnet ads printer info <printer> <server>"
2149 "\n\tlookup info in directory for printer on server"
2150 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
2151 "\nnet ads printer publish <printername>"
2152 "\n\tpublish printer in directory"
2153 "\n\t(note: printer name is required)\n"
2154 "\nnet ads printer remove <printername>"
2155 "\n\tremove printer from directory"
2156 "\n\t(note: printer name is required)\n"));
2160 /*******************************************************************
2161 ********************************************************************/
2163 static int net_ads_printer_search(struct net_context *c,
2167 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2168 ADS_STRUCT *ads = NULL;
2170 LDAPMessage *res = NULL;
2173 if (c->display_usage) {
2175 "net ads printer search\n"
2178 _("List printers in the AD"));
2179 TALLOC_FREE(tmp_ctx);
2183 status = ads_startup(c, false, tmp_ctx, &ads);
2184 if (!ADS_ERR_OK(status)) {
2188 status = ads_find_printers(ads, &res);
2189 if (!ADS_ERR_OK(status)) {
2190 d_fprintf(stderr, _("ads_find_printer: %s\n"),
2191 ads_errstr(status));
2195 if (ads_count_replies(ads, res) == 0) {
2196 d_fprintf(stderr, _("No results found\n"));
2204 ads_msgfree(ads, res);
2205 TALLOC_FREE(tmp_ctx);
2209 static int net_ads_printer_info(struct net_context *c,
2213 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2214 ADS_STRUCT *ads = NULL;
2216 const char *servername = NULL;
2217 const char *printername = NULL;
2218 LDAPMessage *res = NULL;
2221 if (c->display_usage) {
2224 _("net ads printer info [printername [servername]]\n"
2225 " Display printer info from AD\n"
2226 " printername\tPrinter name or wildcard\n"
2227 " servername\tName of the print server\n"));
2228 TALLOC_FREE(tmp_ctx);
2232 status = ads_startup(c, false, tmp_ctx, &ads);
2233 if (!ADS_ERR_OK(status)) {
2238 printername = argv[0];
2244 servername = argv[1];
2246 servername = lp_netbios_name();
2249 status = ads_find_printer_on_server(ads, &res, printername, servername);
2250 if (!ADS_ERR_OK(status)) {
2251 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
2252 servername, ads_errstr(status));
2256 if (ads_count_replies(ads, res) == 0) {
2257 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
2265 ads_msgfree(ads, res);
2266 TALLOC_FREE(tmp_ctx);
2270 static int net_ads_printer_publish(struct net_context *c,
2274 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2275 ADS_STRUCT *ads = NULL;
2277 const char *servername = NULL;
2278 const char *printername = NULL;
2279 struct cli_state *cli = NULL;
2280 struct rpc_pipe_client *pipe_hnd = NULL;
2281 struct sockaddr_storage server_ss = { 0 };
2283 ADS_MODLIST mods = NULL;
2284 char *prt_dn = NULL;
2285 char *srv_dn = NULL;
2286 char **srv_cn = NULL;
2287 char *srv_cn_escaped = NULL;
2288 char *printername_escaped = NULL;
2289 LDAPMessage *res = NULL;
2293 if (argc < 1 || c->display_usage) {
2296 _("net ads printer publish <printername> [servername]\n"
2297 " Publish printer in AD\n"
2298 " printername\tName of the printer\n"
2299 " servername\tName of the print server\n"));
2300 TALLOC_FREE(tmp_ctx);
2304 mods = ads_init_mods(tmp_ctx);
2306 d_fprintf(stderr, _("Out of memory\n"));
2310 status = ads_startup(c, true, tmp_ctx, &ads);
2311 if (!ADS_ERR_OK(status)) {
2315 printername = argv[0];
2318 servername = argv[1];
2320 servername = lp_netbios_name();
2323 /* Get printer data from SPOOLSS */
2325 ok = resolve_name(servername, &server_ss, 0x20, false);
2327 d_fprintf(stderr, _("Could not find server %s\n"),
2332 cli_credentials_set_kerberos_state(c->creds,
2333 CRED_USE_KERBEROS_REQUIRED,
2336 nt_status = cli_full_connection_creds(&cli, lp_netbios_name(), servername,
2340 CLI_FULL_CONNECTION_IPC);
2342 if (NT_STATUS_IS_ERR(nt_status)) {
2343 d_fprintf(stderr, _("Unable to open a connection to %s to "
2344 "obtain data for %s\n"),
2345 servername, printername);
2349 /* Publish on AD server */
2351 ads_find_machine_acct(ads, &res, servername);
2353 if (ads_count_replies(ads, res) == 0) {
2354 d_fprintf(stderr, _("Could not find machine account for server "
2360 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
2361 srv_cn = ldap_explode_dn(srv_dn, 1);
2363 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
2364 printername_escaped = escape_rdn_val_string_alloc(printername);
2365 if (!srv_cn_escaped || !printername_escaped) {
2366 SAFE_FREE(srv_cn_escaped);
2367 SAFE_FREE(printername_escaped);
2368 d_fprintf(stderr, _("Internal error, out of memory!"));
2372 prt_dn = talloc_asprintf(tmp_ctx,
2375 printername_escaped,
2377 if (prt_dn == NULL) {
2378 SAFE_FREE(srv_cn_escaped);
2379 SAFE_FREE(printername_escaped);
2380 d_fprintf(stderr, _("Internal error, out of memory!"));
2384 SAFE_FREE(srv_cn_escaped);
2385 SAFE_FREE(printername_escaped);
2387 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss, &pipe_hnd);
2388 if (!NT_STATUS_IS_OK(nt_status)) {
2389 d_fprintf(stderr, _("Unable to open a connection to the spoolss pipe on %s\n"),
2394 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd,
2401 status = ads_add_printer_entry(ads, prt_dn, tmp_ctx, &mods);
2402 if (!ADS_ERR_OK(status)) {
2403 d_fprintf(stderr, "ads_publish_printer: %s\n",
2404 ads_errstr(status));
2408 d_printf("published printer\n");
2412 talloc_destroy(tmp_ctx);
2417 static int net_ads_printer_remove(struct net_context *c,
2421 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2422 ADS_STRUCT *ads = NULL;
2424 const char *servername = NULL;
2425 char *prt_dn = NULL;
2426 LDAPMessage *res = NULL;
2429 if (argc < 1 || c->display_usage) {
2432 _("net ads printer remove <printername> [servername]\n"
2433 " Remove a printer from the AD\n"
2434 " printername\tName of the printer\n"
2435 " servername\tName of the print server\n"));
2436 TALLOC_FREE(tmp_ctx);
2440 status = ads_startup(c, true, tmp_ctx, &ads);
2441 if (!ADS_ERR_OK(status)) {
2446 servername = argv[1];
2448 servername = lp_netbios_name();
2451 status = ads_find_printer_on_server(ads, &res, argv[0], servername);
2452 if (!ADS_ERR_OK(status)) {
2453 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"),
2454 ads_errstr(status));
2458 if (ads_count_replies(ads, res) == 0) {
2459 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
2463 prt_dn = ads_get_dn(ads, tmp_ctx, res);
2464 if (prt_dn == NULL) {
2465 d_fprintf(stderr, _("Out of memory\n"));
2469 status = ads_del_dn(ads, prt_dn);
2470 if (!ADS_ERR_OK(status)) {
2471 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(status));
2477 ads_msgfree(ads, res);
2478 TALLOC_FREE(tmp_ctx);
2482 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
2484 struct functable func[] = {
2487 net_ads_printer_search,
2489 N_("Search for a printer"),
2490 N_("net ads printer search\n"
2491 " Search for a printer")
2495 net_ads_printer_info,
2497 N_("Display printer information"),
2498 N_("net ads printer info\n"
2499 " Display printer information")
2503 net_ads_printer_publish,
2505 N_("Publish a printer"),
2506 N_("net ads printer publish\n"
2507 " Publish a printer")
2511 net_ads_printer_remove,
2513 N_("Delete a printer"),
2514 N_("net ads printer remove\n"
2515 " Delete a printer")
2517 {NULL, NULL, 0, NULL, NULL}
2520 return net_run_function(c, argc, argv, "net ads printer", func);
2524 static int net_ads_password(struct net_context *c, int argc, const char **argv)
2526 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2527 ADS_STRUCT *ads = NULL;
2528 const char *auth_principal = cli_credentials_get_username(c->creds);
2529 const char *auth_password = cli_credentials_get_password(c->creds);
2530 const char *realm = NULL;
2531 char *new_password = NULL;
2533 char *prompt = NULL;
2534 const char *user = NULL;
2535 char pwd[256] = {0};
2539 if (c->display_usage) {
2542 _("net ads password <username>\n"
2543 " Change password for user\n"
2544 " username\tName of user to change password for\n"));
2545 TALLOC_FREE(tmp_ctx);
2549 if (auth_principal == NULL || auth_password == NULL) {
2550 d_fprintf(stderr, _("You must supply an administrator "
2551 "username/password\n"));
2552 TALLOC_FREE(tmp_ctx);
2557 d_fprintf(stderr, _("ERROR: You must say which username to "
2558 "change password for\n"));
2559 TALLOC_FREE(tmp_ctx);
2563 if (strchr_m(argv[0], '@')) {
2564 user = talloc_strdup(tmp_ctx, argv[0]);
2566 user = talloc_asprintf(tmp_ctx, "%s@%s", argv[0], lp_realm());
2569 d_fprintf(stderr, _("Out of memory\n"));
2573 use_in_memory_ccache();
2574 chr = strchr_m(auth_principal, '@');
2581 /* use the realm so we can eventually change passwords for users
2582 in realms other than default */
2583 ads = ads_init(tmp_ctx,
2592 /* we don't actually need a full connect, but it's the easy way to
2593 fill in the KDC's addresss */
2596 if (!ads->config.realm) {
2597 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
2601 if (argv[1] != NULL) {
2602 new_password = talloc_strdup(tmp_ctx, argv[1]);
2606 prompt = talloc_asprintf(tmp_ctx, _("Enter new password for %s:"), user);
2607 if (prompt == NULL) {
2608 d_fprintf(stderr, _("Out of memory\n"));
2612 rc = samba_getpass(prompt, pwd, sizeof(pwd), false, true);
2616 new_password = talloc_strdup(tmp_ctx, pwd);
2617 memset(pwd, '\0', sizeof(pwd));
2620 if (new_password == NULL) {
2621 d_fprintf(stderr, _("Out of memory\n"));
2625 status = kerberos_set_password(ads->auth.kdc_server,
2630 ads->auth.time_offset);
2631 memset(new_password, '\0', strlen(new_password));
2632 if (!ADS_ERR_OK(status)) {
2633 d_fprintf(stderr, _("Password change failed: %s\n"),
2634 ads_errstr(status));
2638 d_printf(_("Password change for %s completed.\n"), user);
2642 TALLOC_FREE(tmp_ctx);
2646 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2648 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2649 ADS_STRUCT *ads = NULL;
2650 char *host_principal = NULL;
2651 char *my_name = NULL;
2655 if (c->display_usage) {
2657 "net ads changetrustpw\n"
2660 _("Change the machine account's trust password"));
2661 TALLOC_FREE(tmp_ctx);
2665 if (!secrets_init()) {
2666 DEBUG(1,("Failed to initialise secrets database\n"));
2670 net_warn_member_options();
2672 net_use_krb_machine_account(c);
2674 use_in_memory_ccache();
2676 status = ads_startup(c, true, tmp_ctx, &ads);
2677 if (!ADS_ERR_OK(status)) {
2681 my_name = talloc_asprintf_strlower_m(tmp_ctx, "%s", lp_netbios_name());
2682 if (my_name == NULL) {
2683 d_fprintf(stderr, _("Out of memory\n"));
2687 host_principal = talloc_asprintf(tmp_ctx, "%s$@%s", my_name, ads->config.realm);
2688 if (host_principal == NULL) {
2689 d_fprintf(stderr, _("Out of memory\n"));
2693 d_printf(_("Changing password for principal: %s\n"), host_principal);
2695 status = ads_change_trust_account_password(ads, host_principal);
2696 if (!ADS_ERR_OK(status)) {
2697 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(status));
2701 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2703 if (USE_SYSTEM_KEYTAB) {
2704 d_printf(_("Attempting to update system keytab with new password.\n"));
2705 if (ads_keytab_create_default(ads)) {
2706 d_printf(_("Failed to update system keytab.\n"));
2712 TALLOC_FREE(tmp_ctx);
2718 help for net ads search
2720 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2723 "\nnet ads search <expression> <attributes...>\n"
2724 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2725 "The expression is a standard LDAP search expression, and the\n"
2726 "attributes are a list of LDAP fields to show in the results.\n\n"
2727 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2729 net_common_flags_usage(c, argc, argv);
2735 general ADS search function. Useful in diagnosing problems in ADS
2737 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2739 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2740 ADS_STRUCT *ads = NULL;
2742 const char *ldap_exp = NULL;
2743 const char **attrs = NULL;
2744 LDAPMessage *res = NULL;
2747 if (argc < 1 || c->display_usage) {
2748 TALLOC_FREE(tmp_ctx);
2749 return net_ads_search_usage(c, argc, argv);
2752 status = ads_startup(c, false, tmp_ctx, &ads);
2753 if (!ADS_ERR_OK(status)) {
2760 status = ads_do_search_retry(ads,
2761 ads->config.bind_path,
2766 if (!ADS_ERR_OK(status)) {
2767 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(status));
2771 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2773 /* dump the results */
2778 ads_msgfree(ads, res);
2779 TALLOC_FREE(tmp_ctx);
2785 help for net ads search
2787 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2790 "\nnet ads dn <dn> <attributes...>\n"
2791 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2792 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2793 "to show in the results\n\n"
2794 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2795 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2797 net_common_flags_usage(c, argc, argv);
2803 general ADS search function. Useful in diagnosing problems in ADS
2805 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2807 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2808 ADS_STRUCT *ads = NULL;
2810 const char *dn = NULL;
2811 const char **attrs = NULL;
2812 LDAPMessage *res = NULL;
2815 if (argc < 1 || c->display_usage) {
2816 TALLOC_FREE(tmp_ctx);
2817 return net_ads_dn_usage(c, argc, argv);
2820 status = ads_startup(c, false, tmp_ctx, &ads);
2821 if (!ADS_ERR_OK(status)) {
2828 status = ads_do_search_all(ads,
2834 if (!ADS_ERR_OK(status)) {
2835 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(status));
2839 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2841 /* dump the results */
2846 ads_msgfree(ads, res);
2847 TALLOC_FREE(tmp_ctx);
2852 help for net ads sid search
2854 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2857 "\nnet ads sid <sid> <attributes...>\n"
2858 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2859 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2860 "to show in the results\n\n"
2861 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2863 net_common_flags_usage(c, argc, argv);
2869 general ADS search function. Useful in diagnosing problems in ADS
2871 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2873 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2874 ADS_STRUCT *ads = NULL;
2876 const char *sid_string = NULL;
2877 const char **attrs = NULL;
2878 LDAPMessage *res = NULL;
2879 struct dom_sid sid = { 0 };
2882 if (argc < 1 || c->display_usage) {
2883 TALLOC_FREE(tmp_ctx);
2884 return net_ads_sid_usage(c, argc, argv);
2887 status = ads_startup(c, false, tmp_ctx, &ads);
2888 if (!ADS_ERR_OK(status)) {
2892 sid_string = argv[0];
2895 if (!string_to_sid(&sid, sid_string)) {
2896 d_fprintf(stderr, _("could not convert sid\n"));
2900 status = ads_search_retry_sid(ads, &res, &sid, attrs);
2901 if (!ADS_ERR_OK(status)) {
2902 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(status));
2906 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2908 /* dump the results */
2913 ads_msgfree(ads, res);
2914 TALLOC_FREE(tmp_ctx);
2918 static int net_ads_keytab_flush(struct net_context *c,
2922 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2923 ADS_STRUCT *ads = NULL;
2927 if (c->display_usage) {
2929 "net ads keytab flush\n"
2932 _("Delete the whole keytab"));
2933 TALLOC_FREE(tmp_ctx);
2937 if (!c->opt_user_specified && c->opt_password == NULL) {
2938 net_use_krb_machine_account(c);
2941 status = ads_startup(c, true, tmp_ctx, &ads);
2942 if (!ADS_ERR_OK(status)) {
2946 ret = ads_keytab_flush(ads);
2948 TALLOC_FREE(tmp_ctx);
2952 static int net_ads_keytab_add(struct net_context *c,
2957 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2958 ADS_STRUCT *ads = NULL;
2963 if (c->display_usage) {
2966 _("net ads keytab add <principal> [principal ...]\n"
2967 " Add principals to local keytab\n"
2968 " principal\tKerberos principal to add to "
2970 TALLOC_FREE(tmp_ctx);
2974 net_warn_member_options();
2976 d_printf(_("Processing principals to add...\n"));
2978 if (!c->opt_user_specified && c->opt_password == NULL) {
2979 net_use_krb_machine_account(c);
2982 status = ads_startup(c, true, tmp_ctx, &ads);
2983 if (!ADS_ERR_OK(status)) {
2987 for (ret = 0, i = 0; i < argc; i++) {
2988 ret |= ads_keytab_add_entry(ads, argv[i], update_ads);
2991 TALLOC_FREE(tmp_ctx);
2995 static int net_ads_keytab_add_default(struct net_context *c,
2999 return net_ads_keytab_add(c, argc, argv, false);
3002 static int net_ads_keytab_add_update_ads(struct net_context *c,
3006 return net_ads_keytab_add(c, argc, argv, true);
3009 static int net_ads_keytab_delete(struct net_context *c,
3013 TALLOC_CTX *tmp_ctx = talloc_stackframe();
3014 ADS_STRUCT *ads = NULL;
3019 if (c->display_usage) {
3022 _("net ads keytab delete <principal> [principal ...]\n"
3023 " Remove entries for service principal, "
3024 " from the keytab file only."
3025 " Remove principals from local keytab\n"
3026 " principal\tKerberos principal to remove from "
3028 TALLOC_FREE(tmp_ctx);
3032 d_printf(_("Processing principals to delete...\n"));
3034 if (!c->opt_user_specified && c->opt_password == NULL) {
3035 net_use_krb_machine_account(c);
3038 status = ads_startup(c, true, tmp_ctx, &ads);
3039 if (!ADS_ERR_OK(status)) {
3043 for (ret = 0, i = 0; i < argc; i++) {
3044 ret |= ads_keytab_delete_entry(ads, argv[i]);
3047 TALLOC_FREE(tmp_ctx);
3051 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
3053 TALLOC_CTX *tmp_ctx = talloc_stackframe();
3054 ADS_STRUCT *ads = NULL;
3058 if (c->display_usage) {
3060 "net ads keytab create\n"
3063 _("Create new default keytab"));
3064 TALLOC_FREE(tmp_ctx);
3068 net_warn_member_options();
3070 if (!c->opt_user_specified && c->opt_password == NULL) {
3071 net_use_krb_machine_account(c);
3074 status = ads_startup(c, true, tmp_ctx, &ads);
3075 if (!ADS_ERR_OK(status)) {
3079 ret = ads_keytab_create_default(ads);
3081 TALLOC_FREE(tmp_ctx);
3085 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
3087 const char *keytab = NULL;
3089 if (c->display_usage) {
3092 _("net ads keytab list [keytab]\n"
3093 " List a local keytab\n"
3094 " keytab\tKeytab to list\n"));
3102 return ads_keytab_list(keytab);
3106 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
3108 struct functable func[] = {
3111 net_ads_keytab_add_default,
3113 N_("Add a service principal"),
3114 N_("net ads keytab add\n"
3115 " Add a service principal, updates keytab file only.")
3119 net_ads_keytab_delete,
3121 N_("Delete a service principal"),
3122 N_("net ads keytab delete\n"
3123 " Remove entries for service principal, from the keytab file only.")
3127 net_ads_keytab_add_update_ads,
3129 N_("Add a service principal"),
3130 N_("net ads keytab add_update_ads\n"
3131 " Add a service principal, depending on the param passed may update ADS computer object in addition to the keytab file.")
3135 net_ads_keytab_create,
3137 N_("Create a fresh keytab"),
3138 N_("net ads keytab create\n"
3139 " Create a fresh keytab or update existing one.")
3143 net_ads_keytab_flush,
3145 N_("Remove all keytab entries"),
3146 N_("net ads keytab flush\n"
3147 " Remove all keytab entries")
3151 net_ads_keytab_list,
3153 N_("List a keytab"),
3154 N_("net ads keytab list\n"
3157 {NULL, NULL, 0, NULL, NULL}
3160 if (!USE_KERBEROS_KEYTAB) {
3161 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
3162 "keytab method to use keytab functions.\n"));
3165 return net_run_function(c, argc, argv, "net ads keytab", func);
3168 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
3172 if (c->display_usage) {
3174 "net ads kerberos renew\n"
3177 _("Renew TGT from existing credential cache"));
3181 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
3183 d_printf(_("failed to renew kerberos ticket: %s\n"),
3184 error_message(ret));
3189 static int net_ads_kerberos_pac_common(struct net_context *c, int argc, const char **argv,
3190 struct PAC_DATA_CTR **pac_data_ctr)
3194 const char *impersonate_princ_s = NULL;
3195 const char *local_service = NULL;
3198 for (i=0; i<argc; i++) {
3199 if (strnequal(argv[i], "impersonate", strlen("impersonate"))) {
3200 impersonate_princ_s = get_string_param(argv[i]);
3201 if (impersonate_princ_s == NULL) {
3205 if (strnequal(argv[i], "local_service", strlen("local_service"))) {
3206 local_service = get_string_param(argv[i]);
3207 if (local_service == NULL) {
3213 if (local_service == NULL) {
3214 local_service = talloc_asprintf(c, "%s$@%s",
3215 lp_netbios_name(), lp_realm());
3216 if (local_service == NULL) {
3221 c->opt_password = net_prompt_pass(c, c->opt_user_name);
3223 status = kerberos_return_pac(c,
3232 2592000, /* one month */
3233 impersonate_princ_s,
3238 if (!NT_STATUS_IS_OK(status)) {
3239 d_printf(_("failed to query kerberos PAC: %s\n"),
3249 static int net_ads_kerberos_pac_dump(struct net_context *c, int argc, const char **argv)
3251 struct PAC_DATA_CTR *pac_data_ctr = NULL;
3254 enum PAC_TYPE type = 0;
3256 if (c->display_usage) {
3258 "net ads kerberos pac dump [impersonate=string] [local_service=string] [pac_buffer_type=int]\n"
3261 _("Dump the Kerberos PAC"));
3265 for (i=0; i<argc; i++) {
3266 if (strnequal(argv[i], "pac_buffer_type", strlen("pac_buffer_type"))) {
3267 type = get_int_param(argv[i]);
3271 ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3280 s = NDR_PRINT_STRUCT_STRING(c, PAC_DATA,
3281 pac_data_ctr->pac_data);
3283 d_printf(_("The Pac: %s\n"), s);
3290 num_buffers = pac_data_ctr->pac_data->num_buffers;
3292 for (i=0; i<num_buffers; i++) {
3296 if (pac_data_ctr->pac_data->buffers[i].type != type) {
3300 s = NDR_PRINT_UNION_STRING(c, PAC_INFO, type,
3301 pac_data_ctr->pac_data->buffers[i].info);
3303 d_printf(_("The Pac: %s\n"), s);
3312 static int net_ads_kerberos_pac_save(struct net_context *c, int argc, const char **argv)
3314 struct PAC_DATA_CTR *pac_data_ctr = NULL;
3315 char *filename = NULL;
3319 if (c->display_usage) {
3321 "net ads kerberos pac save [impersonate=string] [local_service=string] [filename=string]\n"
3324 _("Save the Kerberos PAC"));
3328 for (i=0; i<argc; i++) {
3329 if (strnequal(argv[i], "filename", strlen("filename"))) {
3330 filename = get_string_param(argv[i]);
3331 if (filename == NULL) {
3337 ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3342 if (filename == NULL) {
3343 d_printf(_("please define \"filename=<filename>\" to save the PAC\n"));
3347 /* save the raw format */
3348 if (!file_save(filename, pac_data_ctr->pac_blob.data, pac_data_ctr->pac_blob.length)) {
3349 d_printf(_("failed to save PAC in %s\n"), filename);
3356 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
3358 struct functable func[] = {
3361 net_ads_kerberos_pac_dump,
3363 N_("Dump Kerberos PAC"),
3364 N_("net ads kerberos pac dump\n"
3365 " Dump a Kerberos PAC to stdout")
3369 net_ads_kerberos_pac_save,
3371 N_("Save Kerberos PAC"),
3372 N_("net ads kerberos pac save\n"
3373 " Save a Kerberos PAC in a file")
3376 {NULL, NULL, 0, NULL, NULL}
3379 return net_run_function(c, argc, argv, "net ads kerberos pac", func);
3382 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
3387 if (c->display_usage) {
3389 "net ads kerberos kinit\n"
3392 _("Get Ticket Granting Ticket (TGT) for the user"));
3396 c->opt_password = net_prompt_pass(c, c->opt_user_name);
3398 ret = kerberos_kinit_password_ext(c->opt_user_name,
3406 2592000, /* one month */
3412 d_printf(_("failed to kinit password: %s\n"),
3418 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3420 struct functable func[] = {
3423 net_ads_kerberos_kinit,
3425 N_("Retrieve Ticket Granting Ticket (TGT)"),
3426 N_("net ads kerberos kinit\n"
3427 " Receive Ticket Granting Ticket (TGT)")
3431 net_ads_kerberos_renew,
3433 N_("Renew Ticket Granting Ticket from credential cache"),
3434 N_("net ads kerberos renew\n"
3435 " Renew Ticket Granting Ticket (TGT) from "
3440 net_ads_kerberos_pac,
3442 N_("Dump Kerberos PAC"),
3443 N_("net ads kerberos pac\n"
3444 " Dump Kerberos PAC")
3446 {NULL, NULL, 0, NULL, NULL}
3449 return net_run_function(c, argc, argv, "net ads kerberos", func);
3452 static int net_ads_setspn_list(struct net_context *c,
3456 TALLOC_CTX *tmp_ctx = talloc_stackframe();
3457 ADS_STRUCT *ads = NULL;
3462 if (c->display_usage) {
3465 _("net ads setspn list <machinename>\n"));
3466 TALLOC_FREE(tmp_ctx);
3470 status = ads_startup(c, true, tmp_ctx, &ads);
3471 if (!ADS_ERR_OK(status)) {
3476 ok = ads_setspn_list(ads, argv[0]);
3478 ok = ads_setspn_list(ads, lp_netbios_name());
3483 TALLOC_FREE(tmp_ctx);
3487 static int net_ads_setspn_add(struct net_context *c, int argc, const char **argv)
3489 TALLOC_CTX *tmp_ctx = talloc_stackframe();
3490 ADS_STRUCT *ads = NULL;
3495 if (c->display_usage || argc < 1) {
3498 _("net ads setspn add <machinename> SPN\n"));
3499 TALLOC_FREE(tmp_ctx);
3503 status = ads_startup(c, true, tmp_ctx, &ads);
3504 if (!ADS_ERR_OK(status)) {
3509 ok = ads_setspn_add(ads, argv[0], argv[1]);
3511 ok = ads_setspn_add(ads, lp_netbios_name(), argv[0]);
3516 TALLOC_FREE(tmp_ctx);
3520 static int net_ads_setspn_delete(struct net_context *c, int argc, const char **argv)
3522 TALLOC_CTX *tmp_ctx = talloc_stackframe();
3523 ADS_STRUCT *ads = NULL;
3528 if (c->display_usage || argc < 1) {
3531 _("net ads setspn delete <machinename> SPN\n"));
3532 TALLOC_FREE(tmp_ctx);
3536 status = ads_startup(c, true, tmp_ctx, &ads);
3537 if (!ADS_ERR_OK(status)) {
3542 ok = ads_setspn_delete(ads, argv[0], argv[1]);
3544 ok = ads_setspn_delete(ads, lp_netbios_name(), argv[0]);
3549 TALLOC_FREE(tmp_ctx);
3553 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
3555 struct functable func[] = {
3558 net_ads_setspn_list,
3560 N_("List Service Principal Names (SPN)"),
3561 N_("net ads setspn list machine\n"
3562 " List Service Principal Names (SPN)")
3568 N_("Add Service Principal Names (SPN)"),
3569 N_("net ads setspn add machine spn\n"
3570 " Add Service Principal Names (SPN)")
3574 net_ads_setspn_delete,
3576 N_("Delete Service Principal Names (SPN)"),
3577 N_("net ads setspn delete machine spn\n"
3578 " Delete Service Principal Names (SPN)")
3580 {NULL, NULL, 0, NULL, NULL}
3583 return net_run_function(c, argc, argv, "net ads setspn", func);
3586 static int net_ads_enctype_lookup_account(struct net_context *c,
3588 const char *account,
3590 const char **enctype_str)
3593 const char *attrs[] = {
3594 "msDS-SupportedEncryptionTypes",
3601 filter = talloc_asprintf(c, "(&(objectclass=user)(sAMAccountName=%s))",
3603 if (filter == NULL) {
3607 status = ads_search(ads, res, filter, attrs);
3608 if (!ADS_ERR_OK(status)) {
3609 d_printf(_("no account found with filter: %s\n"), filter);
3613 count = ads_count_replies(ads, *res);
3618 d_printf(_("no account found with filter: %s\n"), filter);
3621 d_printf(_("multiple accounts found with filter: %s\n"), filter);
3626 *enctype_str = ads_pull_string(ads, c, *res,
3627 "msDS-SupportedEncryptionTypes");
3628 if (*enctype_str == NULL) {
3629 d_printf(_("no msDS-SupportedEncryptionTypes attribute found\n"));
3639 static void net_ads_enctype_dump_enctypes(const char *username,
3640 const char *enctype_str)
3642 int enctypes = atoi(enctype_str);
3644 d_printf(_("'%s' uses \"msDS-SupportedEncryptionTypes\": %d (0x%08x)\n"),
3645 username, enctypes, enctypes);
3647 printf("[%s] 0x%08x DES-CBC-CRC\n",
3648 enctypes & ENC_CRC32 ? "X" : " ",
3650 printf("[%s] 0x%08x DES-CBC-MD5\n",
3651 enctypes & ENC_RSA_MD5 ? "X" : " ",
3653 printf("[%s] 0x%08x RC4-HMAC\n",
3654 enctypes & ENC_RC4_HMAC_MD5 ? "X" : " ",
3656 printf("[%s] 0x%08x AES128-CTS-HMAC-SHA1-96\n",
3657 enctypes & ENC_HMAC_SHA1_96_AES128 ? "X" : " ",
3658 ENC_HMAC_SHA1_96_AES128);
3659 printf("[%s] 0x%08x AES256-CTS-HMAC-SHA1-96\n",
3660 enctypes & ENC_HMAC_SHA1_96_AES256 ? "X" : " ",
3661 ENC_HMAC_SHA1_96_AES256);
3664 static int net_ads_enctypes_list(struct net_context *c, int argc, const char **argv)
3666 TALLOC_CTX *tmp_ctx = talloc_stackframe();
3668 ADS_STRUCT *ads = NULL;
3669 LDAPMessage *res = NULL;
3670 const char *str = NULL;
3673 if (c->display_usage || (argc < 1)) {
3675 "net ads enctypes list\n"
3678 _("List supported enctypes"));
3679 TALLOC_FREE(tmp_ctx);
3683 status = ads_startup(c, false, tmp_ctx, &ads);
3684 if (!ADS_ERR_OK(status)) {
3688 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3693 net_ads_enctype_dump_enctypes(argv[0], str);
3697 ads_msgfree(ads, res);
3698 TALLOC_FREE(tmp_ctx);
3702 static int net_ads_enctypes_set(struct net_context *c, int argc, const char **argv)
3704 TALLOC_CTX *tmp_ctx = talloc_stackframe();
3707 ADS_STRUCT *ads = NULL;
3708 LDAPMessage *res = NULL;
3709 const char *etype_list_str = NULL;
3710 const char *dn = NULL;
3711 ADS_MODLIST mods = NULL;
3712 uint32_t etype_list;
3713 const char *str = NULL;
3715 if (c->display_usage || argc < 1) {
3717 "net ads enctypes set <sAMAccountName> [enctypes]\n"
3720 _("Set supported enctypes"));
3721 TALLOC_FREE(tmp_ctx);
3725 status = ads_startup(c, false, tmp_ctx, &ads);
3726 if (!ADS_ERR_OK(status)) {
3730 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3735 dn = ads_get_dn(ads, tmp_ctx, res);
3741 etype_list |= ENC_RC4_HMAC_MD5;
3742 etype_list |= ENC_HMAC_SHA1_96_AES128;
3743 etype_list |= ENC_HMAC_SHA1_96_AES256;
3745 if (argv[1] != NULL) {
3746 sscanf(argv[1], "%i", &etype_list);
3749 etype_list_str = talloc_asprintf(tmp_ctx, "%d", etype_list);
3750 if (!etype_list_str) {
3754 mods = ads_init_mods(tmp_ctx);
3759 status = ads_mod_str(tmp_ctx, &mods, "msDS-SupportedEncryptionTypes",
3761 if (!ADS_ERR_OK(status)) {
3765 status = ads_gen_mod(ads, dn, mods);
3766 if (!ADS_ERR_OK(status)) {
3767 d_printf(_("failed to add msDS-SupportedEncryptionTypes: %s\n"),
3768 ads_errstr(status));
3772 ads_msgfree(ads, res);
3775 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3780 net_ads_enctype_dump_enctypes(argv[0], str);
3784 ads_msgfree(ads, res);
3785 TALLOC_FREE(tmp_ctx);
3789 static int net_ads_enctypes_delete(struct net_context *c, int argc, const char **argv)
3791 TALLOC_CTX *tmp_ctx = talloc_stackframe();
3794 ADS_STRUCT *ads = NULL;
3795 LDAPMessage *res = NULL;
3796 const char *dn = NULL;
3797 ADS_MODLIST mods = NULL;
3799 if (c->display_usage || argc < 1) {
3801 "net ads enctypes delete <sAMAccountName>\n"
3804 _("Delete supported enctypes"));
3805 TALLOC_FREE(tmp_ctx);
3809 status = ads_startup(c, false, tmp_ctx, &ads);
3810 if (!ADS_ERR_OK(status)) {
3814 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3819 dn = ads_get_dn(ads, tmp_ctx, res);
3824 mods = ads_init_mods(tmp_ctx);
3829 status = ads_mod_str(tmp_ctx, &mods, "msDS-SupportedEncryptionTypes", NULL);
3830 if (!ADS_ERR_OK(status)) {
3834 status = ads_gen_mod(ads, dn, mods);
3835 if (!ADS_ERR_OK(status)) {
3836 d_printf(_("failed to remove msDS-SupportedEncryptionTypes: %s\n"),
3837 ads_errstr(status));
3844 ads_msgfree(ads, res);
3845 TALLOC_FREE(tmp_ctx);
3849 static int net_ads_enctypes(struct net_context *c, int argc, const char **argv)
3851 struct functable func[] = {
3854 net_ads_enctypes_list,
3856 N_("List the supported encryption types"),
3857 N_("net ads enctypes list\n"
3858 " List the supported encryption types")
3862 net_ads_enctypes_set,
3864 N_("Set the supported encryption types"),
3865 N_("net ads enctypes set\n"
3866 " Set the supported encryption types")
3870 net_ads_enctypes_delete,
3872 N_("Delete the supported encryption types"),
3873 N_("net ads enctypes delete\n"
3874 " Delete the supported encryption types")
3877 {NULL, NULL, 0, NULL, NULL}
3880 return net_run_function(c, argc, argv, "net ads enctypes", func);
3884 int net_ads(struct net_context *c, int argc, const char **argv)
3886 struct functable func[] = {
3891 N_("Display details on remote ADS server"),
3893 " Display details on remote ADS server")
3899 N_("Join the local machine to ADS realm"),
3901 " Join the local machine to ADS realm")
3907 N_("Validate machine account"),
3908 N_("net ads testjoin\n"
3909 " Validate machine account")
3915 N_("Remove the local machine from ADS"),
3916 N_("net ads leave\n"
3917 " Remove the local machine from ADS")
3923 N_("Display machine account details"),
3924 N_("net ads status\n"
3925 " Display machine account details")
3931 N_("List/modify users"),
3933 " List/modify users")
3939 N_("List/modify groups"),
3940 N_("net ads group\n"
3941 " List/modify groups")
3947 N_("Issue dynamic DNS update"),
3949 " Issue dynamic DNS update")
3955 N_("Change user passwords"),
3956 N_("net ads password\n"
3957 " Change user passwords")
3961 net_ads_changetrustpw,
3963 N_("Change trust account password"),
3964 N_("net ads changetrustpw\n"
3965 " Change trust account password")
3971 N_("List/modify printer entries"),
3972 N_("net ads printer\n"
3973 " List/modify printer entries")
3979 N_("Issue LDAP search using filter"),
3980 N_("net ads search\n"
3981 " Issue LDAP search using filter")
3987 N_("Issue LDAP search by DN"),
3989 " Issue LDAP search by DN")
3995 N_("Issue LDAP search by SID"),
3997 " Issue LDAP search by SID")
4003 N_("Display workgroup name"),
4004 N_("net ads workgroup\n"
4005 " Display the workgroup name")
4011 N_("Perform CLDAP query on DC"),
4012 N_("net ads lookup\n"
4013 " Find the ADS DC using CLDAP lookups")
4019 N_("Manage local keytab file"),
4020 N_("net ads keytab\n"
4021 " Manage local keytab file")
4027 N_("Manage Service Principal Names (SPN)s"),
4028 N_("net ads spnset\n"
4029 " Manage Service Principal Names (SPN)s")
4035 N_("Manage group policy objects"),
4037 " Manage group policy objects")
4043 N_("Manage kerberos keytab"),
4044 N_("net ads kerberos\n"
4045 " Manage kerberos keytab")
4051 N_("List/modify supported encryption types"),
4052 N_("net ads enctypes\n"
4053 " List/modify enctypes")
4055 {NULL, NULL, 0, NULL, NULL}
4058 return net_run_function(c, argc, argv, "net ads", func);
4063 static int net_ads_noads(void)
4065 d_fprintf(stderr, _("ADS support not compiled in\n"));
4069 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
4071 return net_ads_noads();
4074 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
4076 return net_ads_noads();
4079 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
4081 return net_ads_noads();
4084 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
4086 return net_ads_noads();
4089 int net_ads_join(struct net_context *c, int argc, const char **argv)
4091 return net_ads_noads();
4094 int net_ads_user(struct net_context *c, int argc, const char **argv)
4096 return net_ads_noads();
4099 int net_ads_group(struct net_context *c, int argc, const char **argv)
4101 return net_ads_noads();
4104 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
4106 return net_ads_noads();
4109 /* this one shouldn't display a message */
4110 int net_ads_check(struct net_context *c)
4115 int net_ads_check_our_domain(struct net_context *c)
4120 int net_ads(struct net_context *c, int argc, const char **argv)
4122 return net_ads_noads();
4125 #endif /* HAVE_ADS */