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 "librpc/gen_ndr/ndr_krb5pac.h"
26 #include "../librpc/gen_ndr/cli_spoolss.h"
27 #include "nsswitch/libwbclient/wbclient.h"
31 /* when we do not have sufficient input parameters to contact a remote domain
32 * we always fall back to our own realm - Guenther*/
34 static const char *assume_own_realm(struct net_context *c)
36 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
44 do a cldap netlogon query
46 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
48 char addr[INET6_ADDRSTRLEN];
49 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
51 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
52 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
53 d_fprintf(stderr, _("CLDAP query failed!\n"));
57 d_printf(_("Information for Domain Controller: %s\n\n"),
60 d_printf(_("Response Type: "));
61 switch (reply.command) {
62 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
63 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
65 case LOGON_SAM_LOGON_RESPONSE_EX:
66 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
69 d_printf("0x%x\n", reply.command);
73 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
77 "\tIs a GC of the forest: %s\n"
78 "\tIs an LDAP server: %s\n"
80 "\tIs running a KDC: %s\n"
81 "\tIs running time services: %s\n"
82 "\tIs the closest DC: %s\n"
84 "\tHas a hardware clock: %s\n"
85 "\tIs a non-domain NC serviced by LDAP server: %s\n"
86 "\tIs NT6 DC that has some secrets: %s\n"
87 "\tIs NT6 DC that has all secrets: %s\n"),
88 (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
89 (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
90 (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
91 (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
92 (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
93 (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
94 (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
95 (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
96 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
97 (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
98 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
99 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"));
102 printf(_("Forest:\t\t\t%s\n"), reply.forest);
103 printf(_("Domain:\t\t\t%s\n"), reply.dns_domain);
104 printf(_("Domain Controller:\t%s\n"), reply.pdc_dns_name);
106 printf(_("Pre-Win2k Domain:\t%s\n"), reply.domain);
107 printf(_("Pre-Win2k Hostname:\t%s\n"), reply.pdc_name);
109 if (*reply.user_name) printf(_("User name:\t%s\n"), reply.user_name);
111 printf(_("Server Site Name :\t\t%s\n"), reply.server_site);
112 printf(_("Client Site Name :\t\t%s\n"), reply.client_site);
114 d_printf(_("NT Version: %d\n"), reply.nt_version);
115 d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
116 d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
122 this implements the CLDAP based netlogon lookup requests
123 for finding the domain controller of a ADS domain
125 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
130 if (c->display_usage) {
131 d_printf(_("Usage:\n"
133 " Find the ADS DC using CLDAP lookup.\n"));
137 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
138 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
143 if (!ads->config.realm) {
144 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
145 ads->ldap.port = 389;
148 ret = net_ads_cldap_netlogon(c, ads);
155 static int net_ads_info(struct net_context *c, int argc, const char **argv)
158 char addr[INET6_ADDRSTRLEN];
160 if (c->display_usage) {
161 d_printf(_("Usage:\n"
163 " Display information about an Active Directory "
168 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
169 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
173 if (!ads || !ads->config.realm) {
174 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
179 /* Try to set the server's current time since we didn't do a full
180 TCP LDAP session initially */
182 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
183 d_fprintf( stderr, _("Failed to get server's current time!\n"));
186 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
188 d_printf(_("LDAP server: %s\n"), addr);
189 d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
190 d_printf(_("Realm: %s\n"), ads->config.realm);
191 d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
192 d_printf(_("LDAP port: %d\n"), ads->ldap.port);
193 d_printf(_("Server time: %s\n"),
194 http_timestring(talloc_tos(), ads->config.current_time));
196 d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
197 d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
203 static void use_in_memory_ccache(void) {
204 /* Use in-memory credentials cache so we do not interfere with
205 * existing credentials */
206 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
209 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
210 uint32 auth_flags, ADS_STRUCT **ads_ret)
212 ADS_STRUCT *ads = NULL;
214 bool need_password = false;
215 bool second_time = false;
217 const char *realm = NULL;
218 bool tried_closest_dc = false;
220 /* lp_realm() should be handled by a command line param,
221 However, the join requires that realm be set in smb.conf
222 and compares our realm with the remote server's so this is
223 ok until someone needs more flexibility */
228 if (only_own_domain) {
231 realm = assume_own_realm(c);
234 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
236 if (!c->opt_user_name) {
237 c->opt_user_name = "administrator";
240 if (c->opt_user_specified) {
241 need_password = true;
245 if (!c->opt_password && need_password && !c->opt_machine_pass) {
246 c->opt_password = net_prompt_pass(c, c->opt_user_name);
247 if (!c->opt_password) {
249 return ADS_ERROR(LDAP_NO_MEMORY);
253 if (c->opt_password) {
254 use_in_memory_ccache();
255 SAFE_FREE(ads->auth.password);
256 ads->auth.password = smb_xstrdup(c->opt_password);
259 ads->auth.flags |= auth_flags;
260 SAFE_FREE(ads->auth.user_name);
261 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
264 * If the username is of the form "name@realm",
265 * extract the realm and convert to upper case.
266 * This is only used to establish the connection.
268 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
270 SAFE_FREE(ads->auth.realm);
271 ads->auth.realm = smb_xstrdup(cp);
272 strupper_m(ads->auth.realm);
275 status = ads_connect(ads);
277 if (!ADS_ERR_OK(status)) {
279 if (NT_STATUS_EQUAL(ads_ntstatus(status),
280 NT_STATUS_NO_LOGON_SERVERS)) {
281 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
286 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
287 need_password = true;
296 /* when contacting our own domain, make sure we use the closest DC.
297 * This is done by reconnecting to ADS because only the first call to
298 * ads_connect will give us our own sitename */
300 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
302 tried_closest_dc = true; /* avoid loop */
304 if (!ads_closest_dc(ads)) {
306 namecache_delete(ads->server.realm, 0x1C);
307 namecache_delete(ads->server.workgroup, 0x1C);
320 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
322 return ads_startup_int(c, only_own_domain, 0, ads);
325 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
327 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
331 Check to see if connection can be made via ads.
332 ads_startup() stores the password in opt_password if it needs to so
333 that rpc or rap can use it without re-prompting.
335 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
340 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
344 ads->auth.flags |= ADS_AUTH_NO_BIND;
346 status = ads_connect(ads);
347 if ( !ADS_ERR_OK(status) ) {
355 int net_ads_check_our_domain(struct net_context *c)
357 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
360 int net_ads_check(struct net_context *c)
362 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
366 determine the netbios workgroup name for a domain
368 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
371 char addr[INET6_ADDRSTRLEN];
372 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
374 if (c->display_usage) {
375 d_printf(_("Usage:\n"
376 "net ads workgroup\n"
377 " Print the workgroup name\n"));
381 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
382 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
386 if (!ads->config.realm) {
387 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
388 ads->ldap.port = 389;
391 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
392 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
393 d_fprintf(stderr, _("CLDAP query failed!\n"));
398 d_printf(_("Workgroup: %s\n"), reply.domain);
407 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
409 char **disp_fields = (char **) data_area;
411 if (!field) { /* must be end of record */
412 if (disp_fields[0]) {
413 if (!strchr_m(disp_fields[0], '$')) {
415 d_printf("%-21.21s %s\n",
416 disp_fields[0], disp_fields[1]);
418 d_printf("%s\n", disp_fields[0]);
421 SAFE_FREE(disp_fields[0]);
422 SAFE_FREE(disp_fields[1]);
425 if (!values) /* must be new field, indicate string field */
427 if (StrCaseCmp(field, "sAMAccountName") == 0) {
428 disp_fields[0] = SMB_STRDUP((char *) values[0]);
430 if (StrCaseCmp(field, "description") == 0)
431 disp_fields[1] = SMB_STRDUP((char *) values[0]);
435 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
437 return net_user_usage(c, argc, argv);
440 static int ads_user_add(struct net_context *c, int argc, const char **argv)
445 LDAPMessage *res=NULL;
449 if (argc < 1 || c->display_usage)
450 return net_ads_user_usage(c, argc, argv);
452 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
456 status = ads_find_user_acct(ads, &res, argv[0]);
458 if (!ADS_ERR_OK(status)) {
459 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
463 if (ads_count_replies(ads, res)) {
464 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
469 if (c->opt_container) {
470 ou_str = SMB_STRDUP(c->opt_container);
472 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
475 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
477 if (!ADS_ERR_OK(status)) {
478 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
483 /* if no password is to be set, we're done */
485 d_printf(_("User %s added\n"), argv[0]);
490 /* try setting the password */
491 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
494 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
495 ads->auth.time_offset);
497 if (ADS_ERR_OK(status)) {
498 d_printf(_("User %s added\n"), argv[0]);
503 /* password didn't set, delete account */
504 d_fprintf(stderr, _("Could not add user %s. "
505 "Error setting password %s\n"),
506 argv[0], ads_errstr(status));
507 ads_msgfree(ads, res);
508 status=ads_find_user_acct(ads, &res, argv[0]);
509 if (ADS_ERR_OK(status)) {
510 userdn = ads_get_dn(ads, talloc_tos(), res);
511 ads_del_dn(ads, userdn);
517 ads_msgfree(ads, res);
523 static int ads_user_info(struct net_context *c, int argc, const char **argv)
525 ADS_STRUCT *ads = NULL;
527 LDAPMessage *res = NULL;
531 const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
532 char *searchstring=NULL;
536 DOM_SID primary_group_sid;
538 enum SID_NAME_USE type;
540 if (argc < 1 || c->display_usage) {
541 return net_ads_user_usage(c, argc, argv);
544 frame = talloc_new(talloc_tos());
549 escaped_user = escape_ldap_string(frame, argv[0]);
552 _("ads_user_info: failed to escape user %s\n"),
557 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
562 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
566 rc = ads_search(ads, &res, searchstring, attrs);
567 SAFE_FREE(searchstring);
569 if (!ADS_ERR_OK(rc)) {
570 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(rc));
575 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
576 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
581 rc = ads_domain_sid(ads, &primary_group_sid);
582 if (!ADS_ERR_OK(rc)) {
583 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(rc));
588 sid_append_rid(&primary_group_sid, group_rid);
590 wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
591 NULL, /* don't look up domain */
593 (enum wbcSidType *) &type);
594 if (!WBC_ERROR_IS_OK(wbc_status)) {
595 d_fprintf(stderr, "wbcLookupSid: %s\n",
596 wbcErrorString(wbc_status));
601 d_printf("%s\n", primary_group);
603 wbcFreeMemory(primary_group);
605 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
606 (LDAPMessage *)res, "memberOf");
611 for (i=0;grouplist[i];i++) {
612 groupname = ldap_explode_dn(grouplist[i], 1);
613 d_printf("%s\n", groupname[0]);
614 ldap_value_free(groupname);
616 ldap_value_free(grouplist);
620 if (res) ads_msgfree(ads, res);
621 if (ads) ads_destroy(&ads);
626 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
630 LDAPMessage *res = NULL;
634 return net_ads_user_usage(c, argc, argv);
637 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
641 rc = ads_find_user_acct(ads, &res, argv[0]);
642 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
643 d_printf(_("User %s does not exist.\n"), argv[0]);
644 ads_msgfree(ads, res);
648 userdn = ads_get_dn(ads, talloc_tos(), res);
649 ads_msgfree(ads, res);
650 rc = ads_del_dn(ads, userdn);
652 if (ADS_ERR_OK(rc)) {
653 d_printf(_("User %s deleted\n"), argv[0]);
657 d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
663 int net_ads_user(struct net_context *c, int argc, const char **argv)
665 struct functable func[] = {
670 N_("Add an AD user"),
671 N_("net ads user add\n"
678 N_("Display information about an AD user"),
679 N_("net ads user info\n"
680 " Display information about an AD user")
686 N_("Delete an AD user"),
687 N_("net ads user delete\n"
688 " Delete an AD user")
690 {NULL, NULL, 0, NULL, NULL}
694 const char *shortattrs[] = {"sAMAccountName", NULL};
695 const char *longattrs[] = {"sAMAccountName", "description", NULL};
696 char *disp_fields[2] = {NULL, NULL};
699 if (c->display_usage) {
700 d_printf(_("Usage:\n"
702 " List AD users\n"));
703 net_display_usage_from_functable(func);
707 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
711 if (c->opt_long_list_entries)
712 d_printf(_("\nUser name Comment"
713 "\n-----------------------------\n"));
715 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
717 "(objectCategory=user)",
718 c->opt_long_list_entries ? longattrs :
719 shortattrs, usergrp_display,
722 return ADS_ERR_OK(rc) ? 0 : -1;
725 return net_run_function(c, argc, argv, "net ads user", func);
728 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
730 return net_group_usage(c, argc, argv);
733 static int ads_group_add(struct net_context *c, int argc, const char **argv)
737 LDAPMessage *res=NULL;
741 if (argc < 1 || c->display_usage) {
742 return net_ads_group_usage(c, argc, argv);
745 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
749 status = ads_find_user_acct(ads, &res, argv[0]);
751 if (!ADS_ERR_OK(status)) {
752 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
756 if (ads_count_replies(ads, res)) {
757 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
761 if (c->opt_container) {
762 ou_str = SMB_STRDUP(c->opt_container);
764 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
767 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
769 if (ADS_ERR_OK(status)) {
770 d_printf(_("Group %s added\n"), argv[0]);
773 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
779 ads_msgfree(ads, res);
785 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
789 LDAPMessage *res = NULL;
792 if (argc < 1 || c->display_usage) {
793 return net_ads_group_usage(c, argc, argv);
796 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
800 rc = ads_find_user_acct(ads, &res, argv[0]);
801 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
802 d_printf(_("Group %s does not exist.\n"), argv[0]);
803 ads_msgfree(ads, res);
807 groupdn = ads_get_dn(ads, talloc_tos(), res);
808 ads_msgfree(ads, res);
809 rc = ads_del_dn(ads, groupdn);
810 TALLOC_FREE(groupdn);
811 if (ADS_ERR_OK(rc)) {
812 d_printf(_("Group %s deleted\n"), argv[0]);
816 d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
822 int net_ads_group(struct net_context *c, int argc, const char **argv)
824 struct functable func[] = {
829 N_("Add an AD group"),
830 N_("net ads group add\n"
837 N_("Delete an AD group"),
838 N_("net ads group delete\n"
839 " Delete an AD group")
841 {NULL, NULL, 0, NULL, NULL}
845 const char *shortattrs[] = {"sAMAccountName", NULL};
846 const char *longattrs[] = {"sAMAccountName", "description", NULL};
847 char *disp_fields[2] = {NULL, NULL};
850 if (c->display_usage) {
851 d_printf(_("Usage:\n"
853 " List AD groups\n"));
854 net_display_usage_from_functable(func);
858 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
862 if (c->opt_long_list_entries)
863 d_printf(_("\nGroup name Comment"
864 "\n-----------------------------\n"));
865 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
867 "(objectCategory=group)",
868 c->opt_long_list_entries ? longattrs :
869 shortattrs, usergrp_display,
873 return ADS_ERR_OK(rc) ? 0 : -1;
875 return net_run_function(c, argc, argv, "net ads group", func);
878 static int net_ads_status(struct net_context *c, int argc, const char **argv)
884 if (c->display_usage) {
885 d_printf(_("Usage:\n"
887 " Display machine account details\n"));
891 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
895 rc = ads_find_machine_acct(ads, &res, global_myname());
896 if (!ADS_ERR_OK(rc)) {
897 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
902 if (ads_count_replies(ads, res) == 0) {
903 d_fprintf(stderr, _("No machine account for '%s' found\n"), global_myname());
913 /*******************************************************************
914 Leave an AD domain. Windows XP disables the machine account.
915 We'll try the same. The old code would do an LDAP delete.
916 That only worked using the machine creds because added the machine
917 with full control to the computer object's ACL.
918 *******************************************************************/
920 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
923 struct libnet_UnjoinCtx *r = NULL;
926 if (c->display_usage) {
927 d_printf(_("Usage:\n"
929 " Leave an AD domain\n"));
934 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
938 if (!(ctx = talloc_init("net_ads_leave"))) {
939 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
943 if (!c->opt_kerberos) {
944 use_in_memory_ccache();
947 werr = libnet_init_UnjoinCtx(ctx, &r);
948 if (!W_ERROR_IS_OK(werr)) {
949 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
954 r->in.use_kerberos = c->opt_kerberos;
955 r->in.dc_name = c->opt_host;
956 r->in.domain_name = lp_realm();
957 r->in.admin_account = c->opt_user_name;
958 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
959 r->in.modify_config = lp_config_backend_is_registry();
961 /* Try to delete it, but if that fails, disable it. The
962 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
963 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
964 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
965 r->in.delete_machine_account = true;
967 werr = libnet_Unjoin(ctx, r);
968 if (!W_ERROR_IS_OK(werr)) {
969 d_printf(_("Failed to leave domain: %s\n"),
970 r->out.error_string ? r->out.error_string :
971 get_friendly_werror_msg(werr));
975 if (r->out.deleted_machine_account) {
976 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
977 r->in.machine_name, r->out.dns_domain_name);
981 /* We couldn't delete it - see if the disable succeeded. */
982 if (r->out.disabled_machine_account) {
983 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
984 r->in.machine_name, r->out.dns_domain_name);
989 /* Based on what we requseted, we shouldn't get here, but if
990 we did, it means the secrets were removed, and therefore
991 we have left the domain */
992 d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
993 r->in.machine_name, r->out.dns_domain_name);
999 if (W_ERROR_IS_OK(werr)) {
1006 static NTSTATUS net_ads_join_ok(struct net_context *c)
1008 ADS_STRUCT *ads = NULL;
1011 struct sockaddr_storage dcip;
1013 if (!secrets_init()) {
1014 DEBUG(1,("Failed to initialise secrets database\n"));
1015 return NT_STATUS_ACCESS_DENIED;
1018 net_use_krb_machine_account(c);
1020 get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1022 status = ads_startup(c, true, &ads);
1023 if (!ADS_ERR_OK(status)) {
1024 return ads_ntstatus(status);
1028 return NT_STATUS_OK;
1032 check that an existing join is OK
1034 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1037 use_in_memory_ccache();
1039 if (c->display_usage) {
1040 d_printf(_("Usage:\n"
1041 "net ads testjoin\n"
1042 " Test if the existing join is ok\n"));
1046 /* Display success or failure */
1047 status = net_ads_join_ok(c);
1048 if (!NT_STATUS_IS_OK(status)) {
1049 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1050 get_friendly_nt_error_msg(status));
1054 printf(_("Join is OK\n"));
1058 /*******************************************************************
1059 Simple configu checks before beginning the join
1060 ********************************************************************/
1062 static WERROR check_ads_config( void )
1064 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1065 d_printf(_("Host is not configured as a member server.\n"));
1066 return WERR_INVALID_DOMAIN_ROLE;
1069 if (strlen(global_myname()) > 15) {
1070 d_printf(_("Our netbios name can be at most 15 chars long, "
1071 "\"%s\" is %u chars long\n"), global_myname(),
1072 (unsigned int)strlen(global_myname()));
1073 return WERR_INVALID_COMPUTERNAME;
1076 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1077 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1078 "join to succeed.\n"), get_dyn_CONFIGFILE());
1079 return WERR_INVALID_PARAM;
1085 /*******************************************************************
1086 Send a DNS update request
1087 *******************************************************************/
1089 #if defined(WITH_DNS_UPDATES)
1091 DNS_ERROR DoDNSUpdate(char *pszServerName,
1092 const char *pszDomainName, const char *pszHostName,
1093 const struct sockaddr_storage *sslist,
1096 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1097 const char *machine_name,
1098 const struct sockaddr_storage *addrs,
1101 struct dns_rr_ns *nameservers = NULL;
1103 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1106 const char *dnsdomain = NULL;
1107 char *root_domain = NULL;
1109 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1110 d_printf(_("No DNS domain configured for %s. "
1111 "Unable to perform DNS Update.\n"), machine_name);
1112 status = NT_STATUS_INVALID_PARAMETER;
1117 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1118 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1119 /* Child domains often do not have NS records. Look
1120 for the NS record for the forest root domain
1121 (rootDomainNamingContext in therootDSE) */
1123 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1124 LDAPMessage *msg = NULL;
1126 ADS_STATUS ads_status;
1128 if ( !ads->ldap.ld ) {
1129 ads_status = ads_connect( ads );
1130 if ( !ADS_ERR_OK(ads_status) ) {
1131 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1136 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1137 "(objectclass=*)", rootname_attrs, &msg);
1138 if (!ADS_ERR_OK(ads_status)) {
1142 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1144 ads_msgfree( ads, msg );
1148 root_domain = ads_build_domain( root_dn );
1151 ads_msgfree( ads, msg );
1153 /* try again for NS servers */
1155 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1157 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1158 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1159 "realm\n", ads->config.realm));
1163 dnsdomain = root_domain;
1167 /* Now perform the dns update - we'll try non-secure and if we fail,
1168 we'll follow it up with a secure update */
1170 fstrcpy( dns_server, nameservers[0].hostname );
1172 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1173 if (!ERR_DNS_IS_OK(dns_err)) {
1174 status = NT_STATUS_UNSUCCESSFUL;
1179 SAFE_FREE( root_domain );
1184 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1187 struct sockaddr_storage *iplist = NULL;
1188 fstring machine_name;
1191 name_to_fqdn( machine_name, global_myname() );
1192 strlower_m( machine_name );
1194 /* Get our ip address (not the 127.0.0.x address but a real ip
1197 num_addrs = get_my_ip_address( &iplist );
1198 if ( num_addrs <= 0 ) {
1199 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1201 return NT_STATUS_INVALID_PARAMETER;
1204 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1206 SAFE_FREE( iplist );
1212 /*******************************************************************
1213 ********************************************************************/
1215 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1217 d_printf(_("net ads join [options]\n"
1218 "Valid options:\n"));
1219 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1220 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1221 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1222 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1223 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1224 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1225 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1226 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1227 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1228 " NB: osName and osVer must be specified together for either to take effect.\n"
1229 " Also, the operatingSystemService attribute is also set when along with\n"
1230 " the two other attributes.\n"));
1235 /*******************************************************************
1236 ********************************************************************/
1238 int net_ads_join(struct net_context *c, int argc, const char **argv)
1240 TALLOC_CTX *ctx = NULL;
1241 struct libnet_JoinCtx *r = NULL;
1242 const char *domain = lp_realm();
1243 WERROR werr = WERR_SETUP_NOT_JOINED;
1244 bool createupn = false;
1245 const char *machineupn = NULL;
1246 const char *create_in_ou = NULL;
1248 const char *os_name = NULL;
1249 const char *os_version = NULL;
1250 bool modify_config = lp_config_backend_is_registry();
1252 if (c->display_usage)
1253 return net_ads_join_usage(c, argc, argv);
1255 if (!modify_config) {
1257 werr = check_ads_config();
1258 if (!W_ERROR_IS_OK(werr)) {
1259 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1264 if (!(ctx = talloc_init("net_ads_join"))) {
1265 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1270 if (!c->opt_kerberos) {
1271 use_in_memory_ccache();
1274 werr = libnet_init_JoinCtx(ctx, &r);
1275 if (!W_ERROR_IS_OK(werr)) {
1279 /* process additional command line args */
1281 for ( i=0; i<argc; i++ ) {
1282 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1284 machineupn = get_string_param(argv[i]);
1286 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1287 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1288 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1289 werr = WERR_INVALID_PARAM;
1293 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1294 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1295 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1296 werr = WERR_INVALID_PARAM;
1300 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1301 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1302 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1303 werr = WERR_INVALID_PARAM;
1313 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1314 werr = WERR_INVALID_PARAM;
1318 /* Do the domain join here */
1320 r->in.domain_name = domain;
1321 r->in.create_upn = createupn;
1322 r->in.upn = machineupn;
1323 r->in.account_ou = create_in_ou;
1324 r->in.os_name = os_name;
1325 r->in.os_version = os_version;
1326 r->in.dc_name = c->opt_host;
1327 r->in.admin_account = c->opt_user_name;
1328 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1330 r->in.use_kerberos = c->opt_kerberos;
1331 r->in.modify_config = modify_config;
1332 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1333 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1334 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1336 werr = libnet_Join(ctx, r);
1337 if (!W_ERROR_IS_OK(werr)) {
1341 /* Check the short name of the domain */
1343 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1344 d_printf(_("The workgroup in %s does not match the short\n"
1345 "domain name obtained from the server.\n"
1346 "Using the name [%s] from the server.\n"
1347 "You should set \"workgroup = %s\" in %s.\n"),
1348 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1349 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1352 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1354 if (r->out.dns_domain_name) {
1355 d_printf(_("Joined '%s' to realm '%s'\n"), r->in.machine_name,
1356 r->out.dns_domain_name);
1358 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1359 r->out.netbios_domain_name);
1362 #if defined(WITH_DNS_UPDATES)
1363 if (r->out.domain_is_ad) {
1364 /* We enter this block with user creds */
1365 ADS_STRUCT *ads_dns = NULL;
1367 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1368 /* kinit with the machine password */
1370 use_in_memory_ccache();
1371 if (asprintf( &ads_dns->auth.user_name, "%s$", global_myname()) == -1) {
1374 ads_dns->auth.password = secrets_fetch_machine_password(
1375 r->out.netbios_domain_name, NULL, NULL );
1376 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1377 strupper_m(ads_dns->auth.realm );
1378 ads_kinit_password( ads_dns );
1381 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1382 d_fprintf( stderr, _("DNS update failed!\n") );
1385 /* exit from this block using machine creds */
1386 ads_destroy(&ads_dns);
1395 /* issue an overall failure message at the end. */
1396 d_printf(_("Failed to join domain: %s\n"),
1397 r && r->out.error_string ? r->out.error_string :
1398 get_friendly_werror_msg(werr));
1404 /*******************************************************************
1405 ********************************************************************/
1407 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1409 #if defined(WITH_DNS_UPDATES)
1415 talloc_enable_leak_report();
1418 if (argc > 0 || c->display_usage) {
1419 d_printf(_("Usage:\n"
1420 "net ads dns register\n"
1421 " Register hostname with DNS\n"));
1425 if (!(ctx = talloc_init("net_ads_dns"))) {
1426 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1430 status = ads_startup(c, true, &ads);
1431 if ( !ADS_ERR_OK(status) ) {
1432 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1437 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1438 d_fprintf( stderr, _("DNS update failed!\n") );
1439 ads_destroy( &ads );
1444 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1452 _("DNS update support not enabled at compile time!\n"));
1457 #if defined(WITH_DNS_UPDATES)
1458 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1461 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1463 #if defined(WITH_DNS_UPDATES)
1467 talloc_enable_leak_report();
1470 if (argc != 2 || c->display_usage) {
1471 d_printf(_("Usage:\n"
1472 "net ads dns gethostbyname <server> <name>\n"
1473 " Look up hostname from the AD\n"
1474 " server\tName server to use\n"
1475 " name\tName to look up\n"));
1479 err = do_gethostbyname(argv[0], argv[1]);
1481 d_printf(_("do_gethostbyname returned %d\n"), ERROR_DNS_V(err));
1486 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1488 struct functable func[] = {
1491 net_ads_dns_register,
1493 N_("Add host dns entry to AD"),
1494 N_("net ads dns register\n"
1495 " Add host dns entry to AD")
1499 net_ads_dns_gethostbyname,
1502 N_("net ads dns gethostbyname\n"
1505 {NULL, NULL, 0, NULL, NULL}
1508 return net_run_function(c, argc, argv, "net ads dns", func);
1511 /*******************************************************************
1512 ********************************************************************/
1514 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1517 "\nnet ads printer search <printer>"
1518 "\n\tsearch for a printer in the directory\n"
1519 "\nnet ads printer info <printer> <server>"
1520 "\n\tlookup info in directory for printer on server"
1521 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1522 "\nnet ads printer publish <printername>"
1523 "\n\tpublish printer in directory"
1524 "\n\t(note: printer name is required)\n"
1525 "\nnet ads printer remove <printername>"
1526 "\n\tremove printer from directory"
1527 "\n\t(note: printer name is required)\n"));
1531 /*******************************************************************
1532 ********************************************************************/
1534 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1538 LDAPMessage *res = NULL;
1540 if (c->display_usage) {
1541 d_printf(_("Usage:\n"
1542 "net ads printer search\n"
1543 " List printers in the AD\n"));
1547 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1551 rc = ads_find_printers(ads, &res);
1553 if (!ADS_ERR_OK(rc)) {
1554 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
1555 ads_msgfree(ads, res);
1560 if (ads_count_replies(ads, res) == 0) {
1561 d_fprintf(stderr, _("No results found\n"));
1562 ads_msgfree(ads, res);
1568 ads_msgfree(ads, res);
1573 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1577 const char *servername, *printername;
1578 LDAPMessage *res = NULL;
1580 if (c->display_usage) {
1581 d_printf(_("Usage:\n"
1582 "net ads printer info [printername [servername]]\n"
1583 " Display printer info from AD\n"
1584 " printername\tPrinter name or wildcard\n"
1585 " servername\tName of the print server\n"));
1589 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1594 printername = argv[0];
1600 servername = argv[1];
1602 servername = global_myname();
1605 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1607 if (!ADS_ERR_OK(rc)) {
1608 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
1609 servername, ads_errstr(rc));
1610 ads_msgfree(ads, res);
1615 if (ads_count_replies(ads, res) == 0) {
1616 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
1617 ads_msgfree(ads, res);
1623 ads_msgfree(ads, res);
1629 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1633 const char *servername, *printername;
1634 struct cli_state *cli = NULL;
1635 struct rpc_pipe_client *pipe_hnd = NULL;
1636 struct sockaddr_storage server_ss;
1638 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1639 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1640 char *prt_dn, *srv_dn, **srv_cn;
1641 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1642 LDAPMessage *res = NULL;
1644 if (argc < 1 || c->display_usage) {
1645 d_printf(_("Usage:\n"
1646 "net ads printer publish <printername> [servername]\n"
1647 " Publish printer in AD\n"
1648 " printername\tName of the printer\n"
1649 " servername\tName of the print server\n"));
1650 talloc_destroy(mem_ctx);
1654 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1655 talloc_destroy(mem_ctx);
1659 printername = argv[0];
1662 servername = argv[1];
1664 servername = global_myname();
1667 /* Get printer data from SPOOLSS */
1669 resolve_name(servername, &server_ss, 0x20, false);
1671 nt_status = cli_full_connection(&cli, global_myname(), servername,
1674 c->opt_user_name, c->opt_workgroup,
1675 c->opt_password ? c->opt_password : "",
1676 CLI_FULL_CONNECTION_USE_KERBEROS,
1679 if (NT_STATUS_IS_ERR(nt_status)) {
1680 d_fprintf(stderr, _("Unable to open a connnection to %s to "
1681 "obtain data for %s\n"),
1682 servername, printername);
1684 talloc_destroy(mem_ctx);
1688 /* Publish on AD server */
1690 ads_find_machine_acct(ads, &res, servername);
1692 if (ads_count_replies(ads, res) == 0) {
1693 d_fprintf(stderr, _("Could not find machine account for server "
1697 talloc_destroy(mem_ctx);
1701 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1702 srv_cn = ldap_explode_dn(srv_dn, 1);
1704 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1705 printername_escaped = escape_rdn_val_string_alloc(printername);
1706 if (!srv_cn_escaped || !printername_escaped) {
1707 SAFE_FREE(srv_cn_escaped);
1708 SAFE_FREE(printername_escaped);
1709 d_fprintf(stderr, _("Internal error, out of memory!"));
1711 talloc_destroy(mem_ctx);
1715 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1716 SAFE_FREE(srv_cn_escaped);
1717 SAFE_FREE(printername_escaped);
1718 d_fprintf(stderr, _("Internal error, out of memory!"));
1720 talloc_destroy(mem_ctx);
1724 SAFE_FREE(srv_cn_escaped);
1725 SAFE_FREE(printername_escaped);
1727 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
1728 if (!NT_STATUS_IS_OK(nt_status)) {
1729 d_fprintf(stderr, _("Unable to open a connnection to the spoolss pipe on %s\n"),
1733 talloc_destroy(mem_ctx);
1737 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1741 talloc_destroy(mem_ctx);
1745 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1746 if (!ADS_ERR_OK(rc)) {
1747 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1750 talloc_destroy(mem_ctx);
1754 d_printf("published printer\n");
1757 talloc_destroy(mem_ctx);
1762 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1766 const char *servername;
1768 LDAPMessage *res = NULL;
1770 if (argc < 1 || c->display_usage) {
1771 d_printf(_("Usage:\n"
1772 "net ads printer remove <printername> [servername]\n"
1773 " Remove a printer from the AD\n"
1774 " printername\tName of the printer\n"
1775 " servername\tName of the print server\n"));
1779 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1784 servername = argv[1];
1786 servername = global_myname();
1789 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1791 if (!ADS_ERR_OK(rc)) {
1792 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
1793 ads_msgfree(ads, res);
1798 if (ads_count_replies(ads, res) == 0) {
1799 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
1800 ads_msgfree(ads, res);
1805 prt_dn = ads_get_dn(ads, talloc_tos(), res);
1806 ads_msgfree(ads, res);
1807 rc = ads_del_dn(ads, prt_dn);
1808 TALLOC_FREE(prt_dn);
1810 if (!ADS_ERR_OK(rc)) {
1811 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
1820 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1822 struct functable func[] = {
1825 net_ads_printer_search,
1827 N_("Search for a printer"),
1828 N_("net ads printer search\n"
1829 " Search for a printer")
1833 net_ads_printer_info,
1835 N_("Display printer information"),
1836 N_("net ads printer info\n"
1837 " Display printer information")
1841 net_ads_printer_publish,
1843 N_("Publish a printer"),
1844 N_("net ads printer publish\n"
1845 " Publish a printer")
1849 net_ads_printer_remove,
1851 N_("Delete a printer"),
1852 N_("net ads printer remove\n"
1853 " Delete a printer")
1855 {NULL, NULL, 0, NULL, NULL}
1858 return net_run_function(c, argc, argv, "net ads printer", func);
1862 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1865 const char *auth_principal = c->opt_user_name;
1866 const char *auth_password = c->opt_password;
1868 char *new_password = NULL;
1873 if (c->display_usage) {
1874 d_printf(_("Usage:\n"
1875 "net ads password <username>\n"
1876 " Change password for user\n"
1877 " username\tName of user to change password for\n"));
1881 if (c->opt_user_name == NULL || c->opt_password == NULL) {
1882 d_fprintf(stderr, _("You must supply an administrator "
1883 "username/password\n"));
1888 d_fprintf(stderr, _("ERROR: You must say which username to "
1889 "change password for\n"));
1894 if (!strchr_m(user, '@')) {
1895 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
1901 use_in_memory_ccache();
1902 chr = strchr_m(auth_principal, '@');
1909 /* use the realm so we can eventually change passwords for users
1910 in realms other than default */
1911 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1915 /* we don't actually need a full connect, but it's the easy way to
1916 fill in the KDC's addresss */
1919 if (!ads->config.realm) {
1920 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
1926 new_password = (char *)argv[1];
1928 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
1931 new_password = getpass(prompt);
1935 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1936 auth_password, user, new_password, ads->auth.time_offset);
1937 if (!ADS_ERR_OK(ret)) {
1938 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
1943 d_printf(_("Password change for %s completed.\n"), user);
1949 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1952 char *host_principal;
1956 if (c->display_usage) {
1957 d_printf(_("Usage:\n"
1958 "net ads changetrustpw\n"
1959 " Change the machine account's trust password\n"));
1963 if (!secrets_init()) {
1964 DEBUG(1,("Failed to initialise secrets database\n"));
1968 net_use_krb_machine_account(c);
1970 use_in_memory_ccache();
1972 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1976 fstrcpy(my_name, global_myname());
1977 strlower_m(my_name);
1978 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
1982 d_printf(_("Changing password for principal: %s\n"), host_principal);
1984 ret = ads_change_trust_account_password(ads, host_principal);
1986 if (!ADS_ERR_OK(ret)) {
1987 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
1989 SAFE_FREE(host_principal);
1993 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
1995 if (USE_SYSTEM_KEYTAB) {
1996 d_printf(_("Attempting to update system keytab with new password.\n"));
1997 if (ads_keytab_create_default(ads)) {
1998 d_printf(_("Failed to update system keytab.\n"));
2003 SAFE_FREE(host_principal);
2009 help for net ads search
2011 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2014 "\nnet ads search <expression> <attributes...>\n"
2015 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2016 "The expression is a standard LDAP search expression, and the\n"
2017 "attributes are a list of LDAP fields to show in the results.\n\n"
2018 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2020 net_common_flags_usage(c, argc, argv);
2026 general ADS search function. Useful in diagnosing problems in ADS
2028 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2032 const char *ldap_exp;
2034 LDAPMessage *res = NULL;
2036 if (argc < 1 || c->display_usage) {
2037 return net_ads_search_usage(c, argc, argv);
2040 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2047 rc = ads_do_search_all(ads, ads->config.bind_path,
2049 ldap_exp, attrs, &res);
2050 if (!ADS_ERR_OK(rc)) {
2051 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2056 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2058 /* dump the results */
2061 ads_msgfree(ads, res);
2069 help for net ads search
2071 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2074 "\nnet ads dn <dn> <attributes...>\n"
2075 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2076 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2077 "to show in the results\n\n"
2078 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2079 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2081 net_common_flags_usage(c, argc, argv);
2087 general ADS search function. Useful in diagnosing problems in ADS
2089 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2095 LDAPMessage *res = NULL;
2097 if (argc < 1 || c->display_usage) {
2098 return net_ads_dn_usage(c, argc, argv);
2101 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2108 rc = ads_do_search_all(ads, dn,
2110 "(objectclass=*)", attrs, &res);
2111 if (!ADS_ERR_OK(rc)) {
2112 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2117 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2119 /* dump the results */
2122 ads_msgfree(ads, res);
2129 help for net ads sid search
2131 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2134 "\nnet ads sid <sid> <attributes...>\n"
2135 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2136 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2137 "to show in the results\n\n"
2138 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2140 net_common_flags_usage(c, argc, argv);
2146 general ADS search function. Useful in diagnosing problems in ADS
2148 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2152 const char *sid_string;
2154 LDAPMessage *res = NULL;
2157 if (argc < 1 || c->display_usage) {
2158 return net_ads_sid_usage(c, argc, argv);
2161 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2165 sid_string = argv[0];
2168 if (!string_to_sid(&sid, sid_string)) {
2169 d_fprintf(stderr, _("could not convert sid\n"));
2174 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2175 if (!ADS_ERR_OK(rc)) {
2176 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2181 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2183 /* dump the results */
2186 ads_msgfree(ads, res);
2192 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2197 if (c->display_usage) {
2198 d_printf(_("Usage:\n"
2199 "net ads keytab flush\n"
2200 " Delete the whole keytab\n"));
2204 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2207 ret = ads_keytab_flush(ads);
2212 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2218 if (c->display_usage) {
2219 d_printf(_("Usage:\n"
2220 "net ads keytab add <principal> [principal ...]\n"
2221 " Add principals to local keytab\n"
2222 " principal\tKerberos principal to add to "
2227 d_printf(_("Processing principals to add...\n"));
2228 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2231 for (i = 0; i < argc; i++) {
2232 ret |= ads_keytab_add_entry(ads, argv[i]);
2238 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2243 if (c->display_usage) {
2244 d_printf(_("Usage:\n"
2245 "net ads keytab create\n"
2246 " Create new default keytab\n"));
2250 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2253 ret = ads_keytab_create_default(ads);
2258 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2260 const char *keytab = NULL;
2262 if (c->display_usage) {
2263 d_printf(_("Usage:\n"
2264 "net ads keytab list [keytab]\n"
2265 " List a local keytab\n"
2266 " keytab\tKeytab to list\n"));
2274 return ads_keytab_list(keytab);
2278 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2280 struct functable func[] = {
2285 N_("Add a service principal"),
2286 N_("net ads keytab add\n"
2287 " Add a service principal")
2291 net_ads_keytab_create,
2293 N_("Create a fresh keytab"),
2294 N_("net ads keytab create\n"
2295 " Create a fresh keytab")
2299 net_ads_keytab_flush,
2301 N_("Remove all keytab entries"),
2302 N_("net ads keytab flush\n"
2303 " Remove all keytab entries")
2307 net_ads_keytab_list,
2309 N_("List a keytab"),
2310 N_("net ads keytab list\n"
2313 {NULL, NULL, 0, NULL, NULL}
2316 if (!USE_KERBEROS_KEYTAB) {
2317 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2318 "keytab method to use keytab functions.\n"));
2321 return net_run_function(c, argc, argv, "net ads keytab", func);
2324 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2328 if (c->display_usage) {
2329 d_printf(_("Usage:\n"
2330 "net ads kerberos renew\n"
2331 " Renew TGT from existing credential cache\n"));
2335 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2337 d_printf(_("failed to renew kerberos ticket: %s\n"),
2338 error_message(ret));
2343 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2345 struct PAC_DATA *pac = NULL;
2346 struct PAC_LOGON_INFO *info = NULL;
2347 TALLOC_CTX *mem_ctx = NULL;
2350 const char *impersonate_princ_s = NULL;
2352 if (c->display_usage) {
2353 d_printf(_("Usage:\n"
2354 "net ads kerberos pac\n"
2355 " Dump the Kerberos PAC\n"));
2359 mem_ctx = talloc_init("net_ads_kerberos_pac");
2365 impersonate_princ_s = argv[0];
2368 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2370 status = kerberos_return_pac(mem_ctx,
2379 2592000, /* one month */
2380 impersonate_princ_s,
2382 if (!NT_STATUS_IS_OK(status)) {
2383 d_printf(_("failed to query kerberos PAC: %s\n"),
2388 info = get_logon_info_from_pac(pac);
2391 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2392 d_printf(_("The Pac: %s\n"), s);
2397 TALLOC_FREE(mem_ctx);
2401 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2403 TALLOC_CTX *mem_ctx = NULL;
2407 if (c->display_usage) {
2408 d_printf(_("Usage:\n"
2409 "net ads kerberos kinit\n"
2410 " Get Ticket Granting Ticket (TGT) for the user\n"));
2414 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2419 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2421 ret = kerberos_kinit_password_ext(c->opt_user_name,
2429 2592000, /* one month */
2432 d_printf(_("failed to kinit password: %s\n"),
2439 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2441 struct functable func[] = {
2444 net_ads_kerberos_kinit,
2446 N_("Retrieve Ticket Granting Ticket (TGT)"),
2447 N_("net ads kerberos kinit\n"
2448 " Receive Ticket Granting Ticket (TGT)")
2452 net_ads_kerberos_renew,
2454 N_("Renew Ticket Granting Ticket from credential cache"),
2455 N_("net ads kerberos renew\n"
2456 " Renew Ticket Granting Ticket (TGT) from "
2461 net_ads_kerberos_pac,
2463 N_("Dump Kerberos PAC"),
2464 N_("net ads kerberos pac\n"
2465 " Dump Kerberos PAC")
2467 {NULL, NULL, 0, NULL, NULL}
2470 return net_run_function(c, argc, argv, "net ads kerberos", func);
2473 int net_ads(struct net_context *c, int argc, const char **argv)
2475 struct functable func[] = {
2480 N_("Display details on remote ADS server"),
2482 " Display details on remote ADS server")
2488 N_("Join the local machine to ADS realm"),
2490 " Join the local machine to ADS realm")
2496 N_("Validate machine account"),
2497 N_("net ads testjoin\n"
2498 " Validate machine account")
2504 N_("Remove the local machine from ADS"),
2505 N_("net ads leave\n"
2506 " Remove the local machine from ADS")
2512 N_("Display machine account details"),
2513 N_("net ads status\n"
2514 " Display machine account details")
2520 N_("List/modify users"),
2522 " List/modify users")
2528 N_("List/modify groups"),
2529 N_("net ads group\n"
2530 " List/modify groups")
2536 N_("Issue dynamic DNS update"),
2538 " Issue dynamic DNS update")
2544 N_("Change user passwords"),
2545 N_("net ads password\n"
2546 " Change user passwords")
2550 net_ads_changetrustpw,
2552 N_("Change trust account password"),
2553 N_("net ads changetrustpw\n"
2554 " Change trust account password")
2560 N_("List/modify printer entries"),
2561 N_("net ads printer\n"
2562 " List/modify printer entries")
2568 N_("Issue LDAP search using filter"),
2569 N_("net ads search\n"
2570 " Issue LDAP search using filter")
2576 N_("Issue LDAP search by DN"),
2578 " Issue LDAP search by DN")
2584 N_("Issue LDAP search by SID"),
2586 " Issue LDAP search by SID")
2592 N_("Display workgroup name"),
2593 N_("net ads workgroup\n"
2594 " Display the workgroup name")
2600 N_("Perfom CLDAP query on DC"),
2601 N_("net ads lookup\n"
2602 " Find the ADS DC using CLDAP lookups")
2608 N_("Manage local keytab file"),
2609 N_("net ads keytab\n"
2610 " Manage local keytab file")
2616 N_("Manage group policy objects"),
2618 " Manage group policy objects")
2624 N_("Manage kerberos keytab"),
2625 N_("net ads kerberos\n"
2626 " Manage kerberos keytab")
2628 {NULL, NULL, 0, NULL, NULL}
2631 return net_run_function(c, argc, argv, "net ads", func);
2636 static int net_ads_noads(void)
2638 d_fprintf(stderr, _("ADS support not compiled in\n"));
2642 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2644 return net_ads_noads();
2647 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2649 return net_ads_noads();
2652 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2654 return net_ads_noads();
2657 int net_ads_join(struct net_context *c, int argc, const char **argv)
2659 return net_ads_noads();
2662 int net_ads_user(struct net_context *c, int argc, const char **argv)
2664 return net_ads_noads();
2667 int net_ads_group(struct net_context *c, int argc, const char **argv)
2669 return net_ads_noads();
2672 /* this one shouldn't display a message */
2673 int net_ads_check(struct net_context *c)
2678 int net_ads_check_our_domain(struct net_context *c)
2683 int net_ads(struct net_context *c, int argc, const char **argv)
2685 return net_ads_noads();
2688 #endif /* WITH_ADS */