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 TALLOC_CTX *tmp_ctx = talloc_stackframe();
973 ADS_STRUCT *ads = NULL;
975 LDAPMessage *res = NULL;
978 const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
979 char *searchstring = NULL;
980 char **grouplist = NULL;
981 char *primary_group = NULL;
982 char *escaped_user = NULL;
983 struct dom_sid primary_group_sid;
985 enum wbcSidType type;
987 if (argc < 1 || c->display_usage) {
988 TALLOC_FREE(tmp_ctx);
989 return net_ads_user_usage(c, argc, argv);
992 escaped_user = escape_ldap_string(tmp_ctx, argv[0]);
995 _("ads_user_info: failed to escape user %s\n"),
1000 status = ads_startup(c, false, &ads);
1001 if (!ADS_ERR_OK(status)) {
1005 searchstring = talloc_asprintf(tmp_ctx,
1006 "(sAMAccountName=%s)",
1008 if (searchstring == NULL) {
1012 status = ads_search(ads, &res, searchstring, attrs);
1013 if (!ADS_ERR_OK(status)) {
1014 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(status));
1018 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
1019 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
1023 status = ads_domain_sid(ads, &primary_group_sid);
1024 if (!ADS_ERR_OK(status)) {
1025 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(status));
1029 sid_append_rid(&primary_group_sid, group_rid);
1031 wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
1032 NULL, /* don't look up domain */
1035 if (!WBC_ERROR_IS_OK(wbc_status)) {
1036 d_fprintf(stderr, "wbcLookupSid: %s\n",
1037 wbcErrorString(wbc_status));
1041 d_printf("%s\n", primary_group);
1043 wbcFreeMemory(primary_group);
1045 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
1046 (LDAPMessage *)res, "memberOf");
1051 for (i=0;grouplist[i];i++) {
1052 groupname = ldap_explode_dn(grouplist[i], 1);
1053 d_printf("%s\n", groupname[0]);
1054 ldap_value_free(groupname);
1056 ldap_value_free(grouplist);
1061 ads_msgfree(ads, res);
1063 TALLOC_FREE(tmp_ctx);
1067 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
1069 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1070 ADS_STRUCT *ads = NULL;
1072 LDAPMessage *res = NULL;
1073 char *userdn = NULL;
1077 TALLOC_FREE(tmp_ctx);
1078 return net_ads_user_usage(c, argc, argv);
1081 status = ads_startup(c, false, &ads);
1082 if (!ADS_ERR_OK(status)) {
1086 status = ads_find_user_acct(ads, &res, argv[0]);
1087 if (!ADS_ERR_OK(status) || ads_count_replies(ads, res) != 1) {
1088 d_printf(_("User %s does not exist.\n"), argv[0]);
1092 userdn = ads_get_dn(ads, tmp_ctx, res);
1093 if (userdn == NULL) {
1097 status = ads_del_dn(ads, userdn);
1098 if (!ADS_ERR_OK(status)) {
1099 d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
1100 ads_errstr(status));
1104 d_printf(_("User %s deleted\n"), argv[0]);
1108 ads_msgfree(ads, res);
1110 TALLOC_FREE(tmp_ctx);
1114 int net_ads_user(struct net_context *c, int argc, const char **argv)
1116 struct functable func[] = {
1121 N_("Add an AD user"),
1122 N_("net ads user add\n"
1129 N_("Display information about an AD user"),
1130 N_("net ads user info\n"
1131 " Display information about an AD user")
1137 N_("Delete an AD user"),
1138 N_("net ads user delete\n"
1139 " Delete an AD user")
1141 {NULL, NULL, 0, NULL, NULL}
1143 TALLOC_CTX *tmp_ctx = talloc_stackframe();
1144 ADS_STRUCT *ads = NULL;
1146 const char *shortattrs[] = {"sAMAccountName", NULL};
1147 const char *longattrs[] = {"sAMAccountName", "description", NULL};
1148 char *disp_fields[2] = {NULL, NULL};
1152 TALLOC_FREE(tmp_ctx);
1153 return net_run_function(c, argc, argv, "net ads user", func);
1156 if (c->display_usage) {
1161 _("List AD users"));
1162 net_display_usage_from_functable(func);
1163 TALLOC_FREE(tmp_ctx);
1167 status = ads_startup(c, false, &ads);
1168 if (!ADS_ERR_OK(status)) {
1172 if (c->opt_long_list_entries)
1173 d_printf(_("\nUser name Comment"
1174 "\n-----------------------------\n"));
1176 status = ads_do_search_all_fn(ads,
1177 ads->config.bind_path,
1179 "(objectCategory=user)",
1180 c->opt_long_list_entries ?
1181 longattrs : shortattrs,
1184 if (!ADS_ERR_OK(status)) {
1191 TALLOC_FREE(tmp_ctx);
1195 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
1197 return net_group_usage(c, argc, argv);
1200 static int ads_group_add(struct net_context *c, int argc, const char **argv)
1204 LDAPMessage *res=NULL;
1206 char *ou_str = NULL;
1208 if (argc < 1 || c->display_usage) {
1209 return net_ads_group_usage(c, argc, argv);
1212 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1216 status = ads_find_user_acct(ads, &res, argv[0]);
1218 if (!ADS_ERR_OK(status)) {
1219 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
1223 if (ads_count_replies(ads, res)) {
1224 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
1228 if (c->opt_container) {
1229 ou_str = SMB_STRDUP(c->opt_container);
1231 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
1234 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
1236 if (ADS_ERR_OK(status)) {
1237 d_printf(_("Group %s added\n"), argv[0]);
1240 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
1241 ads_errstr(status));
1246 ads_msgfree(ads, res);
1252 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
1256 LDAPMessage *res = NULL;
1259 if (argc < 1 || c->display_usage) {
1260 return net_ads_group_usage(c, argc, argv);
1263 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1267 rc = ads_find_user_acct(ads, &res, argv[0]);
1268 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
1269 d_printf(_("Group %s does not exist.\n"), argv[0]);
1270 ads_msgfree(ads, res);
1274 groupdn = ads_get_dn(ads, talloc_tos(), res);
1275 ads_msgfree(ads, res);
1276 rc = ads_del_dn(ads, groupdn);
1277 TALLOC_FREE(groupdn);
1278 if (ADS_ERR_OK(rc)) {
1279 d_printf(_("Group %s deleted\n"), argv[0]);
1283 d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
1289 int net_ads_group(struct net_context *c, int argc, const char **argv)
1291 struct functable func[] = {
1296 N_("Add an AD group"),
1297 N_("net ads group add\n"
1304 N_("Delete an AD group"),
1305 N_("net ads group delete\n"
1306 " Delete an AD group")
1308 {NULL, NULL, 0, NULL, NULL}
1312 const char *shortattrs[] = {"sAMAccountName", NULL};
1313 const char *longattrs[] = {"sAMAccountName", "description", NULL};
1314 char *disp_fields[2] = {NULL, NULL};
1317 if (c->display_usage) {
1322 _("List AD groups"));
1323 net_display_usage_from_functable(func);
1327 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1331 if (c->opt_long_list_entries)
1332 d_printf(_("\nGroup name Comment"
1333 "\n-----------------------------\n"));
1334 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
1336 "(objectCategory=group)",
1337 c->opt_long_list_entries ? longattrs :
1338 shortattrs, usergrp_display,
1342 return ADS_ERR_OK(rc) ? 0 : -1;
1344 return net_run_function(c, argc, argv, "net ads group", func);
1347 static int net_ads_status(struct net_context *c, int argc, const char **argv)
1353 if (c->display_usage) {
1358 _("Display machine account details"));
1362 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1366 rc = ads_find_machine_acct(ads, &res, lp_netbios_name());
1367 if (!ADS_ERR_OK(rc)) {
1368 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
1373 if (ads_count_replies(ads, res) == 0) {
1374 d_fprintf(stderr, _("No machine account for '%s' found\n"), lp_netbios_name());
1384 /*******************************************************************
1385 Leave an AD domain. Windows XP disables the machine account.
1386 We'll try the same. The old code would do an LDAP delete.
1387 That only worked using the machine creds because added the machine
1388 with full control to the computer object's ACL.
1389 *******************************************************************/
1391 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
1394 struct libnet_UnjoinCtx *r = NULL;
1397 if (c->display_usage) {
1399 "net ads leave [--keep-account]\n"
1402 _("Leave an AD domain"));
1407 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
1411 if (!(ctx = talloc_init("net_ads_leave"))) {
1412 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1416 if (!c->opt_kerberos) {
1417 use_in_memory_ccache();
1421 d_fprintf(stderr, _("Could not initialise message context. "
1422 "Try running as root\n"));
1426 werr = libnet_init_UnjoinCtx(ctx, &r);
1427 if (!W_ERROR_IS_OK(werr)) {
1428 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
1433 r->in.use_kerberos = c->opt_kerberos;
1434 r->in.dc_name = c->opt_host;
1435 r->in.domain_name = lp_realm();
1436 r->in.admin_account = c->opt_user_name;
1437 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1438 r->in.modify_config = lp_config_backend_is_registry();
1440 /* Try to delete it, but if that fails, disable it. The
1441 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
1442 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1443 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
1444 if (c->opt_keep_account) {
1445 r->in.delete_machine_account = false;
1447 r->in.delete_machine_account = true;
1450 r->in.msg_ctx = c->msg_ctx;
1452 werr = libnet_Unjoin(ctx, r);
1453 if (!W_ERROR_IS_OK(werr)) {
1454 d_printf(_("Failed to leave domain: %s\n"),
1455 r->out.error_string ? r->out.error_string :
1456 get_friendly_werror_msg(werr));
1460 if (r->out.deleted_machine_account) {
1461 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1462 r->in.machine_name, r->out.dns_domain_name);
1466 /* We couldn't delete it - see if the disable succeeded. */
1467 if (r->out.disabled_machine_account) {
1468 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1469 r->in.machine_name, r->out.dns_domain_name);
1474 /* Based on what we requested, we shouldn't get here, but if
1475 we did, it means the secrets were removed, and therefore
1476 we have left the domain */
1477 d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1478 r->in.machine_name, r->out.dns_domain_name);
1484 if (W_ERROR_IS_OK(werr)) {
1491 static NTSTATUS net_ads_join_ok(struct net_context *c)
1493 ADS_STRUCT *ads = NULL;
1496 struct sockaddr_storage dcip;
1498 if (!secrets_init()) {
1499 DEBUG(1,("Failed to initialise secrets database\n"));
1500 return NT_STATUS_ACCESS_DENIED;
1503 net_use_krb_machine_account(c);
1505 get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1507 status = ads_startup(c, true, &ads);
1508 if (!ADS_ERR_OK(status)) {
1509 return ads_ntstatus(status);
1513 return NT_STATUS_OK;
1517 check that an existing join is OK
1519 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1522 use_in_memory_ccache();
1524 if (c->display_usage) {
1526 "net ads testjoin\n"
1529 _("Test if the existing join is ok"));
1533 /* Display success or failure */
1534 status = net_ads_join_ok(c);
1535 if (!NT_STATUS_IS_OK(status)) {
1536 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1537 get_friendly_nt_error_msg(status));
1541 printf(_("Join is OK\n"));
1545 /*******************************************************************
1546 Simple config checks before beginning the join
1547 ********************************************************************/
1549 static WERROR check_ads_config( void )
1551 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1552 d_printf(_("Host is not configured as a member server.\n"));
1553 return WERR_INVALID_DOMAIN_ROLE;
1556 if (strlen(lp_netbios_name()) > 15) {
1557 d_printf(_("Our netbios name can be at most 15 chars long, "
1558 "\"%s\" is %u chars long\n"), lp_netbios_name(),
1559 (unsigned int)strlen(lp_netbios_name()));
1560 return WERR_INVALID_COMPUTERNAME;
1563 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1564 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1565 "join to succeed.\n"), get_dyn_CONFIGFILE());
1566 return WERR_INVALID_PARAMETER;
1572 /*******************************************************************
1573 ********************************************************************/
1575 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1577 d_printf(_("net ads join [--no-dns-updates] [options]\n"
1578 "Valid options:\n"));
1579 d_printf(_(" dnshostname=FQDN Set the dnsHostName attribute during the join.\n"
1580 " The default is in the form netbiosname.dnsdomain\n"));
1581 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1582 " The default UPN is in the form host/netbiosname@REALM.\n"));
1583 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1584 " The OU string read from top to bottom without RDNs\n"
1585 " and delimited by a '/'.\n"
1586 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1587 " NB: A backslash '\\' is used as escape at multiple\n"
1588 " levels and may need to be doubled or even\n"
1589 " quadrupled. It is not used as a separator.\n"));
1590 d_printf(_(" machinepass=PASS Set the machine password to a specific value during\n"
1591 " the join. The default password is random.\n"));
1592 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1593 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during join.\n"
1594 " NB: osName and osVer must be specified together for\n"
1595 " either to take effect. The operatingSystemService\n"
1596 " attribute is then also set along with the two\n"
1597 " other attributes.\n"));
1598 d_printf(_(" osServicePack=string Set the operatingSystemServicePack attribute\n"
1599 " during the join.\n"
1600 " NB: If not specified then by default the samba\n"
1601 " version string is used instead.\n"));
1606 int net_ads_join(struct net_context *c, int argc, const char **argv)
1608 TALLOC_CTX *ctx = NULL;
1609 struct libnet_JoinCtx *r = NULL;
1610 const char *domain = lp_realm();
1611 WERROR werr = WERR_NERR_SETUPNOTJOINED;
1612 bool createupn = false;
1613 const char *dnshostname = NULL;
1614 const char *machineupn = NULL;
1615 const char *machine_password = NULL;
1616 const char *create_in_ou = NULL;
1618 const char *os_name = NULL;
1619 const char *os_version = NULL;
1620 const char *os_servicepack = NULL;
1621 bool modify_config = lp_config_backend_is_registry();
1622 enum libnetjoin_JoinDomNameType domain_name_type = JoinDomNameTypeDNS;
1624 if (c->display_usage)
1625 return net_ads_join_usage(c, argc, argv);
1627 if (!modify_config) {
1629 werr = check_ads_config();
1630 if (!W_ERROR_IS_OK(werr)) {
1631 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1636 if (!(ctx = talloc_init("net_ads_join"))) {
1637 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1638 werr = WERR_NOT_ENOUGH_MEMORY;
1642 if (!c->opt_kerberos) {
1643 use_in_memory_ccache();
1646 werr = libnet_init_JoinCtx(ctx, &r);
1647 if (!W_ERROR_IS_OK(werr)) {
1651 /* process additional command line args */
1653 for ( i=0; i<argc; i++ ) {
1654 if ( !strncasecmp_m(argv[i], "dnshostname", strlen("dnshostname")) ) {
1655 dnshostname = get_string_param(argv[i]);
1657 else if ( !strncasecmp_m(argv[i], "createupn", strlen("createupn")) ) {
1659 machineupn = get_string_param(argv[i]);
1661 else if ( !strncasecmp_m(argv[i], "createcomputer", strlen("createcomputer")) ) {
1662 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1663 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1664 werr = WERR_INVALID_PARAMETER;
1668 else if ( !strncasecmp_m(argv[i], "osName", strlen("osName")) ) {
1669 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1670 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1671 werr = WERR_INVALID_PARAMETER;
1675 else if ( !strncasecmp_m(argv[i], "osVer", strlen("osVer")) ) {
1676 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1677 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1678 werr = WERR_INVALID_PARAMETER;
1682 else if ( !strncasecmp_m(argv[i], "osServicePack", strlen("osServicePack")) ) {
1683 if ( (os_servicepack = get_string_param(argv[i])) == NULL ) {
1684 d_fprintf(stderr, _("Please supply a valid servicepack identifier.\n"));
1685 werr = WERR_INVALID_PARAMETER;
1689 else if ( !strncasecmp_m(argv[i], "machinepass", strlen("machinepass")) ) {
1690 if ( (machine_password = get_string_param(argv[i])) == NULL ) {
1691 d_fprintf(stderr, _("Please supply a valid password to set as trust account password.\n"));
1692 werr = WERR_INVALID_PARAMETER;
1698 if (strchr(domain, '.') == NULL) {
1699 domain_name_type = JoinDomNameTypeUnknown;
1701 domain_name_type = JoinDomNameTypeDNS;
1707 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1708 werr = WERR_INVALID_PARAMETER;
1713 d_fprintf(stderr, _("Could not initialise message context. "
1714 "Try running as root\n"));
1715 werr = WERR_ACCESS_DENIED;
1719 /* Do the domain join here */
1721 r->in.domain_name = domain;
1722 r->in.domain_name_type = domain_name_type;
1723 r->in.create_upn = createupn;
1724 r->in.upn = machineupn;
1725 r->in.dnshostname = dnshostname;
1726 r->in.account_ou = create_in_ou;
1727 r->in.os_name = os_name;
1728 r->in.os_version = os_version;
1729 r->in.os_servicepack = os_servicepack;
1730 r->in.dc_name = c->opt_host;
1731 r->in.admin_account = c->opt_user_name;
1732 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1733 r->in.machine_password = machine_password;
1735 r->in.use_kerberos = c->opt_kerberos;
1736 r->in.modify_config = modify_config;
1737 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1738 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1739 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1740 r->in.msg_ctx = c->msg_ctx;
1742 werr = libnet_Join(ctx, r);
1743 if (W_ERROR_EQUAL(werr, WERR_NERR_DCNOTFOUND) &&
1744 strequal(domain, lp_realm())) {
1745 r->in.domain_name = lp_workgroup();
1746 r->in.domain_name_type = JoinDomNameTypeNBT;
1747 werr = libnet_Join(ctx, r);
1749 if (!W_ERROR_IS_OK(werr)) {
1753 /* Check the short name of the domain */
1755 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1756 d_printf(_("The workgroup in %s does not match the short\n"
1757 "domain name obtained from the server.\n"
1758 "Using the name [%s] from the server.\n"
1759 "You should set \"workgroup = %s\" in %s.\n"),
1760 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1761 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1764 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1766 if (r->out.dns_domain_name) {
1767 d_printf(_("Joined '%s' to dns domain '%s'\n"), r->in.machine_name,
1768 r->out.dns_domain_name);
1770 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1771 r->out.netbios_domain_name);
1774 /* print out informative error string in case there is one */
1775 if (r->out.error_string != NULL) {
1776 d_printf("%s\n", r->out.error_string);
1780 * We try doing the dns update (if it was compiled in
1781 * and if it was not disabled on the command line).
1782 * If the dns update fails, we still consider the join
1783 * operation as succeeded if we came this far.
1785 if (!c->opt_no_dns_updates) {
1786 net_ads_join_dns_updates(c, ctx, r);
1795 /* issue an overall failure message at the end. */
1796 d_printf(_("Failed to join domain: %s\n"),
1797 r && r->out.error_string ? r->out.error_string :
1798 get_friendly_werror_msg(werr));
1804 /*******************************************************************
1805 ********************************************************************/
1807 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1809 #if defined(HAVE_KRB5)
1814 const char *hostname = NULL;
1815 const char **addrs_list = NULL;
1816 struct sockaddr_storage *addrs = NULL;
1821 talloc_enable_leak_report();
1824 if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
1825 d_fprintf(stderr, _("Refusing DNS updates with automatic "
1826 "detection of addresses in a clustered "
1828 c->display_usage = true;
1831 if (c->display_usage) {
1833 "net ads dns register [hostname [IP [IP...]]]\n"
1836 _("Register hostname with DNS\n"));
1840 if (!(ctx = talloc_init("net_ads_dns"))) {
1841 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1850 num_addrs = argc - 1;
1851 addrs_list = &argv[1];
1852 } else if (lp_clustering()) {
1853 addrs_list = lp_cluster_addresses();
1854 num_addrs = str_list_length(addrs_list);
1857 if (num_addrs > 0) {
1858 addrs = talloc_zero_array(ctx, struct sockaddr_storage, num_addrs);
1859 if (addrs == NULL) {
1860 d_fprintf(stderr, _("Error allocating memory!\n"));
1866 for (count = 0; count < num_addrs; count++) {
1867 if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
1868 d_fprintf(stderr, "%s '%s'.\n",
1869 _("Cannot interpret address"),
1876 status = ads_startup(c, true, &ads);
1877 if ( !ADS_ERR_OK(status) ) {
1878 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1883 ntstatus = net_update_dns_ext(c, ctx, ads, hostname, addrs, num_addrs, false);
1884 if (!NT_STATUS_IS_OK(ntstatus)) {
1885 d_fprintf( stderr, _("DNS update failed!\n") );
1886 ads_destroy( &ads );
1891 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1899 _("DNS update support not enabled at compile time!\n"));
1904 static int net_ads_dns_unregister(struct net_context *c,
1908 #if defined(HAVE_KRB5)
1913 const char *hostname = NULL;
1916 talloc_enable_leak_report();
1920 c->display_usage = true;
1923 if (c->display_usage) {
1925 "net ads dns unregister [hostname]\n"
1928 _("Remove all IP Address entires for a given\n"
1929 " hostname from the Active Directory server.\n"));
1933 if (!(ctx = talloc_init("net_ads_dns"))) {
1934 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1938 /* Get the hostname for un-registering */
1941 status = ads_startup(c, true, &ads);
1942 if ( !ADS_ERR_OK(status) ) {
1943 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1948 ntstatus = net_update_dns_ext(c, ctx, ads, hostname, NULL, 0, true);
1949 if (!NT_STATUS_IS_OK(ntstatus)) {
1950 d_fprintf( stderr, _("DNS update failed!\n") );
1951 ads_destroy( &ads );
1956 d_fprintf( stderr, _("Successfully un-registered hostname from DNS\n"));
1964 _("DNS update support not enabled at compile time!\n"));
1970 static int net_ads_dns_async(struct net_context *c, int argc, const char **argv)
1972 size_t num_names = 0;
1973 char **hostnames = NULL;
1975 struct samba_sockaddr *addrs = NULL;
1978 if (argc != 1 || c->display_usage) {
1983 _("net ads dns async <name>\n"),
1984 _(" Async look up hostname from the DNS server\n"
1985 " hostname\tName to look up\n"));
1989 status = ads_dns_lookup_a(talloc_tos(),
1994 if (!NT_STATUS_IS_OK(status)) {
1995 d_printf("Looking up A record for %s got error %s\n",
2000 d_printf("Async A record lookup - got %u names for %s\n",
2001 (unsigned int)num_names,
2003 for (i = 0; i < num_names; i++) {
2004 char addr_buf[INET6_ADDRSTRLEN];
2005 print_sockaddr(addr_buf,
2008 d_printf("hostname[%u] = %s, IPv4addr = %s\n",
2014 #if defined(HAVE_IPV6)
2015 status = ads_dns_lookup_aaaa(talloc_tos(),
2020 if (!NT_STATUS_IS_OK(status)) {
2021 d_printf("Looking up AAAA record for %s got error %s\n",
2026 d_printf("Async AAAA record lookup - got %u names for %s\n",
2027 (unsigned int)num_names,
2029 for (i = 0; i < num_names; i++) {
2030 char addr_buf[INET6_ADDRSTRLEN];
2031 print_sockaddr(addr_buf,
2034 d_printf("hostname[%u] = %s, IPv6addr = %s\n",
2044 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
2046 struct functable func[] = {
2049 net_ads_dns_register,
2051 N_("Add host dns entry to AD"),
2052 N_("net ads dns register\n"
2053 " Add host dns entry to AD")
2057 net_ads_dns_unregister,
2059 N_("Remove host dns entry from AD"),
2060 N_("net ads dns unregister\n"
2061 " Remove host dns entry from AD")
2068 N_("net ads dns async\n"
2069 " Look up host using async DNS")
2071 {NULL, NULL, 0, NULL, NULL}
2074 return net_run_function(c, argc, argv, "net ads dns", func);
2077 /*******************************************************************
2078 ********************************************************************/
2080 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
2083 "\nnet ads printer search <printer>"
2084 "\n\tsearch for a printer in the directory\n"
2085 "\nnet ads printer info <printer> <server>"
2086 "\n\tlookup info in directory for printer on server"
2087 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
2088 "\nnet ads printer publish <printername>"
2089 "\n\tpublish printer in directory"
2090 "\n\t(note: printer name is required)\n"
2091 "\nnet ads printer remove <printername>"
2092 "\n\tremove printer from directory"
2093 "\n\t(note: printer name is required)\n"));
2097 /*******************************************************************
2098 ********************************************************************/
2100 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
2104 LDAPMessage *res = NULL;
2106 if (c->display_usage) {
2108 "net ads printer search\n"
2111 _("List printers in the AD"));
2115 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2119 rc = ads_find_printers(ads, &res);
2121 if (!ADS_ERR_OK(rc)) {
2122 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
2123 ads_msgfree(ads, res);
2128 if (ads_count_replies(ads, res) == 0) {
2129 d_fprintf(stderr, _("No results found\n"));
2130 ads_msgfree(ads, res);
2136 ads_msgfree(ads, res);
2141 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
2145 const char *servername, *printername;
2146 LDAPMessage *res = NULL;
2148 if (c->display_usage) {
2151 _("net ads printer info [printername [servername]]\n"
2152 " Display printer info from AD\n"
2153 " printername\tPrinter name or wildcard\n"
2154 " servername\tName of the print server\n"));
2158 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2163 printername = argv[0];
2169 servername = argv[1];
2171 servername = lp_netbios_name();
2174 rc = ads_find_printer_on_server(ads, &res, printername, servername);
2176 if (!ADS_ERR_OK(rc)) {
2177 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
2178 servername, ads_errstr(rc));
2179 ads_msgfree(ads, res);
2184 if (ads_count_replies(ads, res) == 0) {
2185 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
2186 ads_msgfree(ads, res);
2192 ads_msgfree(ads, res);
2198 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
2202 const char *servername, *printername;
2203 struct cli_state *cli = NULL;
2204 struct rpc_pipe_client *pipe_hnd = NULL;
2205 struct sockaddr_storage server_ss;
2207 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
2208 ADS_MODLIST mods = ads_init_mods(mem_ctx);
2209 char *prt_dn, *srv_dn, **srv_cn;
2210 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
2211 LDAPMessage *res = NULL;
2214 if (argc < 1 || c->display_usage) {
2217 _("net ads printer publish <printername> [servername]\n"
2218 " Publish printer in AD\n"
2219 " printername\tName of the printer\n"
2220 " servername\tName of the print server\n"));
2221 talloc_destroy(mem_ctx);
2225 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2226 talloc_destroy(mem_ctx);
2230 printername = argv[0];
2233 servername = argv[1];
2235 servername = lp_netbios_name();
2238 /* Get printer data from SPOOLSS */
2240 ok = resolve_name(servername, &server_ss, 0x20, false);
2242 d_fprintf(stderr, _("Could not find server %s\n"),
2245 talloc_destroy(mem_ctx);
2249 cli_credentials_set_kerberos_state(c->creds,
2250 CRED_USE_KERBEROS_REQUIRED,
2253 nt_status = cli_full_connection_creds(&cli, lp_netbios_name(), servername,
2257 CLI_FULL_CONNECTION_IPC);
2259 if (NT_STATUS_IS_ERR(nt_status)) {
2260 d_fprintf(stderr, _("Unable to open a connection to %s to "
2261 "obtain data for %s\n"),
2262 servername, printername);
2264 talloc_destroy(mem_ctx);
2268 /* Publish on AD server */
2270 ads_find_machine_acct(ads, &res, servername);
2272 if (ads_count_replies(ads, res) == 0) {
2273 d_fprintf(stderr, _("Could not find machine account for server "
2277 talloc_destroy(mem_ctx);
2281 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
2282 srv_cn = ldap_explode_dn(srv_dn, 1);
2284 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
2285 printername_escaped = escape_rdn_val_string_alloc(printername);
2286 if (!srv_cn_escaped || !printername_escaped) {
2287 SAFE_FREE(srv_cn_escaped);
2288 SAFE_FREE(printername_escaped);
2289 d_fprintf(stderr, _("Internal error, out of memory!"));
2291 talloc_destroy(mem_ctx);
2295 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
2296 SAFE_FREE(srv_cn_escaped);
2297 SAFE_FREE(printername_escaped);
2298 d_fprintf(stderr, _("Internal error, out of memory!"));
2300 talloc_destroy(mem_ctx);
2304 SAFE_FREE(srv_cn_escaped);
2305 SAFE_FREE(printername_escaped);
2307 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss, &pipe_hnd);
2308 if (!NT_STATUS_IS_OK(nt_status)) {
2309 d_fprintf(stderr, _("Unable to open a connection to the spoolss pipe on %s\n"),
2313 talloc_destroy(mem_ctx);
2317 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
2321 talloc_destroy(mem_ctx);
2325 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
2326 if (!ADS_ERR_OK(rc)) {
2327 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
2330 talloc_destroy(mem_ctx);
2334 d_printf("published printer\n");
2337 talloc_destroy(mem_ctx);
2342 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
2346 const char *servername;
2348 LDAPMessage *res = NULL;
2350 if (argc < 1 || c->display_usage) {
2353 _("net ads printer remove <printername> [servername]\n"
2354 " Remove a printer from the AD\n"
2355 " printername\tName of the printer\n"
2356 " servername\tName of the print server\n"));
2360 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2365 servername = argv[1];
2367 servername = lp_netbios_name();
2370 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
2372 if (!ADS_ERR_OK(rc)) {
2373 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
2374 ads_msgfree(ads, res);
2379 if (ads_count_replies(ads, res) == 0) {
2380 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
2381 ads_msgfree(ads, res);
2386 prt_dn = ads_get_dn(ads, talloc_tos(), res);
2387 ads_msgfree(ads, res);
2388 rc = ads_del_dn(ads, prt_dn);
2389 TALLOC_FREE(prt_dn);
2391 if (!ADS_ERR_OK(rc)) {
2392 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
2401 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
2403 struct functable func[] = {
2406 net_ads_printer_search,
2408 N_("Search for a printer"),
2409 N_("net ads printer search\n"
2410 " Search for a printer")
2414 net_ads_printer_info,
2416 N_("Display printer information"),
2417 N_("net ads printer info\n"
2418 " Display printer information")
2422 net_ads_printer_publish,
2424 N_("Publish a printer"),
2425 N_("net ads printer publish\n"
2426 " Publish a printer")
2430 net_ads_printer_remove,
2432 N_("Delete a printer"),
2433 N_("net ads printer remove\n"
2434 " Delete a printer")
2436 {NULL, NULL, 0, NULL, NULL}
2439 return net_run_function(c, argc, argv, "net ads printer", func);
2443 static int net_ads_password(struct net_context *c, int argc, const char **argv)
2446 const char *auth_principal = cli_credentials_get_username(c->creds);
2447 const char *auth_password = cli_credentials_get_password(c->creds);
2448 const char *realm = NULL;
2449 const char *new_password = NULL;
2452 char pwd[256] = {0};
2455 if (c->display_usage) {
2458 _("net ads password <username>\n"
2459 " Change password for user\n"
2460 " username\tName of user to change password for\n"));
2464 if (auth_principal == NULL || auth_password == NULL) {
2465 d_fprintf(stderr, _("You must supply an administrator "
2466 "username/password\n"));
2471 d_fprintf(stderr, _("ERROR: You must say which username to "
2472 "change password for\n"));
2477 if (!strchr_m(user, '@')) {
2478 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
2484 use_in_memory_ccache();
2485 chr = strchr_m(auth_principal, '@');
2492 /* use the realm so we can eventually change passwords for users
2493 in realms other than default */
2494 ads = ads_init(realm, c->opt_workgroup, c->opt_host, ADS_SASL_PLAIN);
2499 /* we don't actually need a full connect, but it's the easy way to
2500 fill in the KDC's addresss */
2503 if (!ads->config.realm) {
2504 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
2510 new_password = (const char *)argv[1];
2514 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
2517 rc = samba_getpass(prompt, pwd, sizeof(pwd), false, true);
2525 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2526 auth_password, user, new_password, ads->auth.time_offset);
2527 memset(pwd, '\0', sizeof(pwd));
2528 if (!ADS_ERR_OK(ret)) {
2529 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2534 d_printf(_("Password change for %s completed.\n"), user);
2540 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2543 char *host_principal;
2547 if (c->display_usage) {
2549 "net ads changetrustpw\n"
2552 _("Change the machine account's trust password"));
2556 if (!secrets_init()) {
2557 DEBUG(1,("Failed to initialise secrets database\n"));
2561 net_use_krb_machine_account(c);
2563 use_in_memory_ccache();
2565 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2569 fstrcpy(my_name, lp_netbios_name());
2570 if (!strlower_m(my_name)) {
2575 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2579 d_printf(_("Changing password for principal: %s\n"), host_principal);
2581 ret = ads_change_trust_account_password(ads, host_principal);
2583 if (!ADS_ERR_OK(ret)) {
2584 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2586 SAFE_FREE(host_principal);
2590 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2592 if (USE_SYSTEM_KEYTAB) {
2593 d_printf(_("Attempting to update system keytab with new password.\n"));
2594 if (ads_keytab_create_default(ads)) {
2595 d_printf(_("Failed to update system keytab.\n"));
2600 SAFE_FREE(host_principal);
2606 help for net ads search
2608 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2611 "\nnet ads search <expression> <attributes...>\n"
2612 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2613 "The expression is a standard LDAP search expression, and the\n"
2614 "attributes are a list of LDAP fields to show in the results.\n\n"
2615 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2617 net_common_flags_usage(c, argc, argv);
2623 general ADS search function. Useful in diagnosing problems in ADS
2625 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2629 const char *ldap_exp;
2631 LDAPMessage *res = NULL;
2633 if (argc < 1 || c->display_usage) {
2634 return net_ads_search_usage(c, argc, argv);
2637 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2644 rc = ads_do_search_retry(ads, ads->config.bind_path,
2646 ldap_exp, attrs, &res);
2647 if (!ADS_ERR_OK(rc)) {
2648 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2653 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2655 /* dump the results */
2658 ads_msgfree(ads, res);
2666 help for net ads search
2668 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2671 "\nnet ads dn <dn> <attributes...>\n"
2672 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2673 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2674 "to show in the results\n\n"
2675 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2676 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2678 net_common_flags_usage(c, argc, argv);
2684 general ADS search function. Useful in diagnosing problems in ADS
2686 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2692 LDAPMessage *res = NULL;
2694 if (argc < 1 || c->display_usage) {
2695 return net_ads_dn_usage(c, argc, argv);
2698 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2705 rc = ads_do_search_all(ads, dn,
2707 "(objectclass=*)", attrs, &res);
2708 if (!ADS_ERR_OK(rc)) {
2709 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2714 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2716 /* dump the results */
2719 ads_msgfree(ads, res);
2726 help for net ads sid search
2728 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2731 "\nnet ads sid <sid> <attributes...>\n"
2732 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2733 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2734 "to show in the results\n\n"
2735 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2737 net_common_flags_usage(c, argc, argv);
2743 general ADS search function. Useful in diagnosing problems in ADS
2745 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2749 const char *sid_string;
2751 LDAPMessage *res = NULL;
2754 if (argc < 1 || c->display_usage) {
2755 return net_ads_sid_usage(c, argc, argv);
2758 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2762 sid_string = argv[0];
2765 if (!string_to_sid(&sid, sid_string)) {
2766 d_fprintf(stderr, _("could not convert sid\n"));
2771 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2772 if (!ADS_ERR_OK(rc)) {
2773 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2778 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2780 /* dump the results */
2783 ads_msgfree(ads, res);
2789 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2794 if (c->display_usage) {
2796 "net ads keytab flush\n"
2799 _("Delete the whole keytab"));
2803 if (!c->opt_user_specified && c->opt_password == NULL) {
2804 net_use_krb_machine_account(c);
2807 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2810 ret = ads_keytab_flush(ads);
2815 static int net_ads_keytab_add(struct net_context *c,
2824 if (c->display_usage) {
2827 _("net ads keytab add <principal> [principal ...]\n"
2828 " Add principals to local keytab\n"
2829 " principal\tKerberos principal to add to "
2834 d_printf(_("Processing principals to add...\n"));
2836 if (!c->opt_user_specified && c->opt_password == NULL) {
2837 net_use_krb_machine_account(c);
2840 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2843 for (i = 0; i < argc; i++) {
2844 ret |= ads_keytab_add_entry(ads, argv[i], update_ads);
2850 static int net_ads_keytab_add_default(struct net_context *c,
2854 return net_ads_keytab_add(c, argc, argv, false);
2857 static int net_ads_keytab_add_update_ads(struct net_context *c,
2861 return net_ads_keytab_add(c, argc, argv, true);
2864 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2869 if (c->display_usage) {
2871 "net ads keytab create\n"
2874 _("Create new default keytab"));
2878 if (!c->opt_user_specified && c->opt_password == NULL) {
2879 net_use_krb_machine_account(c);
2882 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2885 ret = ads_keytab_create_default(ads);
2890 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2892 const char *keytab = NULL;
2894 if (c->display_usage) {
2897 _("net ads keytab list [keytab]\n"
2898 " List a local keytab\n"
2899 " keytab\tKeytab to list\n"));
2907 return ads_keytab_list(keytab);
2911 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2913 struct functable func[] = {
2916 net_ads_keytab_add_default,
2918 N_("Add a service principal"),
2919 N_("net ads keytab add\n"
2920 " Add a service principal, updates keytab file only.")
2924 net_ads_keytab_add_update_ads,
2926 N_("Add a service principal"),
2927 N_("net ads keytab add_update_ads\n"
2928 " Add a service principal, depending on the param passed may update ADS computer object in addition to the keytab file.")
2932 net_ads_keytab_create,
2934 N_("Create a fresh keytab"),
2935 N_("net ads keytab create\n"
2936 " Create a fresh keytab or update existing one.")
2940 net_ads_keytab_flush,
2942 N_("Remove all keytab entries"),
2943 N_("net ads keytab flush\n"
2944 " Remove all keytab entries")
2948 net_ads_keytab_list,
2950 N_("List a keytab"),
2951 N_("net ads keytab list\n"
2954 {NULL, NULL, 0, NULL, NULL}
2957 if (!USE_KERBEROS_KEYTAB) {
2958 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2959 "keytab method to use keytab functions.\n"));
2962 return net_run_function(c, argc, argv, "net ads keytab", func);
2965 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2969 if (c->display_usage) {
2971 "net ads kerberos renew\n"
2974 _("Renew TGT from existing credential cache"));
2978 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2980 d_printf(_("failed to renew kerberos ticket: %s\n"),
2981 error_message(ret));
2986 static int net_ads_kerberos_pac_common(struct net_context *c, int argc, const char **argv,
2987 struct PAC_DATA_CTR **pac_data_ctr)
2991 const char *impersonate_princ_s = NULL;
2992 const char *local_service = NULL;
2995 for (i=0; i<argc; i++) {
2996 if (strnequal(argv[i], "impersonate", strlen("impersonate"))) {
2997 impersonate_princ_s = get_string_param(argv[i]);
2998 if (impersonate_princ_s == NULL) {
3002 if (strnequal(argv[i], "local_service", strlen("local_service"))) {
3003 local_service = get_string_param(argv[i]);
3004 if (local_service == NULL) {
3010 if (local_service == NULL) {
3011 local_service = talloc_asprintf(c, "%s$@%s",
3012 lp_netbios_name(), lp_realm());
3013 if (local_service == NULL) {
3018 c->opt_password = net_prompt_pass(c, c->opt_user_name);
3020 status = kerberos_return_pac(c,
3029 2592000, /* one month */
3030 impersonate_princ_s,
3035 if (!NT_STATUS_IS_OK(status)) {
3036 d_printf(_("failed to query kerberos PAC: %s\n"),
3046 static int net_ads_kerberos_pac_dump(struct net_context *c, int argc, const char **argv)
3048 struct PAC_DATA_CTR *pac_data_ctr = NULL;
3051 enum PAC_TYPE type = 0;
3053 if (c->display_usage) {
3055 "net ads kerberos pac dump [impersonate=string] [local_service=string] [pac_buffer_type=int]\n"
3058 _("Dump the Kerberos PAC"));
3062 for (i=0; i<argc; i++) {
3063 if (strnequal(argv[i], "pac_buffer_type", strlen("pac_buffer_type"))) {
3064 type = get_int_param(argv[i]);
3068 ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3077 s = NDR_PRINT_STRUCT_STRING(c, PAC_DATA,
3078 pac_data_ctr->pac_data);
3080 d_printf(_("The Pac: %s\n"), s);
3087 num_buffers = pac_data_ctr->pac_data->num_buffers;
3089 for (i=0; i<num_buffers; i++) {
3093 if (pac_data_ctr->pac_data->buffers[i].type != type) {
3097 s = NDR_PRINT_UNION_STRING(c, PAC_INFO, type,
3098 pac_data_ctr->pac_data->buffers[i].info);
3100 d_printf(_("The Pac: %s\n"), s);
3109 static int net_ads_kerberos_pac_save(struct net_context *c, int argc, const char **argv)
3111 struct PAC_DATA_CTR *pac_data_ctr = NULL;
3112 char *filename = NULL;
3116 if (c->display_usage) {
3118 "net ads kerberos pac save [impersonate=string] [local_service=string] [filename=string]\n"
3121 _("Save the Kerberos PAC"));
3125 for (i=0; i<argc; i++) {
3126 if (strnequal(argv[i], "filename", strlen("filename"))) {
3127 filename = get_string_param(argv[i]);
3128 if (filename == NULL) {
3134 ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3139 if (filename == NULL) {
3140 d_printf(_("please define \"filename=<filename>\" to save the PAC\n"));
3144 /* save the raw format */
3145 if (!file_save(filename, pac_data_ctr->pac_blob.data, pac_data_ctr->pac_blob.length)) {
3146 d_printf(_("failed to save PAC in %s\n"), filename);
3153 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
3155 struct functable func[] = {
3158 net_ads_kerberos_pac_dump,
3160 N_("Dump Kerberos PAC"),
3161 N_("net ads kerberos pac dump\n"
3162 " Dump a Kerberos PAC to stdout")
3166 net_ads_kerberos_pac_save,
3168 N_("Save Kerberos PAC"),
3169 N_("net ads kerberos pac save\n"
3170 " Save a Kerberos PAC in a file")
3173 {NULL, NULL, 0, NULL, NULL}
3176 return net_run_function(c, argc, argv, "net ads kerberos pac", func);
3179 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
3181 TALLOC_CTX *mem_ctx = NULL;
3185 if (c->display_usage) {
3187 "net ads kerberos kinit\n"
3190 _("Get Ticket Granting Ticket (TGT) for the user"));
3194 mem_ctx = talloc_init("net_ads_kerberos_kinit");
3199 c->opt_password = net_prompt_pass(c, c->opt_user_name);
3201 ret = kerberos_kinit_password_ext(c->opt_user_name,
3209 2592000, /* one month */
3215 d_printf(_("failed to kinit password: %s\n"),
3222 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3224 struct functable func[] = {
3227 net_ads_kerberos_kinit,
3229 N_("Retrieve Ticket Granting Ticket (TGT)"),
3230 N_("net ads kerberos kinit\n"
3231 " Receive Ticket Granting Ticket (TGT)")
3235 net_ads_kerberos_renew,
3237 N_("Renew Ticket Granting Ticket from credential cache"),
3238 N_("net ads kerberos renew\n"
3239 " Renew Ticket Granting Ticket (TGT) from "
3244 net_ads_kerberos_pac,
3246 N_("Dump Kerberos PAC"),
3247 N_("net ads kerberos pac\n"
3248 " Dump Kerberos PAC")
3250 {NULL, NULL, 0, NULL, NULL}
3253 return net_run_function(c, argc, argv, "net ads kerberos", func);
3256 static int net_ads_setspn_list(struct net_context *c, int argc, const char **argv)
3260 ADS_STRUCT *ads = NULL;
3261 if (c->display_usage) {
3264 _("net ads setspn list <machinename>\n"));
3268 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3273 ok = ads_setspn_list(ads, argv[0]);
3275 ok = ads_setspn_list(ads, lp_netbios_name());
3287 static int net_ads_setspn_add(struct net_context *c, int argc, const char **argv)
3291 ADS_STRUCT *ads = NULL;
3292 if (c->display_usage || argc < 1) {
3295 _("net ads setspn add <machinename> SPN\n"));
3299 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3304 ok = ads_setspn_add(ads, argv[0], argv[1]);
3306 ok = ads_setspn_add(ads, lp_netbios_name(), argv[0]);
3318 static int net_ads_setspn_delete(struct net_context *c, int argc, const char **argv)
3322 ADS_STRUCT *ads = NULL;
3323 if (c->display_usage || argc < 1) {
3326 _("net ads setspn delete <machinename> SPN\n"));
3330 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3335 ok = ads_setspn_delete(ads, argv[0], argv[1]);
3337 ok = ads_setspn_delete(ads, lp_netbios_name(), argv[0]);
3349 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
3351 struct functable func[] = {
3354 net_ads_setspn_list,
3356 N_("List Service Principal Names (SPN)"),
3357 N_("net ads setspn list machine\n"
3358 " List Service Principal Names (SPN)")
3364 N_("Add Service Principal Names (SPN)"),
3365 N_("net ads setspn add machine spn\n"
3366 " Add Service Principal Names (SPN)")
3370 net_ads_setspn_delete,
3372 N_("Delete Service Principal Names (SPN)"),
3373 N_("net ads setspn delete machine spn\n"
3374 " Delete Service Principal Names (SPN)")
3376 {NULL, NULL, 0, NULL, NULL}
3379 return net_run_function(c, argc, argv, "net ads setspn", func);
3382 static int net_ads_enctype_lookup_account(struct net_context *c,
3384 const char *account,
3386 const char **enctype_str)
3389 const char *attrs[] = {
3390 "msDS-SupportedEncryptionTypes",
3397 filter = talloc_asprintf(c, "(&(objectclass=user)(sAMAccountName=%s))",
3399 if (filter == NULL) {
3403 status = ads_search(ads, res, filter, attrs);
3404 if (!ADS_ERR_OK(status)) {
3405 d_printf(_("no account found with filter: %s\n"), filter);
3409 count = ads_count_replies(ads, *res);
3414 d_printf(_("no account found with filter: %s\n"), filter);
3417 d_printf(_("multiple accounts found with filter: %s\n"), filter);
3422 *enctype_str = ads_pull_string(ads, c, *res,
3423 "msDS-SupportedEncryptionTypes");
3424 if (*enctype_str == NULL) {
3425 d_printf(_("no msDS-SupportedEncryptionTypes attribute found\n"));
3435 static void net_ads_enctype_dump_enctypes(const char *username,
3436 const char *enctype_str)
3438 int enctypes = atoi(enctype_str);
3440 d_printf(_("'%s' uses \"msDS-SupportedEncryptionTypes\": %d (0x%08x)\n"),
3441 username, enctypes, enctypes);
3443 printf("[%s] 0x%08x DES-CBC-CRC\n",
3444 enctypes & ENC_CRC32 ? "X" : " ",
3446 printf("[%s] 0x%08x DES-CBC-MD5\n",
3447 enctypes & ENC_RSA_MD5 ? "X" : " ",
3449 printf("[%s] 0x%08x RC4-HMAC\n",
3450 enctypes & ENC_RC4_HMAC_MD5 ? "X" : " ",
3452 printf("[%s] 0x%08x AES128-CTS-HMAC-SHA1-96\n",
3453 enctypes & ENC_HMAC_SHA1_96_AES128 ? "X" : " ",
3454 ENC_HMAC_SHA1_96_AES128);
3455 printf("[%s] 0x%08x AES256-CTS-HMAC-SHA1-96\n",
3456 enctypes & ENC_HMAC_SHA1_96_AES256 ? "X" : " ",
3457 ENC_HMAC_SHA1_96_AES256);
3460 static int net_ads_enctypes_list(struct net_context *c, int argc, const char **argv)
3464 ADS_STRUCT *ads = NULL;
3465 LDAPMessage *res = NULL;
3466 const char *str = NULL;
3468 if (c->display_usage || (argc < 1)) {
3470 "net ads enctypes list\n"
3473 _("List supported enctypes"));
3477 status = ads_startup(c, false, &ads);
3478 if (!ADS_ERR_OK(status)) {
3479 printf("startup failed\n");
3483 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3488 net_ads_enctype_dump_enctypes(argv[0], str);
3492 ads_msgfree(ads, res);
3498 static int net_ads_enctypes_set(struct net_context *c, int argc, const char **argv)
3503 LDAPMessage *res = NULL;
3504 const char *etype_list_str;
3507 uint32_t etype_list;
3510 if (c->display_usage || argc < 1) {
3512 "net ads enctypes set <sAMAccountName> [enctypes]\n"
3515 _("Set supported enctypes"));
3519 status = ads_startup(c, false, &ads);
3520 if (!ADS_ERR_OK(status)) {
3521 printf("startup failed\n");
3525 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3530 dn = ads_get_dn(ads, c, res);
3535 etype_list = ENC_CRC32 | ENC_RSA_MD5 | ENC_RC4_HMAC_MD5;
3536 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
3537 etype_list |= ENC_HMAC_SHA1_96_AES128;
3539 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
3540 etype_list |= ENC_HMAC_SHA1_96_AES256;
3543 if (argv[1] != NULL) {
3544 sscanf(argv[1], "%i", &etype_list);
3547 etype_list_str = talloc_asprintf(c, "%d", etype_list);
3548 if (!etype_list_str) {
3552 mods = ads_init_mods(c);
3557 status = ads_mod_str(c, &mods, "msDS-SupportedEncryptionTypes",
3559 if (!ADS_ERR_OK(status)) {
3563 status = ads_gen_mod(ads, dn, mods);
3564 if (!ADS_ERR_OK(status)) {
3565 d_printf(_("failed to add msDS-SupportedEncryptionTypes: %s\n"),
3566 ads_errstr(status));
3570 ads_msgfree(ads, res);
3572 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3577 net_ads_enctype_dump_enctypes(argv[0], str);
3581 ads_msgfree(ads, res);
3587 static int net_ads_enctypes_delete(struct net_context *c, int argc, const char **argv)
3592 LDAPMessage *res = NULL;
3596 if (c->display_usage || argc < 1) {
3598 "net ads enctypes delete <sAMAccountName>\n"
3601 _("Delete supported enctypes"));
3605 status = ads_startup(c, false, &ads);
3606 if (!ADS_ERR_OK(status)) {
3607 printf("startup failed\n");
3611 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3616 dn = ads_get_dn(ads, c, res);
3621 mods = ads_init_mods(c);
3626 status = ads_mod_str(c, &mods, "msDS-SupportedEncryptionTypes", NULL);
3627 if (!ADS_ERR_OK(status)) {
3631 status = ads_gen_mod(ads, dn, mods);
3632 if (!ADS_ERR_OK(status)) {
3633 d_printf(_("failed to remove msDS-SupportedEncryptionTypes: %s\n"),
3634 ads_errstr(status));
3641 ads_msgfree(ads, res);
3646 static int net_ads_enctypes(struct net_context *c, int argc, const char **argv)
3648 struct functable func[] = {
3651 net_ads_enctypes_list,
3653 N_("List the supported encryption types"),
3654 N_("net ads enctypes list\n"
3655 " List the supported encryption types")
3659 net_ads_enctypes_set,
3661 N_("Set the supported encryption types"),
3662 N_("net ads enctypes set\n"
3663 " Set the supported encryption types")
3667 net_ads_enctypes_delete,
3669 N_("Delete the supported encryption types"),
3670 N_("net ads enctypes delete\n"
3671 " Delete the supported encryption types")
3674 {NULL, NULL, 0, NULL, NULL}
3677 return net_run_function(c, argc, argv, "net ads enctypes", func);
3681 int net_ads(struct net_context *c, int argc, const char **argv)
3683 struct functable func[] = {
3688 N_("Display details on remote ADS server"),
3690 " Display details on remote ADS server")
3696 N_("Join the local machine to ADS realm"),
3698 " Join the local machine to ADS realm")
3704 N_("Validate machine account"),
3705 N_("net ads testjoin\n"
3706 " Validate machine account")
3712 N_("Remove the local machine from ADS"),
3713 N_("net ads leave\n"
3714 " Remove the local machine from ADS")
3720 N_("Display machine account details"),
3721 N_("net ads status\n"
3722 " Display machine account details")
3728 N_("List/modify users"),
3730 " List/modify users")
3736 N_("List/modify groups"),
3737 N_("net ads group\n"
3738 " List/modify groups")
3744 N_("Issue dynamic DNS update"),
3746 " Issue dynamic DNS update")
3752 N_("Change user passwords"),
3753 N_("net ads password\n"
3754 " Change user passwords")
3758 net_ads_changetrustpw,
3760 N_("Change trust account password"),
3761 N_("net ads changetrustpw\n"
3762 " Change trust account password")
3768 N_("List/modify printer entries"),
3769 N_("net ads printer\n"
3770 " List/modify printer entries")
3776 N_("Issue LDAP search using filter"),
3777 N_("net ads search\n"
3778 " Issue LDAP search using filter")
3784 N_("Issue LDAP search by DN"),
3786 " Issue LDAP search by DN")
3792 N_("Issue LDAP search by SID"),
3794 " Issue LDAP search by SID")
3800 N_("Display workgroup name"),
3801 N_("net ads workgroup\n"
3802 " Display the workgroup name")
3808 N_("Perform CLDAP query on DC"),
3809 N_("net ads lookup\n"
3810 " Find the ADS DC using CLDAP lookups")
3816 N_("Manage local keytab file"),
3817 N_("net ads keytab\n"
3818 " Manage local keytab file")
3824 N_("Manage Service Principal Names (SPN)s"),
3825 N_("net ads spnset\n"
3826 " Manage Service Principal Names (SPN)s")
3832 N_("Manage group policy objects"),
3834 " Manage group policy objects")
3840 N_("Manage kerberos keytab"),
3841 N_("net ads kerberos\n"
3842 " Manage kerberos keytab")
3848 N_("List/modify supported encryption types"),
3849 N_("net ads enctypes\n"
3850 " List/modify enctypes")
3852 {NULL, NULL, 0, NULL, NULL}
3855 return net_run_function(c, argc, argv, "net ads", func);
3860 static int net_ads_noads(void)
3862 d_fprintf(stderr, _("ADS support not compiled in\n"));
3866 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
3868 return net_ads_noads();
3871 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3873 return net_ads_noads();
3876 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
3878 return net_ads_noads();
3881 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
3883 return net_ads_noads();
3886 int net_ads_join(struct net_context *c, int argc, const char **argv)
3888 return net_ads_noads();
3891 int net_ads_user(struct net_context *c, int argc, const char **argv)
3893 return net_ads_noads();
3896 int net_ads_group(struct net_context *c, int argc, const char **argv)
3898 return net_ads_noads();
3901 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
3903 return net_ads_noads();
3906 /* this one shouldn't display a message */
3907 int net_ads_check(struct net_context *c)
3912 int net_ads_check_our_domain(struct net_context *c)
3917 int net_ads(struct net_context *c, int argc, const char **argv)
3919 return net_ads_noads();
3922 #endif /* HAVE_ADS */