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 = discard_const_p(char, c->opt_target_workgroup);
440 ads->ldap.port = 389;
443 ret = net_ads_cldap_netlogon(c, ads);
446 TALLOC_FREE(tmp_ctx);
453 static int net_ads_info_json(ADS_STRUCT *ads)
456 char addr[INET6_ADDRSTRLEN];
458 struct json_object jsobj = json_new_object();
460 if (json_is_invalid(&jsobj)) {
461 d_fprintf(stderr, _("error setting up JSON value\n"));
466 pass_time = secrets_fetch_pass_last_set_time(ads->server.workgroup);
468 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
470 ret = json_add_string (&jsobj, "LDAP server", addr);
475 ret = json_add_string (&jsobj, "LDAP server name",
476 ads->config.ldap_server_name);
481 ret = json_add_string (&jsobj, "Realm", ads->config.realm);
486 ret = json_add_string (&jsobj, "Bind Path", ads->config.bind_path);
491 ret = json_add_int (&jsobj, "LDAP port", ads->ldap.port);
496 ret = json_add_int (&jsobj, "Server time", ads->config.current_time);
501 ret = json_add_string (&jsobj, "KDC server", ads->auth.kdc_server);
506 ret = json_add_int (&jsobj, "Server time offset",
507 ads->auth.time_offset);
512 ret = json_add_int (&jsobj, "Last machine account password change",
518 ret = output_json(&jsobj);
525 #else /* [HAVE_JANSSON] */
527 static int net_ads_info_json(ADS_STRUCT *ads)
529 d_fprintf(stderr, _("JSON support not available\n"));
534 #endif /* [HAVE_JANSSON] */
538 static int net_ads_info(struct net_context *c, int argc, const char **argv)
540 TALLOC_CTX *tmp_ctx = talloc_stackframe();
541 ADS_STRUCT *ads = NULL;
543 char addr[INET6_ADDRSTRLEN];
547 if (c->display_usage) {
552 _("Display information about an Active Directory "
554 TALLOC_FREE(tmp_ctx);
558 status = ads_startup_nobind(c, false, tmp_ctx, &ads);
559 if (!ADS_ERR_OK(status)) {
560 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
564 if (!ads || !ads->config.realm) {
565 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
569 /* Try to set the server's current time since we didn't do a full
570 TCP LDAP session initially */
572 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
573 d_fprintf( stderr, _("Failed to get server's current time!\n"));
577 ret = net_ads_info_json(ads);
581 pass_time = secrets_fetch_pass_last_set_time(ads->server.workgroup);
583 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
585 d_printf(_("LDAP server: %s\n"), addr);
586 d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
587 d_printf(_("Realm: %s\n"), ads->config.realm);
588 d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
589 d_printf(_("LDAP port: %d\n"), ads->ldap.port);
590 d_printf(_("Server time: %s\n"),
591 http_timestring(tmp_ctx, ads->config.current_time));
593 d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
594 d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
596 d_printf(_("Last machine account password change: %s\n"),
597 http_timestring(tmp_ctx, pass_time));
602 TALLOC_FREE(tmp_ctx);
606 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
607 uint32_t auth_flags, ADS_STRUCT **ads_ret)
609 ADS_STRUCT *ads = NULL;
611 bool need_password = false;
612 bool second_time = false;
614 const char *realm = NULL;
615 bool tried_closest_dc = false;
616 enum credentials_use_kerberos krb5_state =
617 CRED_USE_KERBEROS_DISABLED;
619 /* lp_realm() should be handled by a command line param,
620 However, the join requires that realm be set in smb.conf
621 and compares our realm with the remote server's so this is
622 ok until someone needs more flexibility */
627 if (only_own_domain) {
630 realm = assume_own_realm(c);
633 ads = ads_init(realm,
634 c->opt_target_workgroup,
638 if (!c->opt_user_name) {
639 c->opt_user_name = "administrator";
642 if (c->opt_user_specified) {
643 need_password = true;
647 if (!c->opt_password && need_password && !c->opt_machine_pass) {
648 c->opt_password = net_prompt_pass(c, c->opt_user_name);
649 if (!c->opt_password) {
651 return ADS_ERROR(LDAP_NO_MEMORY);
655 if (c->opt_password) {
656 use_in_memory_ccache();
657 SAFE_FREE(ads->auth.password);
658 ads->auth.password = smb_xstrdup(c->opt_password);
661 SAFE_FREE(ads->auth.user_name);
662 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
664 ads->auth.flags |= auth_flags;
666 /* The ADS code will handle FIPS mode */
667 krb5_state = cli_credentials_get_kerberos_state(c->creds);
668 switch (krb5_state) {
669 case CRED_USE_KERBEROS_REQUIRED:
670 ads->auth.flags &= ~ADS_AUTH_DISABLE_KERBEROS;
671 ads->auth.flags &= ~ADS_AUTH_ALLOW_NTLMSSP;
673 case CRED_USE_KERBEROS_DESIRED:
674 ads->auth.flags &= ~ADS_AUTH_DISABLE_KERBEROS;
675 ads->auth.flags |= ADS_AUTH_ALLOW_NTLMSSP;
677 case CRED_USE_KERBEROS_DISABLED:
678 ads->auth.flags |= ADS_AUTH_DISABLE_KERBEROS;
679 ads->auth.flags |= ADS_AUTH_ALLOW_NTLMSSP;
684 * If the username is of the form "name@realm",
685 * extract the realm and convert to upper case.
686 * This is only used to establish the connection.
688 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
690 SAFE_FREE(ads->auth.realm);
691 ads->auth.realm = smb_xstrdup(cp);
692 if (!strupper_m(ads->auth.realm)) {
694 return ADS_ERROR(LDAP_NO_MEMORY);
698 status = ads_connect(ads);
700 if (!ADS_ERR_OK(status)) {
702 if (NT_STATUS_EQUAL(ads_ntstatus(status),
703 NT_STATUS_NO_LOGON_SERVERS)) {
704 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
709 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
710 need_password = true;
719 /* when contacting our own domain, make sure we use the closest DC.
720 * This is done by reconnecting to ADS because only the first call to
721 * ads_connect will give us our own sitename */
723 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
725 tried_closest_dc = true; /* avoid loop */
727 if (!ads_closest_dc(ads)) {
729 namecache_delete(ads->server.realm, 0x1C);
730 namecache_delete(ads->server.workgroup, 0x1C);
743 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
745 return ads_startup_int(c, only_own_domain, 0, ads);
748 ADS_STATUS ads_startup_nobind(struct net_context *c,
749 bool only_own_domain,
753 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
757 Check to see if connection can be made via ads.
758 ads_startup() stores the password in opt_password if it needs to so
759 that rpc or rap can use it without re-prompting.
761 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
766 ads = ads_init(realm, workgroup, host, ADS_SASL_PLAIN);
771 ads->auth.flags |= ADS_AUTH_NO_BIND;
773 status = ads_connect(ads);
774 if ( !ADS_ERR_OK(status) ) {
782 int net_ads_check_our_domain(struct net_context *c)
784 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
787 int net_ads_check(struct net_context *c)
789 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
793 determine the netbios workgroup name for a domain
795 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
797 TALLOC_CTX *tmp_ctx = talloc_stackframe();
798 ADS_STRUCT *ads = NULL;
800 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
804 if (c->display_usage) {
806 "net ads workgroup\n"
809 _("Print the workgroup name"));
810 TALLOC_FREE(tmp_ctx);
814 status = ads_startup_nobind(c, false, tmp_ctx, &ads);
815 if (!ADS_ERR_OK(status)) {
816 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
820 if (!ads->config.realm) {
821 ads->config.realm = discard_const_p(char, c->opt_target_workgroup);
822 ads->ldap.port = 389;
825 ok = ads_cldap_netlogon_5(tmp_ctx,
826 &ads->ldap.ss, ads->server.realm, &reply);
828 d_fprintf(stderr, _("CLDAP query failed!\n"));
832 d_printf(_("Workgroup: %s\n"), reply.domain_name);
837 TALLOC_FREE(tmp_ctx);
844 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
846 char **disp_fields = (char **) data_area;
848 if (!field) { /* must be end of record */
849 if (disp_fields[0]) {
850 if (!strchr_m(disp_fields[0], '$')) {
852 d_printf("%-21.21s %s\n",
853 disp_fields[0], disp_fields[1]);
855 d_printf("%s\n", disp_fields[0]);
858 SAFE_FREE(disp_fields[0]);
859 SAFE_FREE(disp_fields[1]);
862 if (!values) /* must be new field, indicate string field */
864 if (strcasecmp_m(field, "sAMAccountName") == 0) {
865 disp_fields[0] = SMB_STRDUP((char *) values[0]);
867 if (strcasecmp_m(field, "description") == 0)
868 disp_fields[1] = SMB_STRDUP((char *) values[0]);
872 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
874 return net_user_usage(c, argc, argv);
877 static int ads_user_add(struct net_context *c, int argc, const char **argv)
879 TALLOC_CTX *tmp_ctx = talloc_stackframe();
880 ADS_STRUCT *ads = NULL;
883 LDAPMessage *res=NULL;
887 if (argc < 1 || c->display_usage) {
888 TALLOC_FREE(tmp_ctx);
889 return net_ads_user_usage(c, argc, argv);
892 status = ads_startup(c, false, &ads);
893 if (!ADS_ERR_OK(status)) {
897 status = ads_find_user_acct(ads, &res, argv[0]);
898 if (!ADS_ERR_OK(status)) {
899 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
903 if (ads_count_replies(ads, res)) {
904 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
909 if (c->opt_container) {
910 ou_str = SMB_STRDUP(c->opt_container);
912 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
915 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
916 if (!ADS_ERR_OK(status)) {
917 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
922 /* if no password is to be set, we're done */
924 d_printf(_("User %s added\n"), argv[0]);
929 /* try setting the password */
930 upn = talloc_asprintf(tmp_ctx,
938 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
939 ads->auth.time_offset);
940 if (ADS_ERR_OK(status)) {
941 d_printf(_("User %s added\n"), argv[0]);
947 /* password didn't set, delete account */
948 d_fprintf(stderr, _("Could not add user %s. "
949 "Error setting password %s\n"),
950 argv[0], ads_errstr(status));
952 ads_msgfree(ads, res);
955 status=ads_find_user_acct(ads, &res, argv[0]);
956 if (ADS_ERR_OK(status)) {
957 userdn = ads_get_dn(ads, tmp_ctx, res);
958 ads_del_dn(ads, userdn);
963 ads_msgfree(ads, res);
966 TALLOC_FREE(tmp_ctx);
970 static int ads_user_info(struct net_context *c, int argc, const char **argv)
972 ADS_STRUCT *ads = NULL;
974 LDAPMessage *res = NULL;
978 const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
979 char *searchstring=NULL;
983 struct dom_sid primary_group_sid;
985 enum wbcSidType type;
987 if (argc < 1 || c->display_usage) {
988 return net_ads_user_usage(c, argc, argv);
991 frame = talloc_new(talloc_tos());
996 escaped_user = escape_ldap_string(frame, argv[0]);
999 _("ads_user_info: failed to escape user %s\n"),
1004 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1009 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
1013 rc = ads_search(ads, &res, searchstring, attrs);
1014 SAFE_FREE(searchstring);
1016 if (!ADS_ERR_OK(rc)) {
1017 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(rc));
1022 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
1023 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
1028 rc = ads_domain_sid(ads, &primary_group_sid);
1029 if (!ADS_ERR_OK(rc)) {
1030 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(rc));
1035 sid_append_rid(&primary_group_sid, group_rid);
1037 wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
1038 NULL, /* don't look up domain */
1041 if (!WBC_ERROR_IS_OK(wbc_status)) {
1042 d_fprintf(stderr, "wbcLookupSid: %s\n",
1043 wbcErrorString(wbc_status));
1048 d_printf("%s\n", primary_group);
1050 wbcFreeMemory(primary_group);
1052 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
1053 (LDAPMessage *)res, "memberOf");
1058 for (i=0;grouplist[i];i++) {
1059 groupname = ldap_explode_dn(grouplist[i], 1);
1060 d_printf("%s\n", groupname[0]);
1061 ldap_value_free(groupname);
1063 ldap_value_free(grouplist);
1067 if (res) ads_msgfree(ads, res);
1068 if (ads) ads_destroy(&ads);
1073 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
1077 LDAPMessage *res = NULL;
1081 return net_ads_user_usage(c, argc, argv);
1084 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1088 rc = ads_find_user_acct(ads, &res, argv[0]);
1089 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
1090 d_printf(_("User %s does not exist.\n"), argv[0]);
1091 ads_msgfree(ads, res);
1095 userdn = ads_get_dn(ads, talloc_tos(), res);
1096 ads_msgfree(ads, res);
1097 rc = ads_del_dn(ads, userdn);
1098 TALLOC_FREE(userdn);
1099 if (ADS_ERR_OK(rc)) {
1100 d_printf(_("User %s deleted\n"), argv[0]);
1104 d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
1110 int net_ads_user(struct net_context *c, int argc, const char **argv)
1112 struct functable func[] = {
1117 N_("Add an AD user"),
1118 N_("net ads user add\n"
1125 N_("Display information about an AD user"),
1126 N_("net ads user info\n"
1127 " Display information about an AD user")
1133 N_("Delete an AD user"),
1134 N_("net ads user delete\n"
1135 " Delete an AD user")
1137 {NULL, NULL, 0, NULL, NULL}
1141 const char *shortattrs[] = {"sAMAccountName", NULL};
1142 const char *longattrs[] = {"sAMAccountName", "description", NULL};
1143 char *disp_fields[2] = {NULL, NULL};
1146 if (c->display_usage) {
1151 _("List AD users"));
1152 net_display_usage_from_functable(func);
1156 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1160 if (c->opt_long_list_entries)
1161 d_printf(_("\nUser name Comment"
1162 "\n-----------------------------\n"));
1164 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
1166 "(objectCategory=user)",
1167 c->opt_long_list_entries ? longattrs :
1168 shortattrs, usergrp_display,
1171 return ADS_ERR_OK(rc) ? 0 : -1;
1174 return net_run_function(c, argc, argv, "net ads user", func);
1177 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
1179 return net_group_usage(c, argc, argv);
1182 static int ads_group_add(struct net_context *c, int argc, const char **argv)
1186 LDAPMessage *res=NULL;
1188 char *ou_str = NULL;
1190 if (argc < 1 || c->display_usage) {
1191 return net_ads_group_usage(c, argc, argv);
1194 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1198 status = ads_find_user_acct(ads, &res, argv[0]);
1200 if (!ADS_ERR_OK(status)) {
1201 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
1205 if (ads_count_replies(ads, res)) {
1206 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
1210 if (c->opt_container) {
1211 ou_str = SMB_STRDUP(c->opt_container);
1213 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
1216 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
1218 if (ADS_ERR_OK(status)) {
1219 d_printf(_("Group %s added\n"), argv[0]);
1222 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
1223 ads_errstr(status));
1228 ads_msgfree(ads, res);
1234 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
1238 LDAPMessage *res = NULL;
1241 if (argc < 1 || c->display_usage) {
1242 return net_ads_group_usage(c, argc, argv);
1245 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1249 rc = ads_find_user_acct(ads, &res, argv[0]);
1250 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
1251 d_printf(_("Group %s does not exist.\n"), argv[0]);
1252 ads_msgfree(ads, res);
1256 groupdn = ads_get_dn(ads, talloc_tos(), res);
1257 ads_msgfree(ads, res);
1258 rc = ads_del_dn(ads, groupdn);
1259 TALLOC_FREE(groupdn);
1260 if (ADS_ERR_OK(rc)) {
1261 d_printf(_("Group %s deleted\n"), argv[0]);
1265 d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
1271 int net_ads_group(struct net_context *c, int argc, const char **argv)
1273 struct functable func[] = {
1278 N_("Add an AD group"),
1279 N_("net ads group add\n"
1286 N_("Delete an AD group"),
1287 N_("net ads group delete\n"
1288 " Delete an AD group")
1290 {NULL, NULL, 0, NULL, NULL}
1294 const char *shortattrs[] = {"sAMAccountName", NULL};
1295 const char *longattrs[] = {"sAMAccountName", "description", NULL};
1296 char *disp_fields[2] = {NULL, NULL};
1299 if (c->display_usage) {
1304 _("List AD groups"));
1305 net_display_usage_from_functable(func);
1309 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1313 if (c->opt_long_list_entries)
1314 d_printf(_("\nGroup name Comment"
1315 "\n-----------------------------\n"));
1316 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
1318 "(objectCategory=group)",
1319 c->opt_long_list_entries ? longattrs :
1320 shortattrs, usergrp_display,
1324 return ADS_ERR_OK(rc) ? 0 : -1;
1326 return net_run_function(c, argc, argv, "net ads group", func);
1329 static int net_ads_status(struct net_context *c, int argc, const char **argv)
1335 if (c->display_usage) {
1340 _("Display machine account details"));
1344 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1348 rc = ads_find_machine_acct(ads, &res, lp_netbios_name());
1349 if (!ADS_ERR_OK(rc)) {
1350 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
1355 if (ads_count_replies(ads, res) == 0) {
1356 d_fprintf(stderr, _("No machine account for '%s' found\n"), lp_netbios_name());
1366 /*******************************************************************
1367 Leave an AD domain. Windows XP disables the machine account.
1368 We'll try the same. The old code would do an LDAP delete.
1369 That only worked using the machine creds because added the machine
1370 with full control to the computer object's ACL.
1371 *******************************************************************/
1373 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
1376 struct libnet_UnjoinCtx *r = NULL;
1379 if (c->display_usage) {
1381 "net ads leave [--keep-account]\n"
1384 _("Leave an AD domain"));
1389 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
1393 if (!(ctx = talloc_init("net_ads_leave"))) {
1394 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1398 if (!c->opt_kerberos) {
1399 use_in_memory_ccache();
1403 d_fprintf(stderr, _("Could not initialise message context. "
1404 "Try running as root\n"));
1408 werr = libnet_init_UnjoinCtx(ctx, &r);
1409 if (!W_ERROR_IS_OK(werr)) {
1410 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
1415 r->in.use_kerberos = c->opt_kerberos;
1416 r->in.dc_name = c->opt_host;
1417 r->in.domain_name = lp_realm();
1418 r->in.admin_account = c->opt_user_name;
1419 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1420 r->in.modify_config = lp_config_backend_is_registry();
1422 /* Try to delete it, but if that fails, disable it. The
1423 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
1424 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1425 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
1426 if (c->opt_keep_account) {
1427 r->in.delete_machine_account = false;
1429 r->in.delete_machine_account = true;
1432 r->in.msg_ctx = c->msg_ctx;
1434 werr = libnet_Unjoin(ctx, r);
1435 if (!W_ERROR_IS_OK(werr)) {
1436 d_printf(_("Failed to leave domain: %s\n"),
1437 r->out.error_string ? r->out.error_string :
1438 get_friendly_werror_msg(werr));
1442 if (r->out.deleted_machine_account) {
1443 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1444 r->in.machine_name, r->out.dns_domain_name);
1448 /* We couldn't delete it - see if the disable succeeded. */
1449 if (r->out.disabled_machine_account) {
1450 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1451 r->in.machine_name, r->out.dns_domain_name);
1456 /* Based on what we requested, we shouldn't get here, but if
1457 we did, it means the secrets were removed, and therefore
1458 we have left the domain */
1459 d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1460 r->in.machine_name, r->out.dns_domain_name);
1466 if (W_ERROR_IS_OK(werr)) {
1473 static NTSTATUS net_ads_join_ok(struct net_context *c)
1475 ADS_STRUCT *ads = NULL;
1478 struct sockaddr_storage dcip;
1480 if (!secrets_init()) {
1481 DEBUG(1,("Failed to initialise secrets database\n"));
1482 return NT_STATUS_ACCESS_DENIED;
1485 net_use_krb_machine_account(c);
1487 get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1489 status = ads_startup(c, true, &ads);
1490 if (!ADS_ERR_OK(status)) {
1491 return ads_ntstatus(status);
1495 return NT_STATUS_OK;
1499 check that an existing join is OK
1501 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1504 use_in_memory_ccache();
1506 if (c->display_usage) {
1508 "net ads testjoin\n"
1511 _("Test if the existing join is ok"));
1515 /* Display success or failure */
1516 status = net_ads_join_ok(c);
1517 if (!NT_STATUS_IS_OK(status)) {
1518 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1519 get_friendly_nt_error_msg(status));
1523 printf(_("Join is OK\n"));
1527 /*******************************************************************
1528 Simple config checks before beginning the join
1529 ********************************************************************/
1531 static WERROR check_ads_config( void )
1533 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1534 d_printf(_("Host is not configured as a member server.\n"));
1535 return WERR_INVALID_DOMAIN_ROLE;
1538 if (strlen(lp_netbios_name()) > 15) {
1539 d_printf(_("Our netbios name can be at most 15 chars long, "
1540 "\"%s\" is %u chars long\n"), lp_netbios_name(),
1541 (unsigned int)strlen(lp_netbios_name()));
1542 return WERR_INVALID_COMPUTERNAME;
1545 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1546 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1547 "join to succeed.\n"), get_dyn_CONFIGFILE());
1548 return WERR_INVALID_PARAMETER;
1554 /*******************************************************************
1555 ********************************************************************/
1557 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1559 d_printf(_("net ads join [--no-dns-updates] [options]\n"
1560 "Valid options:\n"));
1561 d_printf(_(" dnshostname=FQDN Set the dnsHostName attribute during the join.\n"
1562 " The default is in the form netbiosname.dnsdomain\n"));
1563 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1564 " The default UPN is in the form host/netbiosname@REALM.\n"));
1565 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1566 " The OU string read from top to bottom without RDNs\n"
1567 " and delimited by a '/'.\n"
1568 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1569 " NB: A backslash '\\' is used as escape at multiple\n"
1570 " levels and may need to be doubled or even\n"
1571 " quadrupled. It is not used as a separator.\n"));
1572 d_printf(_(" machinepass=PASS Set the machine password to a specific value during\n"
1573 " the join. The default password is random.\n"));
1574 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1575 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during join.\n"
1576 " NB: osName and osVer must be specified together for\n"
1577 " either to take effect. The operatingSystemService\n"
1578 " attribute is then also set along with the two\n"
1579 " other attributes.\n"));
1580 d_printf(_(" osServicePack=string Set the operatingSystemServicePack attribute\n"
1581 " during the join.\n"
1582 " NB: If not specified then by default the samba\n"
1583 " version string is used instead.\n"));
1588 int net_ads_join(struct net_context *c, int argc, const char **argv)
1590 TALLOC_CTX *ctx = NULL;
1591 struct libnet_JoinCtx *r = NULL;
1592 const char *domain = lp_realm();
1593 WERROR werr = WERR_NERR_SETUPNOTJOINED;
1594 bool createupn = false;
1595 const char *dnshostname = NULL;
1596 const char *machineupn = NULL;
1597 const char *machine_password = NULL;
1598 const char *create_in_ou = NULL;
1600 const char *os_name = NULL;
1601 const char *os_version = NULL;
1602 const char *os_servicepack = NULL;
1603 bool modify_config = lp_config_backend_is_registry();
1604 enum libnetjoin_JoinDomNameType domain_name_type = JoinDomNameTypeDNS;
1606 if (c->display_usage)
1607 return net_ads_join_usage(c, argc, argv);
1609 if (!modify_config) {
1611 werr = check_ads_config();
1612 if (!W_ERROR_IS_OK(werr)) {
1613 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1618 if (!(ctx = talloc_init("net_ads_join"))) {
1619 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1620 werr = WERR_NOT_ENOUGH_MEMORY;
1624 if (!c->opt_kerberos) {
1625 use_in_memory_ccache();
1628 werr = libnet_init_JoinCtx(ctx, &r);
1629 if (!W_ERROR_IS_OK(werr)) {
1633 /* process additional command line args */
1635 for ( i=0; i<argc; i++ ) {
1636 if ( !strncasecmp_m(argv[i], "dnshostname", strlen("dnshostname")) ) {
1637 dnshostname = get_string_param(argv[i]);
1639 else if ( !strncasecmp_m(argv[i], "createupn", strlen("createupn")) ) {
1641 machineupn = get_string_param(argv[i]);
1643 else if ( !strncasecmp_m(argv[i], "createcomputer", strlen("createcomputer")) ) {
1644 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1645 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1646 werr = WERR_INVALID_PARAMETER;
1650 else if ( !strncasecmp_m(argv[i], "osName", strlen("osName")) ) {
1651 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1652 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1653 werr = WERR_INVALID_PARAMETER;
1657 else if ( !strncasecmp_m(argv[i], "osVer", strlen("osVer")) ) {
1658 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1659 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1660 werr = WERR_INVALID_PARAMETER;
1664 else if ( !strncasecmp_m(argv[i], "osServicePack", strlen("osServicePack")) ) {
1665 if ( (os_servicepack = get_string_param(argv[i])) == NULL ) {
1666 d_fprintf(stderr, _("Please supply a valid servicepack identifier.\n"));
1667 werr = WERR_INVALID_PARAMETER;
1671 else if ( !strncasecmp_m(argv[i], "machinepass", strlen("machinepass")) ) {
1672 if ( (machine_password = get_string_param(argv[i])) == NULL ) {
1673 d_fprintf(stderr, _("Please supply a valid password to set as trust account password.\n"));
1674 werr = WERR_INVALID_PARAMETER;
1680 if (strchr(domain, '.') == NULL) {
1681 domain_name_type = JoinDomNameTypeUnknown;
1683 domain_name_type = JoinDomNameTypeDNS;
1689 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1690 werr = WERR_INVALID_PARAMETER;
1695 d_fprintf(stderr, _("Could not initialise message context. "
1696 "Try running as root\n"));
1697 werr = WERR_ACCESS_DENIED;
1701 /* Do the domain join here */
1703 r->in.domain_name = domain;
1704 r->in.domain_name_type = domain_name_type;
1705 r->in.create_upn = createupn;
1706 r->in.upn = machineupn;
1707 r->in.dnshostname = dnshostname;
1708 r->in.account_ou = create_in_ou;
1709 r->in.os_name = os_name;
1710 r->in.os_version = os_version;
1711 r->in.os_servicepack = os_servicepack;
1712 r->in.dc_name = c->opt_host;
1713 r->in.admin_account = c->opt_user_name;
1714 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1715 r->in.machine_password = machine_password;
1717 r->in.use_kerberos = c->opt_kerberos;
1718 r->in.modify_config = modify_config;
1719 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1720 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1721 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1722 r->in.msg_ctx = c->msg_ctx;
1724 werr = libnet_Join(ctx, r);
1725 if (W_ERROR_EQUAL(werr, WERR_NERR_DCNOTFOUND) &&
1726 strequal(domain, lp_realm())) {
1727 r->in.domain_name = lp_workgroup();
1728 r->in.domain_name_type = JoinDomNameTypeNBT;
1729 werr = libnet_Join(ctx, r);
1731 if (!W_ERROR_IS_OK(werr)) {
1735 /* Check the short name of the domain */
1737 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1738 d_printf(_("The workgroup in %s does not match the short\n"
1739 "domain name obtained from the server.\n"
1740 "Using the name [%s] from the server.\n"
1741 "You should set \"workgroup = %s\" in %s.\n"),
1742 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1743 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1746 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1748 if (r->out.dns_domain_name) {
1749 d_printf(_("Joined '%s' to dns domain '%s'\n"), r->in.machine_name,
1750 r->out.dns_domain_name);
1752 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1753 r->out.netbios_domain_name);
1756 /* print out informative error string in case there is one */
1757 if (r->out.error_string != NULL) {
1758 d_printf("%s\n", r->out.error_string);
1762 * We try doing the dns update (if it was compiled in
1763 * and if it was not disabled on the command line).
1764 * If the dns update fails, we still consider the join
1765 * operation as succeeded if we came this far.
1767 if (!c->opt_no_dns_updates) {
1768 net_ads_join_dns_updates(c, ctx, r);
1777 /* issue an overall failure message at the end. */
1778 d_printf(_("Failed to join domain: %s\n"),
1779 r && r->out.error_string ? r->out.error_string :
1780 get_friendly_werror_msg(werr));
1786 /*******************************************************************
1787 ********************************************************************/
1789 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1791 #if defined(HAVE_KRB5)
1796 const char *hostname = NULL;
1797 const char **addrs_list = NULL;
1798 struct sockaddr_storage *addrs = NULL;
1803 talloc_enable_leak_report();
1806 if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
1807 d_fprintf(stderr, _("Refusing DNS updates with automatic "
1808 "detection of addresses in a clustered "
1810 c->display_usage = true;
1813 if (c->display_usage) {
1815 "net ads dns register [hostname [IP [IP...]]]\n"
1818 _("Register hostname with DNS\n"));
1822 if (!(ctx = talloc_init("net_ads_dns"))) {
1823 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1832 num_addrs = argc - 1;
1833 addrs_list = &argv[1];
1834 } else if (lp_clustering()) {
1835 addrs_list = lp_cluster_addresses();
1836 num_addrs = str_list_length(addrs_list);
1839 if (num_addrs > 0) {
1840 addrs = talloc_zero_array(ctx, struct sockaddr_storage, num_addrs);
1841 if (addrs == NULL) {
1842 d_fprintf(stderr, _("Error allocating memory!\n"));
1848 for (count = 0; count < num_addrs; count++) {
1849 if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
1850 d_fprintf(stderr, "%s '%s'.\n",
1851 _("Cannot interpret address"),
1858 status = ads_startup(c, true, &ads);
1859 if ( !ADS_ERR_OK(status) ) {
1860 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1865 ntstatus = net_update_dns_ext(c, ctx, ads, hostname, addrs, num_addrs, false);
1866 if (!NT_STATUS_IS_OK(ntstatus)) {
1867 d_fprintf( stderr, _("DNS update failed!\n") );
1868 ads_destroy( &ads );
1873 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1881 _("DNS update support not enabled at compile time!\n"));
1886 static int net_ads_dns_unregister(struct net_context *c,
1890 #if defined(HAVE_KRB5)
1895 const char *hostname = NULL;
1898 talloc_enable_leak_report();
1902 c->display_usage = true;
1905 if (c->display_usage) {
1907 "net ads dns unregister [hostname]\n"
1910 _("Remove all IP Address entires for a given\n"
1911 " hostname from the Active Directory server.\n"));
1915 if (!(ctx = talloc_init("net_ads_dns"))) {
1916 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1920 /* Get the hostname for un-registering */
1923 status = ads_startup(c, true, &ads);
1924 if ( !ADS_ERR_OK(status) ) {
1925 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1930 ntstatus = net_update_dns_ext(c, ctx, ads, hostname, NULL, 0, true);
1931 if (!NT_STATUS_IS_OK(ntstatus)) {
1932 d_fprintf( stderr, _("DNS update failed!\n") );
1933 ads_destroy( &ads );
1938 d_fprintf( stderr, _("Successfully un-registered hostname from DNS\n"));
1946 _("DNS update support not enabled at compile time!\n"));
1952 static int net_ads_dns_async(struct net_context *c, int argc, const char **argv)
1954 size_t num_names = 0;
1955 char **hostnames = NULL;
1957 struct samba_sockaddr *addrs = NULL;
1960 if (argc != 1 || c->display_usage) {
1965 _("net ads dns async <name>\n"),
1966 _(" Async look up hostname from the DNS server\n"
1967 " hostname\tName to look up\n"));
1971 status = ads_dns_lookup_a(talloc_tos(),
1976 if (!NT_STATUS_IS_OK(status)) {
1977 d_printf("Looking up A record for %s got error %s\n",
1982 d_printf("Async A record lookup - got %u names for %s\n",
1983 (unsigned int)num_names,
1985 for (i = 0; i < num_names; i++) {
1986 char addr_buf[INET6_ADDRSTRLEN];
1987 print_sockaddr(addr_buf,
1990 d_printf("hostname[%u] = %s, IPv4addr = %s\n",
1996 #if defined(HAVE_IPV6)
1997 status = ads_dns_lookup_aaaa(talloc_tos(),
2002 if (!NT_STATUS_IS_OK(status)) {
2003 d_printf("Looking up AAAA record for %s got error %s\n",
2008 d_printf("Async AAAA record lookup - got %u names for %s\n",
2009 (unsigned int)num_names,
2011 for (i = 0; i < num_names; i++) {
2012 char addr_buf[INET6_ADDRSTRLEN];
2013 print_sockaddr(addr_buf,
2016 d_printf("hostname[%u] = %s, IPv6addr = %s\n",
2026 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
2028 struct functable func[] = {
2031 net_ads_dns_register,
2033 N_("Add host dns entry to AD"),
2034 N_("net ads dns register\n"
2035 " Add host dns entry to AD")
2039 net_ads_dns_unregister,
2041 N_("Remove host dns entry from AD"),
2042 N_("net ads dns unregister\n"
2043 " Remove host dns entry from AD")
2050 N_("net ads dns async\n"
2051 " Look up host using async DNS")
2053 {NULL, NULL, 0, NULL, NULL}
2056 return net_run_function(c, argc, argv, "net ads dns", func);
2059 /*******************************************************************
2060 ********************************************************************/
2062 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
2065 "\nnet ads printer search <printer>"
2066 "\n\tsearch for a printer in the directory\n"
2067 "\nnet ads printer info <printer> <server>"
2068 "\n\tlookup info in directory for printer on server"
2069 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
2070 "\nnet ads printer publish <printername>"
2071 "\n\tpublish printer in directory"
2072 "\n\t(note: printer name is required)\n"
2073 "\nnet ads printer remove <printername>"
2074 "\n\tremove printer from directory"
2075 "\n\t(note: printer name is required)\n"));
2079 /*******************************************************************
2080 ********************************************************************/
2082 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
2086 LDAPMessage *res = NULL;
2088 if (c->display_usage) {
2090 "net ads printer search\n"
2093 _("List printers in the AD"));
2097 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2101 rc = ads_find_printers(ads, &res);
2103 if (!ADS_ERR_OK(rc)) {
2104 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
2105 ads_msgfree(ads, res);
2110 if (ads_count_replies(ads, res) == 0) {
2111 d_fprintf(stderr, _("No results found\n"));
2112 ads_msgfree(ads, res);
2118 ads_msgfree(ads, res);
2123 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
2127 const char *servername, *printername;
2128 LDAPMessage *res = NULL;
2130 if (c->display_usage) {
2133 _("net ads printer info [printername [servername]]\n"
2134 " Display printer info from AD\n"
2135 " printername\tPrinter name or wildcard\n"
2136 " servername\tName of the print server\n"));
2140 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2145 printername = argv[0];
2151 servername = argv[1];
2153 servername = lp_netbios_name();
2156 rc = ads_find_printer_on_server(ads, &res, printername, servername);
2158 if (!ADS_ERR_OK(rc)) {
2159 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
2160 servername, ads_errstr(rc));
2161 ads_msgfree(ads, res);
2166 if (ads_count_replies(ads, res) == 0) {
2167 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
2168 ads_msgfree(ads, res);
2174 ads_msgfree(ads, res);
2180 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
2184 const char *servername, *printername;
2185 struct cli_state *cli = NULL;
2186 struct rpc_pipe_client *pipe_hnd = NULL;
2187 struct sockaddr_storage server_ss;
2189 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
2190 ADS_MODLIST mods = ads_init_mods(mem_ctx);
2191 char *prt_dn, *srv_dn, **srv_cn;
2192 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
2193 LDAPMessage *res = NULL;
2196 if (argc < 1 || c->display_usage) {
2199 _("net ads printer publish <printername> [servername]\n"
2200 " Publish printer in AD\n"
2201 " printername\tName of the printer\n"
2202 " servername\tName of the print server\n"));
2203 talloc_destroy(mem_ctx);
2207 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2208 talloc_destroy(mem_ctx);
2212 printername = argv[0];
2215 servername = argv[1];
2217 servername = lp_netbios_name();
2220 /* Get printer data from SPOOLSS */
2222 ok = resolve_name(servername, &server_ss, 0x20, false);
2224 d_fprintf(stderr, _("Could not find server %s\n"),
2227 talloc_destroy(mem_ctx);
2231 cli_credentials_set_kerberos_state(c->creds,
2232 CRED_USE_KERBEROS_REQUIRED,
2235 nt_status = cli_full_connection_creds(&cli, lp_netbios_name(), servername,
2239 CLI_FULL_CONNECTION_IPC);
2241 if (NT_STATUS_IS_ERR(nt_status)) {
2242 d_fprintf(stderr, _("Unable to open a connection to %s to "
2243 "obtain data for %s\n"),
2244 servername, printername);
2246 talloc_destroy(mem_ctx);
2250 /* Publish on AD server */
2252 ads_find_machine_acct(ads, &res, servername);
2254 if (ads_count_replies(ads, res) == 0) {
2255 d_fprintf(stderr, _("Could not find machine account for server "
2259 talloc_destroy(mem_ctx);
2263 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
2264 srv_cn = ldap_explode_dn(srv_dn, 1);
2266 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
2267 printername_escaped = escape_rdn_val_string_alloc(printername);
2268 if (!srv_cn_escaped || !printername_escaped) {
2269 SAFE_FREE(srv_cn_escaped);
2270 SAFE_FREE(printername_escaped);
2271 d_fprintf(stderr, _("Internal error, out of memory!"));
2273 talloc_destroy(mem_ctx);
2277 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
2278 SAFE_FREE(srv_cn_escaped);
2279 SAFE_FREE(printername_escaped);
2280 d_fprintf(stderr, _("Internal error, out of memory!"));
2282 talloc_destroy(mem_ctx);
2286 SAFE_FREE(srv_cn_escaped);
2287 SAFE_FREE(printername_escaped);
2289 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss, &pipe_hnd);
2290 if (!NT_STATUS_IS_OK(nt_status)) {
2291 d_fprintf(stderr, _("Unable to open a connection to the spoolss pipe on %s\n"),
2295 talloc_destroy(mem_ctx);
2299 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
2303 talloc_destroy(mem_ctx);
2307 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
2308 if (!ADS_ERR_OK(rc)) {
2309 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
2312 talloc_destroy(mem_ctx);
2316 d_printf("published printer\n");
2319 talloc_destroy(mem_ctx);
2324 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
2328 const char *servername;
2330 LDAPMessage *res = NULL;
2332 if (argc < 1 || c->display_usage) {
2335 _("net ads printer remove <printername> [servername]\n"
2336 " Remove a printer from the AD\n"
2337 " printername\tName of the printer\n"
2338 " servername\tName of the print server\n"));
2342 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2347 servername = argv[1];
2349 servername = lp_netbios_name();
2352 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
2354 if (!ADS_ERR_OK(rc)) {
2355 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
2356 ads_msgfree(ads, res);
2361 if (ads_count_replies(ads, res) == 0) {
2362 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
2363 ads_msgfree(ads, res);
2368 prt_dn = ads_get_dn(ads, talloc_tos(), res);
2369 ads_msgfree(ads, res);
2370 rc = ads_del_dn(ads, prt_dn);
2371 TALLOC_FREE(prt_dn);
2373 if (!ADS_ERR_OK(rc)) {
2374 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
2383 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
2385 struct functable func[] = {
2388 net_ads_printer_search,
2390 N_("Search for a printer"),
2391 N_("net ads printer search\n"
2392 " Search for a printer")
2396 net_ads_printer_info,
2398 N_("Display printer information"),
2399 N_("net ads printer info\n"
2400 " Display printer information")
2404 net_ads_printer_publish,
2406 N_("Publish a printer"),
2407 N_("net ads printer publish\n"
2408 " Publish a printer")
2412 net_ads_printer_remove,
2414 N_("Delete a printer"),
2415 N_("net ads printer remove\n"
2416 " Delete a printer")
2418 {NULL, NULL, 0, NULL, NULL}
2421 return net_run_function(c, argc, argv, "net ads printer", func);
2425 static int net_ads_password(struct net_context *c, int argc, const char **argv)
2428 const char *auth_principal = cli_credentials_get_username(c->creds);
2429 const char *auth_password = cli_credentials_get_password(c->creds);
2430 const char *realm = NULL;
2431 const char *new_password = NULL;
2434 char pwd[256] = {0};
2437 if (c->display_usage) {
2440 _("net ads password <username>\n"
2441 " Change password for user\n"
2442 " username\tName of user to change password for\n"));
2446 if (auth_principal == NULL || auth_password == NULL) {
2447 d_fprintf(stderr, _("You must supply an administrator "
2448 "username/password\n"));
2453 d_fprintf(stderr, _("ERROR: You must say which username to "
2454 "change password for\n"));
2459 if (!strchr_m(user, '@')) {
2460 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
2466 use_in_memory_ccache();
2467 chr = strchr_m(auth_principal, '@');
2474 /* use the realm so we can eventually change passwords for users
2475 in realms other than default */
2476 ads = ads_init(realm, c->opt_workgroup, c->opt_host, ADS_SASL_PLAIN);
2481 /* we don't actually need a full connect, but it's the easy way to
2482 fill in the KDC's addresss */
2485 if (!ads->config.realm) {
2486 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
2492 new_password = (const char *)argv[1];
2496 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
2499 rc = samba_getpass(prompt, pwd, sizeof(pwd), false, true);
2507 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2508 auth_password, user, new_password, ads->auth.time_offset);
2509 memset(pwd, '\0', sizeof(pwd));
2510 if (!ADS_ERR_OK(ret)) {
2511 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2516 d_printf(_("Password change for %s completed.\n"), user);
2522 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2525 char *host_principal;
2529 if (c->display_usage) {
2531 "net ads changetrustpw\n"
2534 _("Change the machine account's trust password"));
2538 if (!secrets_init()) {
2539 DEBUG(1,("Failed to initialise secrets database\n"));
2543 net_use_krb_machine_account(c);
2545 use_in_memory_ccache();
2547 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2551 fstrcpy(my_name, lp_netbios_name());
2552 if (!strlower_m(my_name)) {
2557 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2561 d_printf(_("Changing password for principal: %s\n"), host_principal);
2563 ret = ads_change_trust_account_password(ads, host_principal);
2565 if (!ADS_ERR_OK(ret)) {
2566 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2568 SAFE_FREE(host_principal);
2572 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2574 if (USE_SYSTEM_KEYTAB) {
2575 d_printf(_("Attempting to update system keytab with new password.\n"));
2576 if (ads_keytab_create_default(ads)) {
2577 d_printf(_("Failed to update system keytab.\n"));
2582 SAFE_FREE(host_principal);
2588 help for net ads search
2590 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2593 "\nnet ads search <expression> <attributes...>\n"
2594 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2595 "The expression is a standard LDAP search expression, and the\n"
2596 "attributes are a list of LDAP fields to show in the results.\n\n"
2597 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2599 net_common_flags_usage(c, argc, argv);
2605 general ADS search function. Useful in diagnosing problems in ADS
2607 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2611 const char *ldap_exp;
2613 LDAPMessage *res = NULL;
2615 if (argc < 1 || c->display_usage) {
2616 return net_ads_search_usage(c, argc, argv);
2619 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2626 rc = ads_do_search_retry(ads, ads->config.bind_path,
2628 ldap_exp, attrs, &res);
2629 if (!ADS_ERR_OK(rc)) {
2630 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2635 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2637 /* dump the results */
2640 ads_msgfree(ads, res);
2648 help for net ads search
2650 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2653 "\nnet ads dn <dn> <attributes...>\n"
2654 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2655 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2656 "to show in the results\n\n"
2657 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2658 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2660 net_common_flags_usage(c, argc, argv);
2666 general ADS search function. Useful in diagnosing problems in ADS
2668 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2674 LDAPMessage *res = NULL;
2676 if (argc < 1 || c->display_usage) {
2677 return net_ads_dn_usage(c, argc, argv);
2680 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2687 rc = ads_do_search_all(ads, dn,
2689 "(objectclass=*)", attrs, &res);
2690 if (!ADS_ERR_OK(rc)) {
2691 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2696 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2698 /* dump the results */
2701 ads_msgfree(ads, res);
2708 help for net ads sid search
2710 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2713 "\nnet ads sid <sid> <attributes...>\n"
2714 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2715 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2716 "to show in the results\n\n"
2717 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2719 net_common_flags_usage(c, argc, argv);
2725 general ADS search function. Useful in diagnosing problems in ADS
2727 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2731 const char *sid_string;
2733 LDAPMessage *res = NULL;
2736 if (argc < 1 || c->display_usage) {
2737 return net_ads_sid_usage(c, argc, argv);
2740 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2744 sid_string = argv[0];
2747 if (!string_to_sid(&sid, sid_string)) {
2748 d_fprintf(stderr, _("could not convert sid\n"));
2753 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2754 if (!ADS_ERR_OK(rc)) {
2755 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2760 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2762 /* dump the results */
2765 ads_msgfree(ads, res);
2771 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2776 if (c->display_usage) {
2778 "net ads keytab flush\n"
2781 _("Delete the whole keytab"));
2785 if (!c->opt_user_specified && c->opt_password == NULL) {
2786 net_use_krb_machine_account(c);
2789 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2792 ret = ads_keytab_flush(ads);
2797 static int net_ads_keytab_add(struct net_context *c,
2806 if (c->display_usage) {
2809 _("net ads keytab add <principal> [principal ...]\n"
2810 " Add principals to local keytab\n"
2811 " principal\tKerberos principal to add to "
2816 d_printf(_("Processing principals to add...\n"));
2818 if (!c->opt_user_specified && c->opt_password == NULL) {
2819 net_use_krb_machine_account(c);
2822 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2825 for (i = 0; i < argc; i++) {
2826 ret |= ads_keytab_add_entry(ads, argv[i], update_ads);
2832 static int net_ads_keytab_add_default(struct net_context *c,
2836 return net_ads_keytab_add(c, argc, argv, false);
2839 static int net_ads_keytab_add_update_ads(struct net_context *c,
2843 return net_ads_keytab_add(c, argc, argv, true);
2846 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2851 if (c->display_usage) {
2853 "net ads keytab create\n"
2856 _("Create new default keytab"));
2860 if (!c->opt_user_specified && c->opt_password == NULL) {
2861 net_use_krb_machine_account(c);
2864 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2867 ret = ads_keytab_create_default(ads);
2872 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2874 const char *keytab = NULL;
2876 if (c->display_usage) {
2879 _("net ads keytab list [keytab]\n"
2880 " List a local keytab\n"
2881 " keytab\tKeytab to list\n"));
2889 return ads_keytab_list(keytab);
2893 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2895 struct functable func[] = {
2898 net_ads_keytab_add_default,
2900 N_("Add a service principal"),
2901 N_("net ads keytab add\n"
2902 " Add a service principal, updates keytab file only.")
2906 net_ads_keytab_add_update_ads,
2908 N_("Add a service principal"),
2909 N_("net ads keytab add_update_ads\n"
2910 " Add a service principal, depending on the param passed may update ADS computer object in addition to the keytab file.")
2914 net_ads_keytab_create,
2916 N_("Create a fresh keytab"),
2917 N_("net ads keytab create\n"
2918 " Create a fresh keytab or update existing one.")
2922 net_ads_keytab_flush,
2924 N_("Remove all keytab entries"),
2925 N_("net ads keytab flush\n"
2926 " Remove all keytab entries")
2930 net_ads_keytab_list,
2932 N_("List a keytab"),
2933 N_("net ads keytab list\n"
2936 {NULL, NULL, 0, NULL, NULL}
2939 if (!USE_KERBEROS_KEYTAB) {
2940 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2941 "keytab method to use keytab functions.\n"));
2944 return net_run_function(c, argc, argv, "net ads keytab", func);
2947 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2951 if (c->display_usage) {
2953 "net ads kerberos renew\n"
2956 _("Renew TGT from existing credential cache"));
2960 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2962 d_printf(_("failed to renew kerberos ticket: %s\n"),
2963 error_message(ret));
2968 static int net_ads_kerberos_pac_common(struct net_context *c, int argc, const char **argv,
2969 struct PAC_DATA_CTR **pac_data_ctr)
2973 const char *impersonate_princ_s = NULL;
2974 const char *local_service = NULL;
2977 for (i=0; i<argc; i++) {
2978 if (strnequal(argv[i], "impersonate", strlen("impersonate"))) {
2979 impersonate_princ_s = get_string_param(argv[i]);
2980 if (impersonate_princ_s == NULL) {
2984 if (strnequal(argv[i], "local_service", strlen("local_service"))) {
2985 local_service = get_string_param(argv[i]);
2986 if (local_service == NULL) {
2992 if (local_service == NULL) {
2993 local_service = talloc_asprintf(c, "%s$@%s",
2994 lp_netbios_name(), lp_realm());
2995 if (local_service == NULL) {
3000 c->opt_password = net_prompt_pass(c, c->opt_user_name);
3002 status = kerberos_return_pac(c,
3011 2592000, /* one month */
3012 impersonate_princ_s,
3017 if (!NT_STATUS_IS_OK(status)) {
3018 d_printf(_("failed to query kerberos PAC: %s\n"),
3028 static int net_ads_kerberos_pac_dump(struct net_context *c, int argc, const char **argv)
3030 struct PAC_DATA_CTR *pac_data_ctr = NULL;
3033 enum PAC_TYPE type = 0;
3035 if (c->display_usage) {
3037 "net ads kerberos pac dump [impersonate=string] [local_service=string] [pac_buffer_type=int]\n"
3040 _("Dump the Kerberos PAC"));
3044 for (i=0; i<argc; i++) {
3045 if (strnequal(argv[i], "pac_buffer_type", strlen("pac_buffer_type"))) {
3046 type = get_int_param(argv[i]);
3050 ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3059 s = NDR_PRINT_STRUCT_STRING(c, PAC_DATA,
3060 pac_data_ctr->pac_data);
3062 d_printf(_("The Pac: %s\n"), s);
3069 num_buffers = pac_data_ctr->pac_data->num_buffers;
3071 for (i=0; i<num_buffers; i++) {
3075 if (pac_data_ctr->pac_data->buffers[i].type != type) {
3079 s = NDR_PRINT_UNION_STRING(c, PAC_INFO, type,
3080 pac_data_ctr->pac_data->buffers[i].info);
3082 d_printf(_("The Pac: %s\n"), s);
3091 static int net_ads_kerberos_pac_save(struct net_context *c, int argc, const char **argv)
3093 struct PAC_DATA_CTR *pac_data_ctr = NULL;
3094 char *filename = NULL;
3098 if (c->display_usage) {
3100 "net ads kerberos pac save [impersonate=string] [local_service=string] [filename=string]\n"
3103 _("Save the Kerberos PAC"));
3107 for (i=0; i<argc; i++) {
3108 if (strnequal(argv[i], "filename", strlen("filename"))) {
3109 filename = get_string_param(argv[i]);
3110 if (filename == NULL) {
3116 ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3121 if (filename == NULL) {
3122 d_printf(_("please define \"filename=<filename>\" to save the PAC\n"));
3126 /* save the raw format */
3127 if (!file_save(filename, pac_data_ctr->pac_blob.data, pac_data_ctr->pac_blob.length)) {
3128 d_printf(_("failed to save PAC in %s\n"), filename);
3135 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
3137 struct functable func[] = {
3140 net_ads_kerberos_pac_dump,
3142 N_("Dump Kerberos PAC"),
3143 N_("net ads kerberos pac dump\n"
3144 " Dump a Kerberos PAC to stdout")
3148 net_ads_kerberos_pac_save,
3150 N_("Save Kerberos PAC"),
3151 N_("net ads kerberos pac save\n"
3152 " Save a Kerberos PAC in a file")
3155 {NULL, NULL, 0, NULL, NULL}
3158 return net_run_function(c, argc, argv, "net ads kerberos pac", func);
3161 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
3163 TALLOC_CTX *mem_ctx = NULL;
3167 if (c->display_usage) {
3169 "net ads kerberos kinit\n"
3172 _("Get Ticket Granting Ticket (TGT) for the user"));
3176 mem_ctx = talloc_init("net_ads_kerberos_kinit");
3181 c->opt_password = net_prompt_pass(c, c->opt_user_name);
3183 ret = kerberos_kinit_password_ext(c->opt_user_name,
3191 2592000, /* one month */
3197 d_printf(_("failed to kinit password: %s\n"),
3204 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3206 struct functable func[] = {
3209 net_ads_kerberos_kinit,
3211 N_("Retrieve Ticket Granting Ticket (TGT)"),
3212 N_("net ads kerberos kinit\n"
3213 " Receive Ticket Granting Ticket (TGT)")
3217 net_ads_kerberos_renew,
3219 N_("Renew Ticket Granting Ticket from credential cache"),
3220 N_("net ads kerberos renew\n"
3221 " Renew Ticket Granting Ticket (TGT) from "
3226 net_ads_kerberos_pac,
3228 N_("Dump Kerberos PAC"),
3229 N_("net ads kerberos pac\n"
3230 " Dump Kerberos PAC")
3232 {NULL, NULL, 0, NULL, NULL}
3235 return net_run_function(c, argc, argv, "net ads kerberos", func);
3238 static int net_ads_setspn_list(struct net_context *c, int argc, const char **argv)
3242 ADS_STRUCT *ads = NULL;
3243 if (c->display_usage) {
3246 _("net ads setspn list <machinename>\n"));
3250 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3255 ok = ads_setspn_list(ads, argv[0]);
3257 ok = ads_setspn_list(ads, lp_netbios_name());
3269 static int net_ads_setspn_add(struct net_context *c, int argc, const char **argv)
3273 ADS_STRUCT *ads = NULL;
3274 if (c->display_usage || argc < 1) {
3277 _("net ads setspn add <machinename> SPN\n"));
3281 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3286 ok = ads_setspn_add(ads, argv[0], argv[1]);
3288 ok = ads_setspn_add(ads, lp_netbios_name(), argv[0]);
3300 static int net_ads_setspn_delete(struct net_context *c, int argc, const char **argv)
3304 ADS_STRUCT *ads = NULL;
3305 if (c->display_usage || argc < 1) {
3308 _("net ads setspn delete <machinename> SPN\n"));
3312 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3317 ok = ads_setspn_delete(ads, argv[0], argv[1]);
3319 ok = ads_setspn_delete(ads, lp_netbios_name(), argv[0]);
3331 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
3333 struct functable func[] = {
3336 net_ads_setspn_list,
3338 N_("List Service Principal Names (SPN)"),
3339 N_("net ads setspn list machine\n"
3340 " List Service Principal Names (SPN)")
3346 N_("Add Service Principal Names (SPN)"),
3347 N_("net ads setspn add machine spn\n"
3348 " Add Service Principal Names (SPN)")
3352 net_ads_setspn_delete,
3354 N_("Delete Service Principal Names (SPN)"),
3355 N_("net ads setspn delete machine spn\n"
3356 " Delete Service Principal Names (SPN)")
3358 {NULL, NULL, 0, NULL, NULL}
3361 return net_run_function(c, argc, argv, "net ads setspn", func);
3364 static int net_ads_enctype_lookup_account(struct net_context *c,
3366 const char *account,
3368 const char **enctype_str)
3371 const char *attrs[] = {
3372 "msDS-SupportedEncryptionTypes",
3379 filter = talloc_asprintf(c, "(&(objectclass=user)(sAMAccountName=%s))",
3381 if (filter == NULL) {
3385 status = ads_search(ads, res, filter, attrs);
3386 if (!ADS_ERR_OK(status)) {
3387 d_printf(_("no account found with filter: %s\n"), filter);
3391 count = ads_count_replies(ads, *res);
3396 d_printf(_("no account found with filter: %s\n"), filter);
3399 d_printf(_("multiple accounts found with filter: %s\n"), filter);
3404 *enctype_str = ads_pull_string(ads, c, *res,
3405 "msDS-SupportedEncryptionTypes");
3406 if (*enctype_str == NULL) {
3407 d_printf(_("no msDS-SupportedEncryptionTypes attribute found\n"));
3417 static void net_ads_enctype_dump_enctypes(const char *username,
3418 const char *enctype_str)
3420 int enctypes = atoi(enctype_str);
3422 d_printf(_("'%s' uses \"msDS-SupportedEncryptionTypes\": %d (0x%08x)\n"),
3423 username, enctypes, enctypes);
3425 printf("[%s] 0x%08x DES-CBC-CRC\n",
3426 enctypes & ENC_CRC32 ? "X" : " ",
3428 printf("[%s] 0x%08x DES-CBC-MD5\n",
3429 enctypes & ENC_RSA_MD5 ? "X" : " ",
3431 printf("[%s] 0x%08x RC4-HMAC\n",
3432 enctypes & ENC_RC4_HMAC_MD5 ? "X" : " ",
3434 printf("[%s] 0x%08x AES128-CTS-HMAC-SHA1-96\n",
3435 enctypes & ENC_HMAC_SHA1_96_AES128 ? "X" : " ",
3436 ENC_HMAC_SHA1_96_AES128);
3437 printf("[%s] 0x%08x AES256-CTS-HMAC-SHA1-96\n",
3438 enctypes & ENC_HMAC_SHA1_96_AES256 ? "X" : " ",
3439 ENC_HMAC_SHA1_96_AES256);
3442 static int net_ads_enctypes_list(struct net_context *c, int argc, const char **argv)
3446 ADS_STRUCT *ads = NULL;
3447 LDAPMessage *res = NULL;
3448 const char *str = NULL;
3450 if (c->display_usage || (argc < 1)) {
3452 "net ads enctypes list\n"
3455 _("List supported enctypes"));
3459 status = ads_startup(c, false, &ads);
3460 if (!ADS_ERR_OK(status)) {
3461 printf("startup failed\n");
3465 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3470 net_ads_enctype_dump_enctypes(argv[0], str);
3474 ads_msgfree(ads, res);
3480 static int net_ads_enctypes_set(struct net_context *c, int argc, const char **argv)
3485 LDAPMessage *res = NULL;
3486 const char *etype_list_str;
3489 uint32_t etype_list;
3492 if (c->display_usage || argc < 1) {
3494 "net ads enctypes set <sAMAccountName> [enctypes]\n"
3497 _("Set supported enctypes"));
3501 status = ads_startup(c, false, &ads);
3502 if (!ADS_ERR_OK(status)) {
3503 printf("startup failed\n");
3507 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3512 dn = ads_get_dn(ads, c, res);
3517 etype_list = ENC_CRC32 | ENC_RSA_MD5 | ENC_RC4_HMAC_MD5;
3518 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
3519 etype_list |= ENC_HMAC_SHA1_96_AES128;
3521 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
3522 etype_list |= ENC_HMAC_SHA1_96_AES256;
3525 if (argv[1] != NULL) {
3526 sscanf(argv[1], "%i", &etype_list);
3529 etype_list_str = talloc_asprintf(c, "%d", etype_list);
3530 if (!etype_list_str) {
3534 mods = ads_init_mods(c);
3539 status = ads_mod_str(c, &mods, "msDS-SupportedEncryptionTypes",
3541 if (!ADS_ERR_OK(status)) {
3545 status = ads_gen_mod(ads, dn, mods);
3546 if (!ADS_ERR_OK(status)) {
3547 d_printf(_("failed to add msDS-SupportedEncryptionTypes: %s\n"),
3548 ads_errstr(status));
3552 ads_msgfree(ads, res);
3554 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3559 net_ads_enctype_dump_enctypes(argv[0], str);
3563 ads_msgfree(ads, res);
3569 static int net_ads_enctypes_delete(struct net_context *c, int argc, const char **argv)
3574 LDAPMessage *res = NULL;
3578 if (c->display_usage || argc < 1) {
3580 "net ads enctypes delete <sAMAccountName>\n"
3583 _("Delete supported enctypes"));
3587 status = ads_startup(c, false, &ads);
3588 if (!ADS_ERR_OK(status)) {
3589 printf("startup failed\n");
3593 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3598 dn = ads_get_dn(ads, c, res);
3603 mods = ads_init_mods(c);
3608 status = ads_mod_str(c, &mods, "msDS-SupportedEncryptionTypes", NULL);
3609 if (!ADS_ERR_OK(status)) {
3613 status = ads_gen_mod(ads, dn, mods);
3614 if (!ADS_ERR_OK(status)) {
3615 d_printf(_("failed to remove msDS-SupportedEncryptionTypes: %s\n"),
3616 ads_errstr(status));
3623 ads_msgfree(ads, res);
3628 static int net_ads_enctypes(struct net_context *c, int argc, const char **argv)
3630 struct functable func[] = {
3633 net_ads_enctypes_list,
3635 N_("List the supported encryption types"),
3636 N_("net ads enctypes list\n"
3637 " List the supported encryption types")
3641 net_ads_enctypes_set,
3643 N_("Set the supported encryption types"),
3644 N_("net ads enctypes set\n"
3645 " Set the supported encryption types")
3649 net_ads_enctypes_delete,
3651 N_("Delete the supported encryption types"),
3652 N_("net ads enctypes delete\n"
3653 " Delete the supported encryption types")
3656 {NULL, NULL, 0, NULL, NULL}
3659 return net_run_function(c, argc, argv, "net ads enctypes", func);
3663 int net_ads(struct net_context *c, int argc, const char **argv)
3665 struct functable func[] = {
3670 N_("Display details on remote ADS server"),
3672 " Display details on remote ADS server")
3678 N_("Join the local machine to ADS realm"),
3680 " Join the local machine to ADS realm")
3686 N_("Validate machine account"),
3687 N_("net ads testjoin\n"
3688 " Validate machine account")
3694 N_("Remove the local machine from ADS"),
3695 N_("net ads leave\n"
3696 " Remove the local machine from ADS")
3702 N_("Display machine account details"),
3703 N_("net ads status\n"
3704 " Display machine account details")
3710 N_("List/modify users"),
3712 " List/modify users")
3718 N_("List/modify groups"),
3719 N_("net ads group\n"
3720 " List/modify groups")
3726 N_("Issue dynamic DNS update"),
3728 " Issue dynamic DNS update")
3734 N_("Change user passwords"),
3735 N_("net ads password\n"
3736 " Change user passwords")
3740 net_ads_changetrustpw,
3742 N_("Change trust account password"),
3743 N_("net ads changetrustpw\n"
3744 " Change trust account password")
3750 N_("List/modify printer entries"),
3751 N_("net ads printer\n"
3752 " List/modify printer entries")
3758 N_("Issue LDAP search using filter"),
3759 N_("net ads search\n"
3760 " Issue LDAP search using filter")
3766 N_("Issue LDAP search by DN"),
3768 " Issue LDAP search by DN")
3774 N_("Issue LDAP search by SID"),
3776 " Issue LDAP search by SID")
3782 N_("Display workgroup name"),
3783 N_("net ads workgroup\n"
3784 " Display the workgroup name")
3790 N_("Perform CLDAP query on DC"),
3791 N_("net ads lookup\n"
3792 " Find the ADS DC using CLDAP lookups")
3798 N_("Manage local keytab file"),
3799 N_("net ads keytab\n"
3800 " Manage local keytab file")
3806 N_("Manage Service Principal Names (SPN)s"),
3807 N_("net ads spnset\n"
3808 " Manage Service Principal Names (SPN)s")
3814 N_("Manage group policy objects"),
3816 " Manage group policy objects")
3822 N_("Manage kerberos keytab"),
3823 N_("net ads kerberos\n"
3824 " Manage kerberos keytab")
3830 N_("List/modify supported encryption types"),
3831 N_("net ads enctypes\n"
3832 " List/modify enctypes")
3834 {NULL, NULL, 0, NULL, NULL}
3837 return net_run_function(c, argc, argv, "net ads", func);
3842 static int net_ads_noads(void)
3844 d_fprintf(stderr, _("ADS support not compiled in\n"));
3848 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
3850 return net_ads_noads();
3853 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3855 return net_ads_noads();
3858 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
3860 return net_ads_noads();
3863 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
3865 return net_ads_noads();
3868 int net_ads_join(struct net_context *c, int argc, const char **argv)
3870 return net_ads_noads();
3873 int net_ads_user(struct net_context *c, int argc, const char **argv)
3875 return net_ads_noads();
3878 int net_ads_group(struct net_context *c, int argc, const char **argv)
3880 return net_ads_noads();
3883 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
3885 return net_ads_noads();
3888 /* this one shouldn't display a message */
3889 int net_ads_check(struct net_context *c)
3894 int net_ads_check_our_domain(struct net_context *c)
3899 int net_ads(struct net_context *c, int argc, const char **argv)
3901 return net_ads_noads();
3904 #endif /* HAVE_ADS */