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 "rpc_client/cli_pipe.h"
26 #include "librpc/gen_ndr/ndr_krb5pac.h"
27 #include "../librpc/gen_ndr/ndr_spoolss.h"
28 #include "nsswitch/libwbclient/wbclient.h"
30 #include "libads/cldap.h"
31 #include "../lib/addns/dnsquery.h"
32 #include "../libds/common/flags.h"
33 #include "librpc/gen_ndr/libnet_join.h"
34 #include "libnet/libnet_join.h"
38 #include "../libcli/security/security.h"
39 #include "libsmb/libsmb.h"
40 #include "lib/param/loadparm.h"
41 #include "utils/net_dns.h"
45 /* when we do not have sufficient input parameters to contact a remote domain
46 * we always fall back to our own realm - Guenther*/
48 static const char *assume_own_realm(struct net_context *c)
50 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
58 do a cldap netlogon query
60 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
62 char addr[INET6_ADDRSTRLEN];
63 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
65 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
67 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads->ldap.ss, ads->server.realm, &reply ) ) {
68 d_fprintf(stderr, _("CLDAP query failed!\n"));
72 d_printf(_("Information for Domain Controller: %s\n\n"),
75 d_printf(_("Response Type: "));
76 switch (reply.command) {
77 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
78 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
80 case LOGON_SAM_LOGON_RESPONSE_EX:
81 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
84 d_printf("0x%x\n", reply.command);
88 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
92 "\tIs a GC of the forest: %s\n"
93 "\tIs an LDAP server: %s\n"
95 "\tIs running a KDC: %s\n"
96 "\tIs running time services: %s\n"
97 "\tIs the closest DC: %s\n"
99 "\tHas a hardware clock: %s\n"
100 "\tIs a non-domain NC serviced by LDAP server: %s\n"
101 "\tIs NT6 DC that has some secrets: %s\n"
102 "\tIs NT6 DC that has all secrets: %s\n"
103 "\tRuns Active Directory Web Services: %s\n"
104 "\tRuns on Windows 2012 or later: %s\n"),
105 (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
106 (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
107 (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
108 (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
109 (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
110 (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
111 (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
112 (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
113 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
114 (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
115 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
116 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"),
117 (reply.server_type & NBT_SERVER_ADS_WEB_SERVICE) ? _("yes") : _("no"),
118 (reply.server_type & NBT_SERVER_DS_8) ? _("yes") : _("no"));
121 printf(_("Forest:\t\t\t%s\n"), reply.forest);
122 printf(_("Domain:\t\t\t%s\n"), reply.dns_domain);
123 printf(_("Domain Controller:\t%s\n"), reply.pdc_dns_name);
125 printf(_("Pre-Win2k Domain:\t%s\n"), reply.domain_name);
126 printf(_("Pre-Win2k Hostname:\t%s\n"), reply.pdc_name);
128 if (*reply.user_name) printf(_("User name:\t%s\n"), reply.user_name);
130 printf(_("Server Site Name :\t\t%s\n"), reply.server_site);
131 printf(_("Client Site Name :\t\t%s\n"), reply.client_site);
133 d_printf(_("NT Version: %d\n"), reply.nt_version);
134 d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
135 d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
141 this implements the CLDAP based netlogon lookup requests
142 for finding the domain controller of a ADS domain
144 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
149 if (c->display_usage) {
154 _("Find the ADS DC using CLDAP lookup.\n"));
158 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
159 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
164 if (!ads->config.realm) {
165 ads->config.realm = discard_const_p(char, c->opt_target_workgroup);
166 ads->ldap.port = 389;
169 ret = net_ads_cldap_netlogon(c, ads);
176 static int net_ads_info(struct net_context *c, int argc, const char **argv)
179 char addr[INET6_ADDRSTRLEN];
181 if (c->display_usage) {
186 _("Display information about an Active Directory "
191 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
192 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
196 if (!ads || !ads->config.realm) {
197 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
202 /* Try to set the server's current time since we didn't do a full
203 TCP LDAP session initially */
205 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
206 d_fprintf( stderr, _("Failed to get server's current time!\n"));
209 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
211 d_printf(_("LDAP server: %s\n"), addr);
212 d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
213 d_printf(_("Realm: %s\n"), ads->config.realm);
214 d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
215 d_printf(_("LDAP port: %d\n"), ads->ldap.port);
216 d_printf(_("Server time: %s\n"),
217 http_timestring(talloc_tos(), ads->config.current_time));
219 d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
220 d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
226 static void use_in_memory_ccache(void) {
227 /* Use in-memory credentials cache so we do not interfere with
228 * existing credentials */
229 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
232 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
233 uint32 auth_flags, ADS_STRUCT **ads_ret)
235 ADS_STRUCT *ads = NULL;
237 bool need_password = false;
238 bool second_time = false;
240 const char *realm = NULL;
241 bool tried_closest_dc = false;
243 /* lp_realm() should be handled by a command line param,
244 However, the join requires that realm be set in smb.conf
245 and compares our realm with the remote server's so this is
246 ok until someone needs more flexibility */
251 if (only_own_domain) {
254 realm = assume_own_realm(c);
257 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
259 if (!c->opt_user_name) {
260 c->opt_user_name = "administrator";
263 if (c->opt_user_specified) {
264 need_password = true;
268 if (!c->opt_password && need_password && !c->opt_machine_pass) {
269 c->opt_password = net_prompt_pass(c, c->opt_user_name);
270 if (!c->opt_password) {
272 return ADS_ERROR(LDAP_NO_MEMORY);
276 if (c->opt_password) {
277 use_in_memory_ccache();
278 SAFE_FREE(ads->auth.password);
279 ads->auth.password = smb_xstrdup(c->opt_password);
282 ads->auth.flags |= auth_flags;
283 SAFE_FREE(ads->auth.user_name);
284 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
287 * If the username is of the form "name@realm",
288 * extract the realm and convert to upper case.
289 * This is only used to establish the connection.
291 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
293 SAFE_FREE(ads->auth.realm);
294 ads->auth.realm = smb_xstrdup(cp);
295 if (!strupper_m(ads->auth.realm)) {
297 return ADS_ERROR(LDAP_NO_MEMORY);
301 status = ads_connect(ads);
303 if (!ADS_ERR_OK(status)) {
305 if (NT_STATUS_EQUAL(ads_ntstatus(status),
306 NT_STATUS_NO_LOGON_SERVERS)) {
307 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
312 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
313 need_password = true;
322 /* when contacting our own domain, make sure we use the closest DC.
323 * This is done by reconnecting to ADS because only the first call to
324 * ads_connect will give us our own sitename */
326 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
328 tried_closest_dc = true; /* avoid loop */
330 if (!ads_closest_dc(ads)) {
332 namecache_delete(ads->server.realm, 0x1C);
333 namecache_delete(ads->server.workgroup, 0x1C);
346 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
348 return ads_startup_int(c, only_own_domain, 0, ads);
351 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
353 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
357 Check to see if connection can be made via ads.
358 ads_startup() stores the password in opt_password if it needs to so
359 that rpc or rap can use it without re-prompting.
361 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
366 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
370 ads->auth.flags |= ADS_AUTH_NO_BIND;
372 status = ads_connect(ads);
373 if ( !ADS_ERR_OK(status) ) {
381 int net_ads_check_our_domain(struct net_context *c)
383 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
386 int net_ads_check(struct net_context *c)
388 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
392 determine the netbios workgroup name for a domain
394 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
397 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
399 if (c->display_usage) {
401 "net ads workgroup\n"
404 _("Print the workgroup name"));
408 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
409 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
413 if (!ads->config.realm) {
414 ads->config.realm = discard_const_p(char, c->opt_target_workgroup);
415 ads->ldap.port = 389;
418 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads->ldap.ss, ads->server.realm, &reply ) ) {
419 d_fprintf(stderr, _("CLDAP query failed!\n"));
424 d_printf(_("Workgroup: %s\n"), reply.domain_name);
433 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
435 char **disp_fields = (char **) data_area;
437 if (!field) { /* must be end of record */
438 if (disp_fields[0]) {
439 if (!strchr_m(disp_fields[0], '$')) {
441 d_printf("%-21.21s %s\n",
442 disp_fields[0], disp_fields[1]);
444 d_printf("%s\n", disp_fields[0]);
447 SAFE_FREE(disp_fields[0]);
448 SAFE_FREE(disp_fields[1]);
451 if (!values) /* must be new field, indicate string field */
453 if (strcasecmp_m(field, "sAMAccountName") == 0) {
454 disp_fields[0] = SMB_STRDUP((char *) values[0]);
456 if (strcasecmp_m(field, "description") == 0)
457 disp_fields[1] = SMB_STRDUP((char *) values[0]);
461 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
463 return net_user_usage(c, argc, argv);
466 static int ads_user_add(struct net_context *c, int argc, const char **argv)
471 LDAPMessage *res=NULL;
475 if (argc < 1 || c->display_usage)
476 return net_ads_user_usage(c, argc, argv);
478 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
482 status = ads_find_user_acct(ads, &res, argv[0]);
484 if (!ADS_ERR_OK(status)) {
485 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
489 if (ads_count_replies(ads, res)) {
490 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
495 if (c->opt_container) {
496 ou_str = SMB_STRDUP(c->opt_container);
498 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
501 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
503 if (!ADS_ERR_OK(status)) {
504 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
509 /* if no password is to be set, we're done */
511 d_printf(_("User %s added\n"), argv[0]);
516 /* try setting the password */
517 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
520 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
521 ads->auth.time_offset);
523 if (ADS_ERR_OK(status)) {
524 d_printf(_("User %s added\n"), argv[0]);
529 /* password didn't set, delete account */
530 d_fprintf(stderr, _("Could not add user %s. "
531 "Error setting password %s\n"),
532 argv[0], ads_errstr(status));
533 ads_msgfree(ads, res);
534 status=ads_find_user_acct(ads, &res, argv[0]);
535 if (ADS_ERR_OK(status)) {
536 userdn = ads_get_dn(ads, talloc_tos(), res);
537 ads_del_dn(ads, userdn);
543 ads_msgfree(ads, res);
549 static int ads_user_info(struct net_context *c, int argc, const char **argv)
551 ADS_STRUCT *ads = NULL;
553 LDAPMessage *res = NULL;
557 const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
558 char *searchstring=NULL;
562 struct dom_sid primary_group_sid;
564 enum wbcSidType type;
566 if (argc < 1 || c->display_usage) {
567 return net_ads_user_usage(c, argc, argv);
570 frame = talloc_new(talloc_tos());
575 escaped_user = escape_ldap_string(frame, argv[0]);
578 _("ads_user_info: failed to escape user %s\n"),
583 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
588 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
592 rc = ads_search(ads, &res, searchstring, attrs);
593 SAFE_FREE(searchstring);
595 if (!ADS_ERR_OK(rc)) {
596 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(rc));
601 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
602 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
607 rc = ads_domain_sid(ads, &primary_group_sid);
608 if (!ADS_ERR_OK(rc)) {
609 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(rc));
614 sid_append_rid(&primary_group_sid, group_rid);
616 wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
617 NULL, /* don't look up domain */
620 if (!WBC_ERROR_IS_OK(wbc_status)) {
621 d_fprintf(stderr, "wbcLookupSid: %s\n",
622 wbcErrorString(wbc_status));
627 d_printf("%s\n", primary_group);
629 wbcFreeMemory(primary_group);
631 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
632 (LDAPMessage *)res, "memberOf");
637 for (i=0;grouplist[i];i++) {
638 groupname = ldap_explode_dn(grouplist[i], 1);
639 d_printf("%s\n", groupname[0]);
640 ldap_value_free(groupname);
642 ldap_value_free(grouplist);
646 if (res) ads_msgfree(ads, res);
647 if (ads) ads_destroy(&ads);
652 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
656 LDAPMessage *res = NULL;
660 return net_ads_user_usage(c, argc, argv);
663 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
667 rc = ads_find_user_acct(ads, &res, argv[0]);
668 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
669 d_printf(_("User %s does not exist.\n"), argv[0]);
670 ads_msgfree(ads, res);
674 userdn = ads_get_dn(ads, talloc_tos(), res);
675 ads_msgfree(ads, res);
676 rc = ads_del_dn(ads, userdn);
678 if (ADS_ERR_OK(rc)) {
679 d_printf(_("User %s deleted\n"), argv[0]);
683 d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
689 int net_ads_user(struct net_context *c, int argc, const char **argv)
691 struct functable func[] = {
696 N_("Add an AD user"),
697 N_("net ads user add\n"
704 N_("Display information about an AD user"),
705 N_("net ads user info\n"
706 " Display information about an AD user")
712 N_("Delete an AD user"),
713 N_("net ads user delete\n"
714 " Delete an AD user")
716 {NULL, NULL, 0, NULL, NULL}
720 const char *shortattrs[] = {"sAMAccountName", NULL};
721 const char *longattrs[] = {"sAMAccountName", "description", NULL};
722 char *disp_fields[2] = {NULL, NULL};
725 if (c->display_usage) {
731 net_display_usage_from_functable(func);
735 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
739 if (c->opt_long_list_entries)
740 d_printf(_("\nUser name Comment"
741 "\n-----------------------------\n"));
743 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
745 "(objectCategory=user)",
746 c->opt_long_list_entries ? longattrs :
747 shortattrs, usergrp_display,
750 return ADS_ERR_OK(rc) ? 0 : -1;
753 return net_run_function(c, argc, argv, "net ads user", func);
756 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
758 return net_group_usage(c, argc, argv);
761 static int ads_group_add(struct net_context *c, int argc, const char **argv)
765 LDAPMessage *res=NULL;
769 if (argc < 1 || c->display_usage) {
770 return net_ads_group_usage(c, argc, argv);
773 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
777 status = ads_find_user_acct(ads, &res, argv[0]);
779 if (!ADS_ERR_OK(status)) {
780 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
784 if (ads_count_replies(ads, res)) {
785 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
789 if (c->opt_container) {
790 ou_str = SMB_STRDUP(c->opt_container);
792 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
795 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
797 if (ADS_ERR_OK(status)) {
798 d_printf(_("Group %s added\n"), argv[0]);
801 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
807 ads_msgfree(ads, res);
813 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
817 LDAPMessage *res = NULL;
820 if (argc < 1 || c->display_usage) {
821 return net_ads_group_usage(c, argc, argv);
824 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
828 rc = ads_find_user_acct(ads, &res, argv[0]);
829 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
830 d_printf(_("Group %s does not exist.\n"), argv[0]);
831 ads_msgfree(ads, res);
835 groupdn = ads_get_dn(ads, talloc_tos(), res);
836 ads_msgfree(ads, res);
837 rc = ads_del_dn(ads, groupdn);
838 TALLOC_FREE(groupdn);
839 if (ADS_ERR_OK(rc)) {
840 d_printf(_("Group %s deleted\n"), argv[0]);
844 d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
850 int net_ads_group(struct net_context *c, int argc, const char **argv)
852 struct functable func[] = {
857 N_("Add an AD group"),
858 N_("net ads group add\n"
865 N_("Delete an AD group"),
866 N_("net ads group delete\n"
867 " Delete an AD group")
869 {NULL, NULL, 0, NULL, NULL}
873 const char *shortattrs[] = {"sAMAccountName", NULL};
874 const char *longattrs[] = {"sAMAccountName", "description", NULL};
875 char *disp_fields[2] = {NULL, NULL};
878 if (c->display_usage) {
883 _("List AD groups"));
884 net_display_usage_from_functable(func);
888 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
892 if (c->opt_long_list_entries)
893 d_printf(_("\nGroup name Comment"
894 "\n-----------------------------\n"));
895 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
897 "(objectCategory=group)",
898 c->opt_long_list_entries ? longattrs :
899 shortattrs, usergrp_display,
903 return ADS_ERR_OK(rc) ? 0 : -1;
905 return net_run_function(c, argc, argv, "net ads group", func);
908 static int net_ads_status(struct net_context *c, int argc, const char **argv)
914 if (c->display_usage) {
919 _("Display machine account details"));
923 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
927 rc = ads_find_machine_acct(ads, &res, lp_netbios_name());
928 if (!ADS_ERR_OK(rc)) {
929 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
934 if (ads_count_replies(ads, res) == 0) {
935 d_fprintf(stderr, _("No machine account for '%s' found\n"), lp_netbios_name());
945 /*******************************************************************
946 Leave an AD domain. Windows XP disables the machine account.
947 We'll try the same. The old code would do an LDAP delete.
948 That only worked using the machine creds because added the machine
949 with full control to the computer object's ACL.
950 *******************************************************************/
952 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
955 struct libnet_UnjoinCtx *r = NULL;
958 if (c->display_usage) {
963 _("Leave an AD domain"));
968 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
972 if (!(ctx = talloc_init("net_ads_leave"))) {
973 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
977 if (!c->opt_kerberos) {
978 use_in_memory_ccache();
982 d_fprintf(stderr, _("Could not initialise message context. "
983 "Try running as root\n"));
987 werr = libnet_init_UnjoinCtx(ctx, &r);
988 if (!W_ERROR_IS_OK(werr)) {
989 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
994 r->in.use_kerberos = c->opt_kerberos;
995 r->in.dc_name = c->opt_host;
996 r->in.domain_name = lp_realm();
997 r->in.admin_account = c->opt_user_name;
998 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
999 r->in.modify_config = lp_config_backend_is_registry();
1001 /* Try to delete it, but if that fails, disable it. The
1002 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
1003 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1004 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
1005 r->in.delete_machine_account = true;
1006 r->in.msg_ctx = c->msg_ctx;
1008 werr = libnet_Unjoin(ctx, r);
1009 if (!W_ERROR_IS_OK(werr)) {
1010 d_printf(_("Failed to leave domain: %s\n"),
1011 r->out.error_string ? r->out.error_string :
1012 get_friendly_werror_msg(werr));
1016 if (r->out.deleted_machine_account) {
1017 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1018 r->in.machine_name, r->out.dns_domain_name);
1022 /* We couldn't delete it - see if the disable succeeded. */
1023 if (r->out.disabled_machine_account) {
1024 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1025 r->in.machine_name, r->out.dns_domain_name);
1030 /* Based on what we requested, we shouldn't get here, but if
1031 we did, it means the secrets were removed, and therefore
1032 we have left the domain */
1033 d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1034 r->in.machine_name, r->out.dns_domain_name);
1040 if (W_ERROR_IS_OK(werr)) {
1047 static NTSTATUS net_ads_join_ok(struct net_context *c)
1049 ADS_STRUCT *ads = NULL;
1052 struct sockaddr_storage dcip;
1054 if (!secrets_init()) {
1055 DEBUG(1,("Failed to initialise secrets database\n"));
1056 return NT_STATUS_ACCESS_DENIED;
1059 net_use_krb_machine_account(c);
1061 get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1063 status = ads_startup(c, true, &ads);
1064 if (!ADS_ERR_OK(status)) {
1065 return ads_ntstatus(status);
1069 return NT_STATUS_OK;
1073 check that an existing join is OK
1075 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1078 use_in_memory_ccache();
1080 if (c->display_usage) {
1082 "net ads testjoin\n"
1085 _("Test if the existing join is ok"));
1089 /* Display success or failure */
1090 status = net_ads_join_ok(c);
1091 if (!NT_STATUS_IS_OK(status)) {
1092 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1093 get_friendly_nt_error_msg(status));
1097 printf(_("Join is OK\n"));
1101 /*******************************************************************
1102 Simple configu checks before beginning the join
1103 ********************************************************************/
1105 static WERROR check_ads_config( void )
1107 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1108 d_printf(_("Host is not configured as a member server.\n"));
1109 return WERR_INVALID_DOMAIN_ROLE;
1112 if (strlen(lp_netbios_name()) > 15) {
1113 d_printf(_("Our netbios name can be at most 15 chars long, "
1114 "\"%s\" is %u chars long\n"), lp_netbios_name(),
1115 (unsigned int)strlen(lp_netbios_name()));
1116 return WERR_INVALID_COMPUTERNAME;
1119 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1120 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1121 "join to succeed.\n"), get_dyn_CONFIGFILE());
1122 return WERR_INVALID_PARAM;
1128 /*******************************************************************
1129 Send a DNS update request
1130 *******************************************************************/
1132 #if defined(WITH_DNS_UPDATES)
1133 #include "../lib/addns/dns.h"
1135 static NTSTATUS net_update_dns_internal(struct net_context *c,
1136 TALLOC_CTX *ctx, ADS_STRUCT *ads,
1137 const char *machine_name,
1138 const struct sockaddr_storage *addrs,
1141 struct dns_rr_ns *nameservers = NULL;
1142 int ns_count = 0, i;
1143 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1146 const char *dnsdomain = NULL;
1147 char *root_domain = NULL;
1149 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1150 d_printf(_("No DNS domain configured for %s. "
1151 "Unable to perform DNS Update.\n"), machine_name);
1152 status = NT_STATUS_INVALID_PARAMETER;
1157 status = ads_dns_lookup_ns(ctx,
1161 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1162 /* Child domains often do not have NS records. Look
1163 for the NS record for the forest root domain
1164 (rootDomainNamingContext in therootDSE) */
1166 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1167 LDAPMessage *msg = NULL;
1169 ADS_STATUS ads_status;
1171 if ( !ads->ldap.ld ) {
1172 ads_status = ads_connect( ads );
1173 if ( !ADS_ERR_OK(ads_status) ) {
1174 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1179 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1180 "(objectclass=*)", rootname_attrs, &msg);
1181 if (!ADS_ERR_OK(ads_status)) {
1185 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1187 ads_msgfree( ads, msg );
1191 root_domain = ads_build_domain( root_dn );
1194 ads_msgfree( ads, msg );
1196 /* try again for NS servers */
1198 status = ads_dns_lookup_ns(ctx,
1203 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1204 DEBUG(3,("net_update_dns_internal: Failed to find name server for the %s "
1205 "realm\n", ads->config.realm));
1209 dnsdomain = root_domain;
1213 for (i=0; i < ns_count; i++) {
1215 uint32_t flags = DNS_UPDATE_SIGNED |
1216 DNS_UPDATE_UNSIGNED |
1217 DNS_UPDATE_UNSIGNED_SUFFICIENT |
1219 DNS_UPDATE_PROBE_SUFFICIENT;
1222 flags &= ~DNS_UPDATE_PROBE_SUFFICIENT;
1223 flags &= ~DNS_UPDATE_UNSIGNED_SUFFICIENT;
1226 status = NT_STATUS_UNSUCCESSFUL;
1228 /* Now perform the dns update - we'll try non-secure and if we fail,
1229 we'll follow it up with a secure update */
1231 fstrcpy( dns_server, nameservers[i].hostname );
1233 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs, flags);
1234 if (ERR_DNS_IS_OK(dns_err)) {
1235 status = NT_STATUS_OK;
1239 if (ERR_DNS_EQUAL(dns_err, ERROR_DNS_INVALID_NAME_SERVER) ||
1240 ERR_DNS_EQUAL(dns_err, ERROR_DNS_CONNECTION_FAILED) ||
1241 ERR_DNS_EQUAL(dns_err, ERROR_DNS_SOCKET_ERROR)) {
1242 DEBUG(1,("retrying DNS update with next nameserver after receiving %s\n",
1243 dns_errstr(dns_err)));
1247 d_printf(_("DNS Update for %s failed: %s\n"),
1248 machine_name, dns_errstr(dns_err));
1249 status = NT_STATUS_UNSUCCESSFUL;
1255 SAFE_FREE( root_domain );
1260 static NTSTATUS net_update_dns_ext(struct net_context *c,
1261 TALLOC_CTX *mem_ctx, ADS_STRUCT *ads,
1262 const char *hostname,
1263 struct sockaddr_storage *iplist,
1266 struct sockaddr_storage *iplist_alloc = NULL;
1267 fstring machine_name;
1271 fstrcpy(machine_name, hostname);
1273 name_to_fqdn( machine_name, lp_netbios_name() );
1275 if (!strlower_m( machine_name )) {
1276 return NT_STATUS_INVALID_PARAMETER;
1279 if (num_addrs == 0 || iplist == NULL) {
1281 * Get our ip address
1282 * (not the 127.0.0.x address but a real ip address)
1284 num_addrs = get_my_ip_address(&iplist_alloc);
1285 if ( num_addrs <= 0 ) {
1286 DEBUG(4, ("net_update_dns_ext: Failed to find my "
1287 "non-loopback IP addresses!\n"));
1288 return NT_STATUS_INVALID_PARAMETER;
1290 iplist = iplist_alloc;
1293 status = net_update_dns_internal(c, mem_ctx, ads, machine_name,
1296 SAFE_FREE(iplist_alloc);
1300 static NTSTATUS net_update_dns(struct net_context *c, TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, const char *hostname)
1304 status = net_update_dns_ext(c, mem_ctx, ads, hostname, NULL, 0);
1310 /*******************************************************************
1311 ********************************************************************/
1313 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1315 d_printf(_("net ads join [options]\n"
1316 "Valid options:\n"));
1317 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1318 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1319 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1320 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1321 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1322 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1323 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1324 d_printf(_(" machinepass=PASS Set the machine password to a specific value during the join.\n"
1325 " The deault password is random.\n"));
1326 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1327 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1328 " NB: osName and osVer must be specified together for either to take effect.\n"
1329 " Also, the operatingSystemService attribute is also set when along with\n"
1330 " the two other attributes.\n"));
1336 static void _net_ads_join_dns_updates(struct net_context *c, TALLOC_CTX *ctx, struct libnet_JoinCtx *r)
1338 #if defined(WITH_DNS_UPDATES)
1339 ADS_STRUCT *ads_dns = NULL;
1344 * In a clustered environment, don't do dynamic dns updates:
1345 * Registering the set of ip addresses that are assigned to
1346 * the interfaces of the node that performs the join does usually
1347 * not have the desired effect, since the local interfaces do not
1348 * carry the complete set of the cluster's public IP addresses.
1349 * And it can also contain internal addresses that should not
1350 * be visible to the outside at all.
1351 * In order to do dns updates in a clustererd setup, use
1352 * net ads dns register.
1354 if (lp_clustering()) {
1355 d_fprintf(stderr, _("Not doing automatic DNS update in a "
1356 "clustered setup.\n"));
1360 if (!r->out.domain_is_ad) {
1365 * We enter this block with user creds.
1366 * kinit with the machine password to do dns update.
1369 ads_dns = ads_init(lp_realm(), NULL, r->in.dc_name);
1371 if (ads_dns == NULL) {
1372 d_fprintf(stderr, _("DNS update failed: out of memory!\n"));
1376 use_in_memory_ccache();
1378 ret = asprintf(&ads_dns->auth.user_name, "%s$", lp_netbios_name());
1380 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1384 ads_dns->auth.password = secrets_fetch_machine_password(
1385 r->out.netbios_domain_name, NULL, NULL);
1386 if (ads_dns->auth.password == NULL) {
1387 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1391 ads_dns->auth.realm = SMB_STRDUP(r->out.dns_domain_name);
1392 if (ads_dns->auth.realm == NULL) {
1393 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1397 if (!strupper_m(ads_dns->auth.realm)) {
1398 d_fprintf(stderr, _("strupper_m %s failed\n"), ads_dns->auth.realm);
1402 ret = ads_kinit_password(ads_dns);
1405 _("DNS update failed: kinit failed: %s\n"),
1406 error_message(ret));
1410 status = net_update_dns(c, ctx, ads_dns, NULL);
1411 if (!NT_STATUS_IS_OK(status)) {
1412 d_fprintf( stderr, _("DNS update failed: %s\n"),
1417 ads_destroy(&ads_dns);
1424 int net_ads_join(struct net_context *c, int argc, const char **argv)
1426 TALLOC_CTX *ctx = NULL;
1427 struct libnet_JoinCtx *r = NULL;
1428 const char *domain = lp_realm();
1429 WERROR werr = WERR_SETUP_NOT_JOINED;
1430 bool createupn = false;
1431 const char *machineupn = NULL;
1432 const char *machine_password = NULL;
1433 const char *create_in_ou = NULL;
1435 const char *os_name = NULL;
1436 const char *os_version = NULL;
1437 bool modify_config = lp_config_backend_is_registry();
1439 if (c->display_usage)
1440 return net_ads_join_usage(c, argc, argv);
1442 if (!modify_config) {
1444 werr = check_ads_config();
1445 if (!W_ERROR_IS_OK(werr)) {
1446 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1451 if (!(ctx = talloc_init("net_ads_join"))) {
1452 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1457 if (!c->opt_kerberos) {
1458 use_in_memory_ccache();
1461 werr = libnet_init_JoinCtx(ctx, &r);
1462 if (!W_ERROR_IS_OK(werr)) {
1466 /* process additional command line args */
1468 for ( i=0; i<argc; i++ ) {
1469 if ( !strncasecmp_m(argv[i], "createupn", strlen("createupn")) ) {
1471 machineupn = get_string_param(argv[i]);
1473 else if ( !strncasecmp_m(argv[i], "createcomputer", strlen("createcomputer")) ) {
1474 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1475 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1476 werr = WERR_INVALID_PARAM;
1480 else if ( !strncasecmp_m(argv[i], "osName", strlen("osName")) ) {
1481 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1482 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1483 werr = WERR_INVALID_PARAM;
1487 else if ( !strncasecmp_m(argv[i], "osVer", strlen("osVer")) ) {
1488 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1489 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1490 werr = WERR_INVALID_PARAM;
1494 else if ( !strncasecmp_m(argv[i], "machinepass", strlen("machinepass")) ) {
1495 if ( (machine_password = get_string_param(argv[i])) == NULL ) {
1496 d_fprintf(stderr, _("Please supply a valid password to set as trust account password.\n"));
1497 werr = WERR_INVALID_PARAM;
1507 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1508 werr = WERR_INVALID_PARAM;
1513 d_fprintf(stderr, _("Could not initialise message context. "
1514 "Try running as root\n"));
1515 werr = WERR_ACCESS_DENIED;
1519 /* Do the domain join here */
1521 r->in.domain_name = domain;
1522 r->in.create_upn = createupn;
1523 r->in.upn = machineupn;
1524 r->in.account_ou = create_in_ou;
1525 r->in.os_name = os_name;
1526 r->in.os_version = os_version;
1527 r->in.dc_name = c->opt_host;
1528 r->in.admin_account = c->opt_user_name;
1529 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1530 r->in.machine_password = machine_password;
1532 r->in.use_kerberos = c->opt_kerberos;
1533 r->in.modify_config = modify_config;
1534 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1535 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1536 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1537 r->in.msg_ctx = c->msg_ctx;
1539 werr = libnet_Join(ctx, r);
1540 if (W_ERROR_EQUAL(werr, WERR_DCNOTFOUND) &&
1541 strequal(domain, lp_realm())) {
1542 r->in.domain_name = lp_workgroup();
1543 werr = libnet_Join(ctx, r);
1545 if (!W_ERROR_IS_OK(werr)) {
1549 /* Check the short name of the domain */
1551 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1552 d_printf(_("The workgroup in %s does not match the short\n"
1553 "domain name obtained from the server.\n"
1554 "Using the name [%s] from the server.\n"
1555 "You should set \"workgroup = %s\" in %s.\n"),
1556 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1557 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1560 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1562 if (r->out.dns_domain_name) {
1563 d_printf(_("Joined '%s' to dns domain '%s'\n"), r->in.machine_name,
1564 r->out.dns_domain_name);
1566 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1567 r->out.netbios_domain_name);
1571 * We try doing the dns update (if it was compiled in).
1572 * If the dns update fails, we still consider the join
1573 * operation as succeeded if we came this far.
1575 _net_ads_join_dns_updates(c, ctx, r);
1583 /* issue an overall failure message at the end. */
1584 d_printf(_("Failed to join domain: %s\n"),
1585 r && r->out.error_string ? r->out.error_string :
1586 get_friendly_werror_msg(werr));
1592 /*******************************************************************
1593 ********************************************************************/
1595 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1597 #if defined(WITH_DNS_UPDATES)
1602 const char *hostname = NULL;
1603 const char **addrs_list = NULL;
1604 struct sockaddr_storage *addrs = NULL;
1609 talloc_enable_leak_report();
1612 if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
1613 d_fprintf(stderr, _("Refusing DNS updates with automatic "
1614 "detection of addresses in a clustered "
1616 c->display_usage = true;
1619 if (c->display_usage) {
1621 "net ads dns register [hostname [IP [IP...]]]\n"
1624 _("Register hostname with DNS\n"));
1628 if (!(ctx = talloc_init("net_ads_dns"))) {
1629 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1638 num_addrs = argc - 1;
1639 addrs_list = &argv[1];
1640 } else if (lp_clustering()) {
1641 addrs_list = lp_cluster_addresses();
1642 num_addrs = str_list_length(addrs_list);
1645 if (num_addrs > 0) {
1646 addrs = talloc_zero_array(ctx, struct sockaddr_storage, num_addrs);
1647 if (addrs == NULL) {
1648 d_fprintf(stderr, _("Error allocating memory!\n"));
1654 for (count = 0; count < num_addrs; count++) {
1655 if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
1656 d_fprintf(stderr, "%s '%s'.\n",
1657 _("Cannot interpret address"),
1664 status = ads_startup(c, true, &ads);
1665 if ( !ADS_ERR_OK(status) ) {
1666 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1671 ntstatus = net_update_dns_ext(c, ctx, ads, hostname, addrs, num_addrs);
1672 if (!NT_STATUS_IS_OK(ntstatus)) {
1673 d_fprintf( stderr, _("DNS update failed!\n") );
1674 ads_destroy( &ads );
1679 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1687 _("DNS update support not enabled at compile time!\n"));
1692 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1694 #if defined(WITH_DNS_UPDATES)
1698 talloc_enable_leak_report();
1701 if (argc != 2 || c->display_usage) {
1706 _("net ads dns gethostbyname <server> <name>\n"),
1707 _(" Look up hostname from the AD\n"
1708 " server\tName server to use\n"
1709 " name\tName to look up\n"));
1713 err = do_gethostbyname(argv[0], argv[1]);
1715 d_printf(_("do_gethostbyname returned %s (%d)\n"),
1716 dns_errstr(err), ERROR_DNS_V(err));
1721 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1723 struct functable func[] = {
1726 net_ads_dns_register,
1728 N_("Add host dns entry to AD"),
1729 N_("net ads dns register\n"
1730 " Add host dns entry to AD")
1734 net_ads_dns_gethostbyname,
1737 N_("net ads dns gethostbyname\n"
1740 {NULL, NULL, 0, NULL, NULL}
1743 return net_run_function(c, argc, argv, "net ads dns", func);
1746 /*******************************************************************
1747 ********************************************************************/
1749 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1752 "\nnet ads printer search <printer>"
1753 "\n\tsearch for a printer in the directory\n"
1754 "\nnet ads printer info <printer> <server>"
1755 "\n\tlookup info in directory for printer on server"
1756 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1757 "\nnet ads printer publish <printername>"
1758 "\n\tpublish printer in directory"
1759 "\n\t(note: printer name is required)\n"
1760 "\nnet ads printer remove <printername>"
1761 "\n\tremove printer from directory"
1762 "\n\t(note: printer name is required)\n"));
1766 /*******************************************************************
1767 ********************************************************************/
1769 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1773 LDAPMessage *res = NULL;
1775 if (c->display_usage) {
1777 "net ads printer search\n"
1780 _("List printers in the AD"));
1784 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1788 rc = ads_find_printers(ads, &res);
1790 if (!ADS_ERR_OK(rc)) {
1791 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
1792 ads_msgfree(ads, res);
1797 if (ads_count_replies(ads, res) == 0) {
1798 d_fprintf(stderr, _("No results found\n"));
1799 ads_msgfree(ads, res);
1805 ads_msgfree(ads, res);
1810 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1814 const char *servername, *printername;
1815 LDAPMessage *res = NULL;
1817 if (c->display_usage) {
1820 _("net ads printer info [printername [servername]]\n"
1821 " Display printer info from AD\n"
1822 " printername\tPrinter name or wildcard\n"
1823 " servername\tName of the print server\n"));
1827 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1832 printername = argv[0];
1838 servername = argv[1];
1840 servername = lp_netbios_name();
1843 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1845 if (!ADS_ERR_OK(rc)) {
1846 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
1847 servername, ads_errstr(rc));
1848 ads_msgfree(ads, res);
1853 if (ads_count_replies(ads, res) == 0) {
1854 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
1855 ads_msgfree(ads, res);
1861 ads_msgfree(ads, res);
1867 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1871 const char *servername, *printername;
1872 struct cli_state *cli = NULL;
1873 struct rpc_pipe_client *pipe_hnd = NULL;
1874 struct sockaddr_storage server_ss;
1876 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1877 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1878 char *prt_dn, *srv_dn, **srv_cn;
1879 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1880 LDAPMessage *res = NULL;
1882 if (argc < 1 || c->display_usage) {
1885 _("net ads printer publish <printername> [servername]\n"
1886 " Publish printer in AD\n"
1887 " printername\tName of the printer\n"
1888 " servername\tName of the print server\n"));
1889 talloc_destroy(mem_ctx);
1893 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1894 talloc_destroy(mem_ctx);
1898 printername = argv[0];
1901 servername = argv[1];
1903 servername = lp_netbios_name();
1906 /* Get printer data from SPOOLSS */
1908 resolve_name(servername, &server_ss, 0x20, false);
1910 nt_status = cli_full_connection(&cli, lp_netbios_name(), servername,
1913 c->opt_user_name, c->opt_workgroup,
1914 c->opt_password ? c->opt_password : "",
1915 CLI_FULL_CONNECTION_USE_KERBEROS,
1916 SMB_SIGNING_DEFAULT);
1918 if (NT_STATUS_IS_ERR(nt_status)) {
1919 d_fprintf(stderr, _("Unable to open a connection to %s to "
1920 "obtain data for %s\n"),
1921 servername, printername);
1923 talloc_destroy(mem_ctx);
1927 /* Publish on AD server */
1929 ads_find_machine_acct(ads, &res, servername);
1931 if (ads_count_replies(ads, res) == 0) {
1932 d_fprintf(stderr, _("Could not find machine account for server "
1936 talloc_destroy(mem_ctx);
1940 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1941 srv_cn = ldap_explode_dn(srv_dn, 1);
1943 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1944 printername_escaped = escape_rdn_val_string_alloc(printername);
1945 if (!srv_cn_escaped || !printername_escaped) {
1946 SAFE_FREE(srv_cn_escaped);
1947 SAFE_FREE(printername_escaped);
1948 d_fprintf(stderr, _("Internal error, out of memory!"));
1950 talloc_destroy(mem_ctx);
1954 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1955 SAFE_FREE(srv_cn_escaped);
1956 SAFE_FREE(printername_escaped);
1957 d_fprintf(stderr, _("Internal error, out of memory!"));
1959 talloc_destroy(mem_ctx);
1963 SAFE_FREE(srv_cn_escaped);
1964 SAFE_FREE(printername_escaped);
1966 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss, &pipe_hnd);
1967 if (!NT_STATUS_IS_OK(nt_status)) {
1968 d_fprintf(stderr, _("Unable to open a connection to the spoolss pipe on %s\n"),
1972 talloc_destroy(mem_ctx);
1976 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1980 talloc_destroy(mem_ctx);
1984 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1985 if (!ADS_ERR_OK(rc)) {
1986 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1989 talloc_destroy(mem_ctx);
1993 d_printf("published printer\n");
1996 talloc_destroy(mem_ctx);
2001 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
2005 const char *servername;
2007 LDAPMessage *res = NULL;
2009 if (argc < 1 || c->display_usage) {
2012 _("net ads printer remove <printername> [servername]\n"
2013 " Remove a printer from the AD\n"
2014 " printername\tName of the printer\n"
2015 " servername\tName of the print server\n"));
2019 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2024 servername = argv[1];
2026 servername = lp_netbios_name();
2029 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
2031 if (!ADS_ERR_OK(rc)) {
2032 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
2033 ads_msgfree(ads, res);
2038 if (ads_count_replies(ads, res) == 0) {
2039 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
2040 ads_msgfree(ads, res);
2045 prt_dn = ads_get_dn(ads, talloc_tos(), res);
2046 ads_msgfree(ads, res);
2047 rc = ads_del_dn(ads, prt_dn);
2048 TALLOC_FREE(prt_dn);
2050 if (!ADS_ERR_OK(rc)) {
2051 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
2060 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
2062 struct functable func[] = {
2065 net_ads_printer_search,
2067 N_("Search for a printer"),
2068 N_("net ads printer search\n"
2069 " Search for a printer")
2073 net_ads_printer_info,
2075 N_("Display printer information"),
2076 N_("net ads printer info\n"
2077 " Display printer information")
2081 net_ads_printer_publish,
2083 N_("Publish a printer"),
2084 N_("net ads printer publish\n"
2085 " Publish a printer")
2089 net_ads_printer_remove,
2091 N_("Delete a printer"),
2092 N_("net ads printer remove\n"
2093 " Delete a printer")
2095 {NULL, NULL, 0, NULL, NULL}
2098 return net_run_function(c, argc, argv, "net ads printer", func);
2102 static int net_ads_password(struct net_context *c, int argc, const char **argv)
2105 const char *auth_principal = c->opt_user_name;
2106 const char *auth_password = c->opt_password;
2107 const char *realm = NULL;
2108 const char *new_password = NULL;
2111 char pwd[256] = {0};
2114 if (c->display_usage) {
2117 _("net ads password <username>\n"
2118 " Change password for user\n"
2119 " username\tName of user to change password for\n"));
2123 if (c->opt_user_name == NULL || c->opt_password == NULL) {
2124 d_fprintf(stderr, _("You must supply an administrator "
2125 "username/password\n"));
2130 d_fprintf(stderr, _("ERROR: You must say which username to "
2131 "change password for\n"));
2136 if (!strchr_m(user, '@')) {
2137 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
2143 use_in_memory_ccache();
2144 chr = strchr_m(auth_principal, '@');
2151 /* use the realm so we can eventually change passwords for users
2152 in realms other than default */
2153 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
2157 /* we don't actually need a full connect, but it's the easy way to
2158 fill in the KDC's addresss */
2161 if (!ads->config.realm) {
2162 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
2168 new_password = (const char *)argv[1];
2172 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
2175 rc = samba_getpass(prompt, pwd, sizeof(pwd), false, true);
2183 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2184 auth_password, user, new_password, ads->auth.time_offset);
2185 memset(pwd, '\0', sizeof(pwd));
2186 if (!ADS_ERR_OK(ret)) {
2187 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2192 d_printf(_("Password change for %s completed.\n"), user);
2198 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2201 char *host_principal;
2205 if (c->display_usage) {
2207 "net ads changetrustpw\n"
2210 _("Change the machine account's trust password"));
2214 if (!secrets_init()) {
2215 DEBUG(1,("Failed to initialise secrets database\n"));
2219 net_use_krb_machine_account(c);
2221 use_in_memory_ccache();
2223 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2227 fstrcpy(my_name, lp_netbios_name());
2228 if (!strlower_m(my_name)) {
2233 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2237 d_printf(_("Changing password for principal: %s\n"), host_principal);
2239 ret = ads_change_trust_account_password(ads, host_principal);
2241 if (!ADS_ERR_OK(ret)) {
2242 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2244 SAFE_FREE(host_principal);
2248 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2250 if (USE_SYSTEM_KEYTAB) {
2251 d_printf(_("Attempting to update system keytab with new password.\n"));
2252 if (ads_keytab_create_default(ads)) {
2253 d_printf(_("Failed to update system keytab.\n"));
2258 SAFE_FREE(host_principal);
2264 help for net ads search
2266 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2269 "\nnet ads search <expression> <attributes...>\n"
2270 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2271 "The expression is a standard LDAP search expression, and the\n"
2272 "attributes are a list of LDAP fields to show in the results.\n\n"
2273 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2275 net_common_flags_usage(c, argc, argv);
2281 general ADS search function. Useful in diagnosing problems in ADS
2283 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2287 const char *ldap_exp;
2289 LDAPMessage *res = NULL;
2291 if (argc < 1 || c->display_usage) {
2292 return net_ads_search_usage(c, argc, argv);
2295 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2302 rc = ads_do_search_retry(ads, ads->config.bind_path,
2304 ldap_exp, attrs, &res);
2305 if (!ADS_ERR_OK(rc)) {
2306 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2311 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2313 /* dump the results */
2316 ads_msgfree(ads, res);
2324 help for net ads search
2326 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2329 "\nnet ads dn <dn> <attributes...>\n"
2330 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2331 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2332 "to show in the results\n\n"
2333 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2334 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2336 net_common_flags_usage(c, argc, argv);
2342 general ADS search function. Useful in diagnosing problems in ADS
2344 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2350 LDAPMessage *res = NULL;
2352 if (argc < 1 || c->display_usage) {
2353 return net_ads_dn_usage(c, argc, argv);
2356 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2363 rc = ads_do_search_all(ads, dn,
2365 "(objectclass=*)", attrs, &res);
2366 if (!ADS_ERR_OK(rc)) {
2367 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2372 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2374 /* dump the results */
2377 ads_msgfree(ads, res);
2384 help for net ads sid search
2386 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2389 "\nnet ads sid <sid> <attributes...>\n"
2390 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2391 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2392 "to show in the results\n\n"
2393 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2395 net_common_flags_usage(c, argc, argv);
2401 general ADS search function. Useful in diagnosing problems in ADS
2403 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2407 const char *sid_string;
2409 LDAPMessage *res = NULL;
2412 if (argc < 1 || c->display_usage) {
2413 return net_ads_sid_usage(c, argc, argv);
2416 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2420 sid_string = argv[0];
2423 if (!string_to_sid(&sid, sid_string)) {
2424 d_fprintf(stderr, _("could not convert sid\n"));
2429 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2430 if (!ADS_ERR_OK(rc)) {
2431 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2436 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2438 /* dump the results */
2441 ads_msgfree(ads, res);
2447 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2452 if (c->display_usage) {
2454 "net ads keytab flush\n"
2457 _("Delete the whole keytab"));
2461 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2464 ret = ads_keytab_flush(ads);
2469 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2475 if (c->display_usage) {
2478 _("net ads keytab add <principal> [principal ...]\n"
2479 " Add principals to local keytab\n"
2480 " principal\tKerberos principal to add to "
2485 d_printf(_("Processing principals to add...\n"));
2486 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2489 for (i = 0; i < argc; i++) {
2490 ret |= ads_keytab_add_entry(ads, argv[i]);
2496 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2501 if (c->display_usage) {
2503 "net ads keytab create\n"
2506 _("Create new default keytab"));
2510 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2513 ret = ads_keytab_create_default(ads);
2518 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2520 const char *keytab = NULL;
2522 if (c->display_usage) {
2525 _("net ads keytab list [keytab]\n"
2526 " List a local keytab\n"
2527 " keytab\tKeytab to list\n"));
2535 return ads_keytab_list(keytab);
2539 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2541 struct functable func[] = {
2546 N_("Add a service principal"),
2547 N_("net ads keytab add\n"
2548 " Add a service principal")
2552 net_ads_keytab_create,
2554 N_("Create a fresh keytab"),
2555 N_("net ads keytab create\n"
2556 " Create a fresh keytab")
2560 net_ads_keytab_flush,
2562 N_("Remove all keytab entries"),
2563 N_("net ads keytab flush\n"
2564 " Remove all keytab entries")
2568 net_ads_keytab_list,
2570 N_("List a keytab"),
2571 N_("net ads keytab list\n"
2574 {NULL, NULL, 0, NULL, NULL}
2577 if (!USE_KERBEROS_KEYTAB) {
2578 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2579 "keytab method to use keytab functions.\n"));
2582 return net_run_function(c, argc, argv, "net ads keytab", func);
2585 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2589 if (c->display_usage) {
2591 "net ads kerberos renew\n"
2594 _("Renew TGT from existing credential cache"));
2598 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2600 d_printf(_("failed to renew kerberos ticket: %s\n"),
2601 error_message(ret));
2606 static int net_ads_kerberos_pac_common(struct net_context *c, int argc, const char **argv,
2607 struct PAC_DATA_CTR **pac_data_ctr)
2611 const char *impersonate_princ_s = NULL;
2612 const char *local_service = NULL;
2615 for (i=0; i<argc; i++) {
2616 if (strnequal(argv[i], "impersonate", strlen("impersonate"))) {
2617 impersonate_princ_s = get_string_param(argv[i]);
2618 if (impersonate_princ_s == NULL) {
2622 if (strnequal(argv[i], "local_service", strlen("local_service"))) {
2623 local_service = get_string_param(argv[i]);
2624 if (local_service == NULL) {
2630 if (local_service == NULL) {
2631 local_service = talloc_asprintf(c, "%s$@%s",
2632 lp_netbios_name(), lp_realm());
2633 if (local_service == NULL) {
2638 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2640 status = kerberos_return_pac(c,
2649 2592000, /* one month */
2650 impersonate_princ_s,
2653 if (!NT_STATUS_IS_OK(status)) {
2654 d_printf(_("failed to query kerberos PAC: %s\n"),
2664 static int net_ads_kerberos_pac_dump(struct net_context *c, int argc, const char **argv)
2666 struct PAC_DATA_CTR *pac_data_ctr = NULL;
2669 enum PAC_TYPE type = 0;
2671 if (c->display_usage) {
2673 "net ads kerberos pac dump [impersonate=string] [local_service=string] [pac_buffer_type=int]\n"
2676 _("Dump the Kerberos PAC"));
2680 for (i=0; i<argc; i++) {
2681 if (strnequal(argv[i], "pac_buffer_type", strlen("pac_buffer_type"))) {
2682 type = get_int_param(argv[i]);
2686 ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
2695 s = NDR_PRINT_STRUCT_STRING(c, PAC_DATA,
2696 pac_data_ctr->pac_data);
2698 d_printf(_("The Pac: %s\n"), s);
2705 for (i=0; i < pac_data_ctr->pac_data->num_buffers; i++) {
2709 if (pac_data_ctr->pac_data->buffers[i].type != type) {
2713 s = NDR_PRINT_UNION_STRING(c, PAC_INFO, type,
2714 pac_data_ctr->pac_data->buffers[i].info);
2716 d_printf(_("The Pac: %s\n"), s);
2725 static int net_ads_kerberos_pac_save(struct net_context *c, int argc, const char **argv)
2727 struct PAC_DATA_CTR *pac_data_ctr = NULL;
2728 char *filename = NULL;
2732 if (c->display_usage) {
2734 "net ads kerberos pac save [impersonate=string] [local_service=string] [filename=string]\n"
2737 _("Save the Kerberos PAC"));
2741 for (i=0; i<argc; i++) {
2742 if (strnequal(argv[i], "filename", strlen("filename"))) {
2743 filename = get_string_param(argv[i]);
2744 if (filename == NULL) {
2750 ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
2755 if (filename == NULL) {
2756 d_printf(_("please define \"filename=<filename>\" to save the PAC\n"));
2760 /* save the raw format */
2761 if (!file_save(filename, pac_data_ctr->pac_blob.data, pac_data_ctr->pac_blob.length)) {
2762 d_printf(_("failed to save PAC in %s\n"), filename);
2769 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2771 struct functable func[] = {
2774 net_ads_kerberos_pac_dump,
2776 N_("Dump Kerberos PAC"),
2777 N_("net ads kerberos pac dump\n"
2778 " Dump a Kerberos PAC to stdout")
2782 net_ads_kerberos_pac_save,
2784 N_("Save Kerberos PAC"),
2785 N_("net ads kerberos pac save\n"
2786 " Save a Kerberos PAC in a file")
2789 {NULL, NULL, 0, NULL, NULL}
2792 return net_run_function(c, argc, argv, "net ads kerberos pac", func);
2795 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2797 TALLOC_CTX *mem_ctx = NULL;
2801 if (c->display_usage) {
2803 "net ads kerberos kinit\n"
2806 _("Get Ticket Granting Ticket (TGT) for the user"));
2810 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2815 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2817 ret = kerberos_kinit_password_ext(c->opt_user_name,
2825 2592000, /* one month */
2828 d_printf(_("failed to kinit password: %s\n"),
2835 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2837 struct functable func[] = {
2840 net_ads_kerberos_kinit,
2842 N_("Retrieve Ticket Granting Ticket (TGT)"),
2843 N_("net ads kerberos kinit\n"
2844 " Receive Ticket Granting Ticket (TGT)")
2848 net_ads_kerberos_renew,
2850 N_("Renew Ticket Granting Ticket from credential cache"),
2851 N_("net ads kerberos renew\n"
2852 " Renew Ticket Granting Ticket (TGT) from "
2857 net_ads_kerberos_pac,
2859 N_("Dump Kerberos PAC"),
2860 N_("net ads kerberos pac\n"
2861 " Dump Kerberos PAC")
2863 {NULL, NULL, 0, NULL, NULL}
2866 return net_run_function(c, argc, argv, "net ads kerberos", func);
2869 static int net_ads_enctype_lookup_account(struct net_context *c,
2871 const char *account,
2873 const char **enctype_str)
2876 const char *attrs[] = {
2877 "msDS-SupportedEncryptionTypes",
2884 filter = talloc_asprintf(c, "(&(objectclass=user)(sAMAccountName=%s))",
2886 if (filter == NULL) {
2890 status = ads_search(ads, res, filter, attrs);
2891 if (!ADS_ERR_OK(status)) {
2892 d_printf(_("no account found with filter: %s\n"), filter);
2896 count = ads_count_replies(ads, *res);
2901 d_printf(_("no account found with filter: %s\n"), filter);
2904 d_printf(_("multiple accounts found with filter: %s\n"), filter);
2909 *enctype_str = ads_pull_string(ads, c, *res,
2910 "msDS-SupportedEncryptionTypes");
2911 if (*enctype_str == NULL) {
2912 d_printf(_("no msDS-SupportedEncryptionTypes attribute found\n"));
2922 static void net_ads_enctype_dump_enctypes(const char *username,
2923 const char *enctype_str)
2925 int enctypes = atoi(enctype_str);
2927 d_printf(_("'%s' uses \"msDS-SupportedEncryptionTypes\": %d (0x%08x)\n"),
2928 username, enctypes, enctypes);
2930 printf("[%s] 0x%08x DES-CBC-CRC\n",
2931 enctypes & ENC_CRC32 ? "X" : " ",
2933 printf("[%s] 0x%08x DES-CBC-MD5\n",
2934 enctypes & ENC_RSA_MD5 ? "X" : " ",
2936 printf("[%s] 0x%08x RC4-HMAC\n",
2937 enctypes & ENC_RC4_HMAC_MD5 ? "X" : " ",
2939 printf("[%s] 0x%08x AES128-CTS-HMAC-SHA1-96\n",
2940 enctypes & ENC_HMAC_SHA1_96_AES128 ? "X" : " ",
2941 ENC_HMAC_SHA1_96_AES128);
2942 printf("[%s] 0x%08x AES256-CTS-HMAC-SHA1-96\n",
2943 enctypes & ENC_HMAC_SHA1_96_AES256 ? "X" : " ",
2944 ENC_HMAC_SHA1_96_AES256);
2947 static int net_ads_enctypes_list(struct net_context *c, int argc, const char **argv)
2951 ADS_STRUCT *ads = NULL;
2952 LDAPMessage *res = NULL;
2953 const char *str = NULL;
2955 if (c->display_usage || (argc < 1)) {
2957 "net ads enctypes list\n"
2960 _("List supported enctypes"));
2964 status = ads_startup(c, false, &ads);
2965 if (!ADS_ERR_OK(status)) {
2966 printf("startup failed\n");
2970 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
2975 net_ads_enctype_dump_enctypes(argv[0], str);
2979 ads_msgfree(ads, res);
2985 static int net_ads_enctypes_set(struct net_context *c, int argc, const char **argv)
2990 LDAPMessage *res = NULL;
2991 const char *etype_list_str;
2994 uint32_t etype_list;
2997 if (c->display_usage || argc < 1) {
2999 "net ads enctypes set <sAMAccountName> [enctypes]\n"
3002 _("Set supported enctypes"));
3006 status = ads_startup(c, false, &ads);
3007 if (!ADS_ERR_OK(status)) {
3008 printf("startup failed\n");
3012 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3017 dn = ads_get_dn(ads, c, res);
3022 etype_list = ENC_CRC32 | ENC_RSA_MD5 | ENC_RC4_HMAC_MD5;
3023 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
3024 etype_list |= ENC_HMAC_SHA1_96_AES128;
3026 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
3027 etype_list |= ENC_HMAC_SHA1_96_AES256;
3030 if (argv[1] != NULL) {
3031 sscanf(argv[1], "%i", &etype_list);
3034 etype_list_str = talloc_asprintf(c, "%d", etype_list);
3035 if (!etype_list_str) {
3039 mods = ads_init_mods(c);
3044 status = ads_mod_str(c, &mods, "msDS-SupportedEncryptionTypes",
3046 if (!ADS_ERR_OK(status)) {
3050 status = ads_gen_mod(ads, dn, mods);
3051 if (!ADS_ERR_OK(status)) {
3052 d_printf(_("failed to add msDS-SupportedEncryptionTypes: %s\n"),
3053 ads_errstr(status));
3057 ads_msgfree(ads, res);
3059 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3064 net_ads_enctype_dump_enctypes(argv[0], str);
3068 ads_msgfree(ads, res);
3074 static int net_ads_enctypes_delete(struct net_context *c, int argc, const char **argv)
3079 LDAPMessage *res = NULL;
3083 if (c->display_usage || argc < 1) {
3085 "net ads enctypes delete <sAMAccountName>\n"
3088 _("Delete supported enctypes"));
3092 status = ads_startup(c, false, &ads);
3093 if (!ADS_ERR_OK(status)) {
3094 printf("startup failed\n");
3098 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3103 dn = ads_get_dn(ads, c, res);
3108 mods = ads_init_mods(c);
3113 status = ads_mod_str(c, &mods, "msDS-SupportedEncryptionTypes", NULL);
3114 if (!ADS_ERR_OK(status)) {
3118 status = ads_gen_mod(ads, dn, mods);
3119 if (!ADS_ERR_OK(status)) {
3120 d_printf(_("failed to remove msDS-SupportedEncryptionTypes: %s\n"),
3121 ads_errstr(status));
3128 ads_msgfree(ads, res);
3133 static int net_ads_enctypes(struct net_context *c, int argc, const char **argv)
3135 struct functable func[] = {
3138 net_ads_enctypes_list,
3140 N_("List the supported encryption types"),
3141 N_("net ads enctypes list\n"
3142 " List the supported encryption types")
3146 net_ads_enctypes_set,
3148 N_("Set the supported encryption types"),
3149 N_("net ads enctypes set\n"
3150 " Set the supported encryption types")
3154 net_ads_enctypes_delete,
3156 N_("Delete the supported encryption types"),
3157 N_("net ads enctypes delete\n"
3158 " Delete the supported encryption types")
3161 {NULL, NULL, 0, NULL, NULL}
3164 return net_run_function(c, argc, argv, "net ads enctypes", func);
3168 int net_ads(struct net_context *c, int argc, const char **argv)
3170 struct functable func[] = {
3175 N_("Display details on remote ADS server"),
3177 " Display details on remote ADS server")
3183 N_("Join the local machine to ADS realm"),
3185 " Join the local machine to ADS realm")
3191 N_("Validate machine account"),
3192 N_("net ads testjoin\n"
3193 " Validate machine account")
3199 N_("Remove the local machine from ADS"),
3200 N_("net ads leave\n"
3201 " Remove the local machine from ADS")
3207 N_("Display machine account details"),
3208 N_("net ads status\n"
3209 " Display machine account details")
3215 N_("List/modify users"),
3217 " List/modify users")
3223 N_("List/modify groups"),
3224 N_("net ads group\n"
3225 " List/modify groups")
3231 N_("Issue dynamic DNS update"),
3233 " Issue dynamic DNS update")
3239 N_("Change user passwords"),
3240 N_("net ads password\n"
3241 " Change user passwords")
3245 net_ads_changetrustpw,
3247 N_("Change trust account password"),
3248 N_("net ads changetrustpw\n"
3249 " Change trust account password")
3255 N_("List/modify printer entries"),
3256 N_("net ads printer\n"
3257 " List/modify printer entries")
3263 N_("Issue LDAP search using filter"),
3264 N_("net ads search\n"
3265 " Issue LDAP search using filter")
3271 N_("Issue LDAP search by DN"),
3273 " Issue LDAP search by DN")
3279 N_("Issue LDAP search by SID"),
3281 " Issue LDAP search by SID")
3287 N_("Display workgroup name"),
3288 N_("net ads workgroup\n"
3289 " Display the workgroup name")
3295 N_("Perfom CLDAP query on DC"),
3296 N_("net ads lookup\n"
3297 " Find the ADS DC using CLDAP lookups")
3303 N_("Manage local keytab file"),
3304 N_("net ads keytab\n"
3305 " Manage local keytab file")
3311 N_("Manage group policy objects"),
3313 " Manage group policy objects")
3319 N_("Manage kerberos keytab"),
3320 N_("net ads kerberos\n"
3321 " Manage kerberos keytab")
3327 N_("List/modify supported encryption types"),
3328 N_("net ads enctypes\n"
3329 " List/modify enctypes")
3331 {NULL, NULL, 0, NULL, NULL}
3334 return net_run_function(c, argc, argv, "net ads", func);
3339 static int net_ads_noads(void)
3341 d_fprintf(stderr, _("ADS support not compiled in\n"));
3345 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
3347 return net_ads_noads();
3350 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3352 return net_ads_noads();
3355 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
3357 return net_ads_noads();
3360 int net_ads_join(struct net_context *c, int argc, const char **argv)
3362 return net_ads_noads();
3365 int net_ads_user(struct net_context *c, int argc, const char **argv)
3367 return net_ads_noads();
3370 int net_ads_group(struct net_context *c, int argc, const char **argv)
3372 return net_ads_noads();
3375 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
3377 return net_ads_noads();
3380 /* this one shouldn't display a message */
3381 int net_ads_check(struct net_context *c)
3386 int net_ads_check_our_domain(struct net_context *c)
3391 int net_ads(struct net_context *c, int argc, const char **argv)
3393 return net_ads_noads();
3396 #endif /* HAVE_ADS */