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"
28 #include "libads/cldap.h"
29 #include "libads/dns.h"
30 #include "../libds/common/flags.h"
34 /* when we do not have sufficient input parameters to contact a remote domain
35 * we always fall back to our own realm - Guenther*/
37 static const char *assume_own_realm(struct net_context *c)
39 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
47 do a cldap netlogon query
49 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
51 char addr[INET6_ADDRSTRLEN];
52 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
54 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
55 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
56 d_fprintf(stderr, _("CLDAP query failed!\n"));
60 d_printf(_("Information for Domain Controller: %s\n\n"),
63 d_printf(_("Response Type: "));
64 switch (reply.command) {
65 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
66 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
68 case LOGON_SAM_LOGON_RESPONSE_EX:
69 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
72 d_printf("0x%x\n", reply.command);
76 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
80 "\tIs a GC of the forest: %s\n"
81 "\tIs an LDAP server: %s\n"
83 "\tIs running a KDC: %s\n"
84 "\tIs running time services: %s\n"
85 "\tIs the closest DC: %s\n"
87 "\tHas a hardware clock: %s\n"
88 "\tIs a non-domain NC serviced by LDAP server: %s\n"
89 "\tIs NT6 DC that has some secrets: %s\n"
90 "\tIs NT6 DC that has all secrets: %s\n"),
91 (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
92 (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
93 (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
94 (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
95 (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
96 (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
97 (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
98 (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
99 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
100 (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
101 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
102 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"));
105 printf(_("Forest:\t\t\t%s\n"), reply.forest);
106 printf(_("Domain:\t\t\t%s\n"), reply.dns_domain);
107 printf(_("Domain Controller:\t%s\n"), reply.pdc_dns_name);
109 printf(_("Pre-Win2k Domain:\t%s\n"), reply.domain_name);
110 printf(_("Pre-Win2k Hostname:\t%s\n"), reply.pdc_name);
112 if (*reply.user_name) printf(_("User name:\t%s\n"), reply.user_name);
114 printf(_("Server Site Name :\t\t%s\n"), reply.server_site);
115 printf(_("Client Site Name :\t\t%s\n"), reply.client_site);
117 d_printf(_("NT Version: %d\n"), reply.nt_version);
118 d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
119 d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
125 this implements the CLDAP based netlogon lookup requests
126 for finding the domain controller of a ADS domain
128 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
133 if (c->display_usage) {
138 _("Find the ADS DC using CLDAP lookup.\n"));
142 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
143 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
148 if (!ads->config.realm) {
149 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
150 ads->ldap.port = 389;
153 ret = net_ads_cldap_netlogon(c, ads);
160 static int net_ads_info(struct net_context *c, int argc, const char **argv)
163 char addr[INET6_ADDRSTRLEN];
165 if (c->display_usage) {
170 _("Display information about an Active Directory "
175 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
176 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
180 if (!ads || !ads->config.realm) {
181 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
186 /* Try to set the server's current time since we didn't do a full
187 TCP LDAP session initially */
189 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
190 d_fprintf( stderr, _("Failed to get server's current time!\n"));
193 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
195 d_printf(_("LDAP server: %s\n"), addr);
196 d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
197 d_printf(_("Realm: %s\n"), ads->config.realm);
198 d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
199 d_printf(_("LDAP port: %d\n"), ads->ldap.port);
200 d_printf(_("Server time: %s\n"),
201 http_timestring(talloc_tos(), ads->config.current_time));
203 d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
204 d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
210 static void use_in_memory_ccache(void) {
211 /* Use in-memory credentials cache so we do not interfere with
212 * existing credentials */
213 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
216 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
217 uint32 auth_flags, ADS_STRUCT **ads_ret)
219 ADS_STRUCT *ads = NULL;
221 bool need_password = false;
222 bool second_time = false;
224 const char *realm = NULL;
225 bool tried_closest_dc = false;
227 /* lp_realm() should be handled by a command line param,
228 However, the join requires that realm be set in smb.conf
229 and compares our realm with the remote server's so this is
230 ok until someone needs more flexibility */
235 if (only_own_domain) {
238 realm = assume_own_realm(c);
241 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
243 if (!c->opt_user_name) {
244 c->opt_user_name = "administrator";
247 if (c->opt_user_specified) {
248 need_password = true;
252 if (!c->opt_password && need_password && !c->opt_machine_pass) {
253 c->opt_password = net_prompt_pass(c, c->opt_user_name);
254 if (!c->opt_password) {
256 return ADS_ERROR(LDAP_NO_MEMORY);
260 if (c->opt_password) {
261 use_in_memory_ccache();
262 SAFE_FREE(ads->auth.password);
263 ads->auth.password = smb_xstrdup(c->opt_password);
266 ads->auth.flags |= auth_flags;
267 SAFE_FREE(ads->auth.user_name);
268 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
271 * If the username is of the form "name@realm",
272 * extract the realm and convert to upper case.
273 * This is only used to establish the connection.
275 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
277 SAFE_FREE(ads->auth.realm);
278 ads->auth.realm = smb_xstrdup(cp);
279 strupper_m(ads->auth.realm);
282 status = ads_connect(ads);
284 if (!ADS_ERR_OK(status)) {
286 if (NT_STATUS_EQUAL(ads_ntstatus(status),
287 NT_STATUS_NO_LOGON_SERVERS)) {
288 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
293 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
294 need_password = true;
303 /* when contacting our own domain, make sure we use the closest DC.
304 * This is done by reconnecting to ADS because only the first call to
305 * ads_connect will give us our own sitename */
307 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
309 tried_closest_dc = true; /* avoid loop */
311 if (!ads_closest_dc(ads)) {
313 namecache_delete(ads->server.realm, 0x1C);
314 namecache_delete(ads->server.workgroup, 0x1C);
327 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
329 return ads_startup_int(c, only_own_domain, 0, ads);
332 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
334 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
338 Check to see if connection can be made via ads.
339 ads_startup() stores the password in opt_password if it needs to so
340 that rpc or rap can use it without re-prompting.
342 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
347 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
351 ads->auth.flags |= ADS_AUTH_NO_BIND;
353 status = ads_connect(ads);
354 if ( !ADS_ERR_OK(status) ) {
362 int net_ads_check_our_domain(struct net_context *c)
364 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
367 int net_ads_check(struct net_context *c)
369 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
373 determine the netbios workgroup name for a domain
375 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
378 char addr[INET6_ADDRSTRLEN];
379 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
381 if (c->display_usage) {
383 "net ads workgroup\n"
386 _("Print the workgroup name"));
390 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
391 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
395 if (!ads->config.realm) {
396 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
397 ads->ldap.port = 389;
400 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
401 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
402 d_fprintf(stderr, _("CLDAP query failed!\n"));
407 d_printf(_("Workgroup: %s\n"), reply.domain_name);
416 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
418 char **disp_fields = (char **) data_area;
420 if (!field) { /* must be end of record */
421 if (disp_fields[0]) {
422 if (!strchr_m(disp_fields[0], '$')) {
424 d_printf("%-21.21s %s\n",
425 disp_fields[0], disp_fields[1]);
427 d_printf("%s\n", disp_fields[0]);
430 SAFE_FREE(disp_fields[0]);
431 SAFE_FREE(disp_fields[1]);
434 if (!values) /* must be new field, indicate string field */
436 if (StrCaseCmp(field, "sAMAccountName") == 0) {
437 disp_fields[0] = SMB_STRDUP((char *) values[0]);
439 if (StrCaseCmp(field, "description") == 0)
440 disp_fields[1] = SMB_STRDUP((char *) values[0]);
444 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
446 return net_user_usage(c, argc, argv);
449 static int ads_user_add(struct net_context *c, int argc, const char **argv)
454 LDAPMessage *res=NULL;
458 if (argc < 1 || c->display_usage)
459 return net_ads_user_usage(c, argc, argv);
461 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
465 status = ads_find_user_acct(ads, &res, argv[0]);
467 if (!ADS_ERR_OK(status)) {
468 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
472 if (ads_count_replies(ads, res)) {
473 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
478 if (c->opt_container) {
479 ou_str = SMB_STRDUP(c->opt_container);
481 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
484 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
486 if (!ADS_ERR_OK(status)) {
487 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
492 /* if no password is to be set, we're done */
494 d_printf(_("User %s added\n"), argv[0]);
499 /* try setting the password */
500 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
503 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
504 ads->auth.time_offset);
506 if (ADS_ERR_OK(status)) {
507 d_printf(_("User %s added\n"), argv[0]);
512 /* password didn't set, delete account */
513 d_fprintf(stderr, _("Could not add user %s. "
514 "Error setting password %s\n"),
515 argv[0], ads_errstr(status));
516 ads_msgfree(ads, res);
517 status=ads_find_user_acct(ads, &res, argv[0]);
518 if (ADS_ERR_OK(status)) {
519 userdn = ads_get_dn(ads, talloc_tos(), res);
520 ads_del_dn(ads, userdn);
526 ads_msgfree(ads, res);
532 static int ads_user_info(struct net_context *c, int argc, const char **argv)
534 ADS_STRUCT *ads = NULL;
536 LDAPMessage *res = NULL;
540 const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
541 char *searchstring=NULL;
545 struct dom_sid primary_group_sid;
547 enum wbcSidType type;
549 if (argc < 1 || c->display_usage) {
550 return net_ads_user_usage(c, argc, argv);
553 frame = talloc_new(talloc_tos());
558 escaped_user = escape_ldap_string(frame, argv[0]);
561 _("ads_user_info: failed to escape user %s\n"),
566 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
571 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
575 rc = ads_search(ads, &res, searchstring, attrs);
576 SAFE_FREE(searchstring);
578 if (!ADS_ERR_OK(rc)) {
579 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(rc));
584 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
585 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
590 rc = ads_domain_sid(ads, &primary_group_sid);
591 if (!ADS_ERR_OK(rc)) {
592 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(rc));
597 sid_append_rid(&primary_group_sid, group_rid);
599 wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
600 NULL, /* don't look up domain */
603 if (!WBC_ERROR_IS_OK(wbc_status)) {
604 d_fprintf(stderr, "wbcLookupSid: %s\n",
605 wbcErrorString(wbc_status));
610 d_printf("%s\n", primary_group);
612 wbcFreeMemory(primary_group);
614 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
615 (LDAPMessage *)res, "memberOf");
620 for (i=0;grouplist[i];i++) {
621 groupname = ldap_explode_dn(grouplist[i], 1);
622 d_printf("%s\n", groupname[0]);
623 ldap_value_free(groupname);
625 ldap_value_free(grouplist);
629 if (res) ads_msgfree(ads, res);
630 if (ads) ads_destroy(&ads);
635 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
639 LDAPMessage *res = NULL;
643 return net_ads_user_usage(c, argc, argv);
646 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
650 rc = ads_find_user_acct(ads, &res, argv[0]);
651 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
652 d_printf(_("User %s does not exist.\n"), argv[0]);
653 ads_msgfree(ads, res);
657 userdn = ads_get_dn(ads, talloc_tos(), res);
658 ads_msgfree(ads, res);
659 rc = ads_del_dn(ads, userdn);
661 if (ADS_ERR_OK(rc)) {
662 d_printf(_("User %s deleted\n"), argv[0]);
666 d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
672 int net_ads_user(struct net_context *c, int argc, const char **argv)
674 struct functable func[] = {
679 N_("Add an AD user"),
680 N_("net ads user add\n"
687 N_("Display information about an AD user"),
688 N_("net ads user info\n"
689 " Display information about an AD user")
695 N_("Delete an AD user"),
696 N_("net ads user delete\n"
697 " Delete an AD user")
699 {NULL, NULL, 0, NULL, NULL}
703 const char *shortattrs[] = {"sAMAccountName", NULL};
704 const char *longattrs[] = {"sAMAccountName", "description", NULL};
705 char *disp_fields[2] = {NULL, NULL};
708 if (c->display_usage) {
714 net_display_usage_from_functable(func);
718 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
722 if (c->opt_long_list_entries)
723 d_printf(_("\nUser name Comment"
724 "\n-----------------------------\n"));
726 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
728 "(objectCategory=user)",
729 c->opt_long_list_entries ? longattrs :
730 shortattrs, usergrp_display,
733 return ADS_ERR_OK(rc) ? 0 : -1;
736 return net_run_function(c, argc, argv, "net ads user", func);
739 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
741 return net_group_usage(c, argc, argv);
744 static int ads_group_add(struct net_context *c, int argc, const char **argv)
748 LDAPMessage *res=NULL;
752 if (argc < 1 || c->display_usage) {
753 return net_ads_group_usage(c, argc, argv);
756 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
760 status = ads_find_user_acct(ads, &res, argv[0]);
762 if (!ADS_ERR_OK(status)) {
763 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
767 if (ads_count_replies(ads, res)) {
768 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
772 if (c->opt_container) {
773 ou_str = SMB_STRDUP(c->opt_container);
775 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
778 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
780 if (ADS_ERR_OK(status)) {
781 d_printf(_("Group %s added\n"), argv[0]);
784 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
790 ads_msgfree(ads, res);
796 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
800 LDAPMessage *res = NULL;
803 if (argc < 1 || c->display_usage) {
804 return net_ads_group_usage(c, argc, argv);
807 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
811 rc = ads_find_user_acct(ads, &res, argv[0]);
812 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
813 d_printf(_("Group %s does not exist.\n"), argv[0]);
814 ads_msgfree(ads, res);
818 groupdn = ads_get_dn(ads, talloc_tos(), res);
819 ads_msgfree(ads, res);
820 rc = ads_del_dn(ads, groupdn);
821 TALLOC_FREE(groupdn);
822 if (ADS_ERR_OK(rc)) {
823 d_printf(_("Group %s deleted\n"), argv[0]);
827 d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
833 int net_ads_group(struct net_context *c, int argc, const char **argv)
835 struct functable func[] = {
840 N_("Add an AD group"),
841 N_("net ads group add\n"
848 N_("Delete an AD group"),
849 N_("net ads group delete\n"
850 " Delete an AD group")
852 {NULL, NULL, 0, NULL, NULL}
856 const char *shortattrs[] = {"sAMAccountName", NULL};
857 const char *longattrs[] = {"sAMAccountName", "description", NULL};
858 char *disp_fields[2] = {NULL, NULL};
861 if (c->display_usage) {
866 _("List AD groups"));
867 net_display_usage_from_functable(func);
871 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
875 if (c->opt_long_list_entries)
876 d_printf(_("\nGroup name Comment"
877 "\n-----------------------------\n"));
878 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
880 "(objectCategory=group)",
881 c->opt_long_list_entries ? longattrs :
882 shortattrs, usergrp_display,
886 return ADS_ERR_OK(rc) ? 0 : -1;
888 return net_run_function(c, argc, argv, "net ads group", func);
891 static int net_ads_status(struct net_context *c, int argc, const char **argv)
897 if (c->display_usage) {
902 _("Display machine account details"));
906 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
910 rc = ads_find_machine_acct(ads, &res, global_myname());
911 if (!ADS_ERR_OK(rc)) {
912 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
917 if (ads_count_replies(ads, res) == 0) {
918 d_fprintf(stderr, _("No machine account for '%s' found\n"), global_myname());
928 /*******************************************************************
929 Leave an AD domain. Windows XP disables the machine account.
930 We'll try the same. The old code would do an LDAP delete.
931 That only worked using the machine creds because added the machine
932 with full control to the computer object's ACL.
933 *******************************************************************/
935 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
938 struct libnet_UnjoinCtx *r = NULL;
941 if (c->display_usage) {
946 _("Leave an AD domain"));
951 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
955 if (!(ctx = talloc_init("net_ads_leave"))) {
956 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
960 if (!c->opt_kerberos) {
961 use_in_memory_ccache();
964 werr = libnet_init_UnjoinCtx(ctx, &r);
965 if (!W_ERROR_IS_OK(werr)) {
966 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
971 r->in.use_kerberos = c->opt_kerberos;
972 r->in.dc_name = c->opt_host;
973 r->in.domain_name = lp_realm();
974 r->in.admin_account = c->opt_user_name;
975 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
976 r->in.modify_config = lp_config_backend_is_registry();
978 /* Try to delete it, but if that fails, disable it. The
979 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
980 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
981 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
982 r->in.delete_machine_account = true;
984 werr = libnet_Unjoin(ctx, r);
985 if (!W_ERROR_IS_OK(werr)) {
986 d_printf(_("Failed to leave domain: %s\n"),
987 r->out.error_string ? r->out.error_string :
988 get_friendly_werror_msg(werr));
992 if (r->out.deleted_machine_account) {
993 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
994 r->in.machine_name, r->out.dns_domain_name);
998 /* We couldn't delete it - see if the disable succeeded. */
999 if (r->out.disabled_machine_account) {
1000 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1001 r->in.machine_name, r->out.dns_domain_name);
1006 /* Based on what we requseted, we shouldn't get here, but if
1007 we did, it means the secrets were removed, and therefore
1008 we have left the domain */
1009 d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1010 r->in.machine_name, r->out.dns_domain_name);
1016 if (W_ERROR_IS_OK(werr)) {
1023 static NTSTATUS net_ads_join_ok(struct net_context *c)
1025 ADS_STRUCT *ads = NULL;
1028 struct sockaddr_storage dcip;
1030 if (!secrets_init()) {
1031 DEBUG(1,("Failed to initialise secrets database\n"));
1032 return NT_STATUS_ACCESS_DENIED;
1035 net_use_krb_machine_account(c);
1037 get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1039 status = ads_startup(c, true, &ads);
1040 if (!ADS_ERR_OK(status)) {
1041 return ads_ntstatus(status);
1045 return NT_STATUS_OK;
1049 check that an existing join is OK
1051 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1054 use_in_memory_ccache();
1056 if (c->display_usage) {
1058 "net ads testjoin\n"
1061 _("Test if the existing join is ok"));
1065 /* Display success or failure */
1066 status = net_ads_join_ok(c);
1067 if (!NT_STATUS_IS_OK(status)) {
1068 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1069 get_friendly_nt_error_msg(status));
1073 printf(_("Join is OK\n"));
1077 /*******************************************************************
1078 Simple configu checks before beginning the join
1079 ********************************************************************/
1081 static WERROR check_ads_config( void )
1083 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1084 d_printf(_("Host is not configured as a member server.\n"));
1085 return WERR_INVALID_DOMAIN_ROLE;
1088 if (strlen(global_myname()) > 15) {
1089 d_printf(_("Our netbios name can be at most 15 chars long, "
1090 "\"%s\" is %u chars long\n"), global_myname(),
1091 (unsigned int)strlen(global_myname()));
1092 return WERR_INVALID_COMPUTERNAME;
1095 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1096 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1097 "join to succeed.\n"), get_dyn_CONFIGFILE());
1098 return WERR_INVALID_PARAM;
1104 /*******************************************************************
1105 Send a DNS update request
1106 *******************************************************************/
1108 #if defined(WITH_DNS_UPDATES)
1110 DNS_ERROR DoDNSUpdate(char *pszServerName,
1111 const char *pszDomainName, const char *pszHostName,
1112 const struct sockaddr_storage *sslist,
1115 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1116 const char *machine_name,
1117 const struct sockaddr_storage *addrs,
1120 struct dns_rr_ns *nameservers = NULL;
1122 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1125 const char *dnsdomain = NULL;
1126 char *root_domain = NULL;
1128 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1129 d_printf(_("No DNS domain configured for %s. "
1130 "Unable to perform DNS Update.\n"), machine_name);
1131 status = NT_STATUS_INVALID_PARAMETER;
1136 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1137 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1138 /* Child domains often do not have NS records. Look
1139 for the NS record for the forest root domain
1140 (rootDomainNamingContext in therootDSE) */
1142 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1143 LDAPMessage *msg = NULL;
1145 ADS_STATUS ads_status;
1147 if ( !ads->ldap.ld ) {
1148 ads_status = ads_connect( ads );
1149 if ( !ADS_ERR_OK(ads_status) ) {
1150 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1155 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1156 "(objectclass=*)", rootname_attrs, &msg);
1157 if (!ADS_ERR_OK(ads_status)) {
1161 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1163 ads_msgfree( ads, msg );
1167 root_domain = ads_build_domain( root_dn );
1170 ads_msgfree( ads, msg );
1172 /* try again for NS servers */
1174 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1176 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1177 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1178 "realm\n", ads->config.realm));
1182 dnsdomain = root_domain;
1186 /* Now perform the dns update - we'll try non-secure and if we fail,
1187 we'll follow it up with a secure update */
1189 fstrcpy( dns_server, nameservers[0].hostname );
1191 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1192 if (!ERR_DNS_IS_OK(dns_err)) {
1193 status = NT_STATUS_UNSUCCESSFUL;
1198 SAFE_FREE( root_domain );
1203 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1206 struct sockaddr_storage *iplist = NULL;
1207 fstring machine_name;
1210 name_to_fqdn( machine_name, global_myname() );
1211 strlower_m( machine_name );
1213 /* Get our ip address (not the 127.0.0.x address but a real ip
1216 num_addrs = get_my_ip_address( &iplist );
1217 if ( num_addrs <= 0 ) {
1218 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1220 return NT_STATUS_INVALID_PARAMETER;
1223 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1225 SAFE_FREE( iplist );
1231 /*******************************************************************
1232 ********************************************************************/
1234 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1236 d_printf(_("net ads join [options]\n"
1237 "Valid options:\n"));
1238 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1239 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1240 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1241 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1242 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1243 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1244 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1245 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1246 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1247 " NB: osName and osVer must be specified together for either to take effect.\n"
1248 " Also, the operatingSystemService attribute is also set when along with\n"
1249 " the two other attributes.\n"));
1254 /*******************************************************************
1255 ********************************************************************/
1257 int net_ads_join(struct net_context *c, int argc, const char **argv)
1259 TALLOC_CTX *ctx = NULL;
1260 struct libnet_JoinCtx *r = NULL;
1261 const char *domain = lp_realm();
1262 WERROR werr = WERR_SETUP_NOT_JOINED;
1263 bool createupn = false;
1264 const char *machineupn = NULL;
1265 const char *create_in_ou = NULL;
1267 const char *os_name = NULL;
1268 const char *os_version = NULL;
1269 bool modify_config = lp_config_backend_is_registry();
1271 if (c->display_usage)
1272 return net_ads_join_usage(c, argc, argv);
1274 if (!modify_config) {
1276 werr = check_ads_config();
1277 if (!W_ERROR_IS_OK(werr)) {
1278 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1283 if (!(ctx = talloc_init("net_ads_join"))) {
1284 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1289 if (!c->opt_kerberos) {
1290 use_in_memory_ccache();
1293 werr = libnet_init_JoinCtx(ctx, &r);
1294 if (!W_ERROR_IS_OK(werr)) {
1298 /* process additional command line args */
1300 for ( i=0; i<argc; i++ ) {
1301 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1303 machineupn = get_string_param(argv[i]);
1305 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1306 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1307 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1308 werr = WERR_INVALID_PARAM;
1312 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1313 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1314 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1315 werr = WERR_INVALID_PARAM;
1319 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1320 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1321 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1322 werr = WERR_INVALID_PARAM;
1332 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1333 werr = WERR_INVALID_PARAM;
1337 /* Do the domain join here */
1339 r->in.domain_name = domain;
1340 r->in.create_upn = createupn;
1341 r->in.upn = machineupn;
1342 r->in.account_ou = create_in_ou;
1343 r->in.os_name = os_name;
1344 r->in.os_version = os_version;
1345 r->in.dc_name = c->opt_host;
1346 r->in.admin_account = c->opt_user_name;
1347 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1349 r->in.use_kerberos = c->opt_kerberos;
1350 r->in.modify_config = modify_config;
1351 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1352 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1353 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1355 werr = libnet_Join(ctx, r);
1356 if (!W_ERROR_IS_OK(werr)) {
1360 /* Check the short name of the domain */
1362 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1363 d_printf(_("The workgroup in %s does not match the short\n"
1364 "domain name obtained from the server.\n"
1365 "Using the name [%s] from the server.\n"
1366 "You should set \"workgroup = %s\" in %s.\n"),
1367 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1368 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1371 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1373 if (r->out.dns_domain_name) {
1374 d_printf(_("Joined '%s' to realm '%s'\n"), r->in.machine_name,
1375 r->out.dns_domain_name);
1377 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1378 r->out.netbios_domain_name);
1381 #if defined(WITH_DNS_UPDATES)
1382 if (r->out.domain_is_ad) {
1383 /* We enter this block with user creds */
1384 ADS_STRUCT *ads_dns = NULL;
1386 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1387 /* kinit with the machine password */
1389 use_in_memory_ccache();
1390 if (asprintf( &ads_dns->auth.user_name, "%s$", global_myname()) == -1) {
1393 ads_dns->auth.password = secrets_fetch_machine_password(
1394 r->out.netbios_domain_name, NULL, NULL );
1395 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1396 strupper_m(ads_dns->auth.realm );
1397 ads_kinit_password( ads_dns );
1400 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1401 d_fprintf( stderr, _("DNS update failed!\n") );
1404 /* exit from this block using machine creds */
1405 ads_destroy(&ads_dns);
1414 /* issue an overall failure message at the end. */
1415 d_printf(_("Failed to join domain: %s\n"),
1416 r && r->out.error_string ? r->out.error_string :
1417 get_friendly_werror_msg(werr));
1423 /*******************************************************************
1424 ********************************************************************/
1426 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1428 #if defined(WITH_DNS_UPDATES)
1434 talloc_enable_leak_report();
1437 if (argc > 0 || c->display_usage) {
1439 "net ads dns register\n"
1442 _("Register hostname with DNS\n"));
1446 if (!(ctx = talloc_init("net_ads_dns"))) {
1447 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1451 status = ads_startup(c, true, &ads);
1452 if ( !ADS_ERR_OK(status) ) {
1453 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1458 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1459 d_fprintf( stderr, _("DNS update failed!\n") );
1460 ads_destroy( &ads );
1465 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1473 _("DNS update support not enabled at compile time!\n"));
1478 #if defined(WITH_DNS_UPDATES)
1479 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1482 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1484 #if defined(WITH_DNS_UPDATES)
1488 talloc_enable_leak_report();
1491 if (argc != 2 || c->display_usage) {
1496 _("net ads dns gethostbyname <server> <name>\n"),
1497 _(" Look up hostname from the AD\n"
1498 " server\tName server to use\n"
1499 " name\tName to look up\n"));
1503 err = do_gethostbyname(argv[0], argv[1]);
1505 d_printf(_("do_gethostbyname returned %d\n"), ERROR_DNS_V(err));
1510 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1512 struct functable func[] = {
1515 net_ads_dns_register,
1517 N_("Add host dns entry to AD"),
1518 N_("net ads dns register\n"
1519 " Add host dns entry to AD")
1523 net_ads_dns_gethostbyname,
1526 N_("net ads dns gethostbyname\n"
1529 {NULL, NULL, 0, NULL, NULL}
1532 return net_run_function(c, argc, argv, "net ads dns", func);
1535 /*******************************************************************
1536 ********************************************************************/
1538 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1541 "\nnet ads printer search <printer>"
1542 "\n\tsearch for a printer in the directory\n"
1543 "\nnet ads printer info <printer> <server>"
1544 "\n\tlookup info in directory for printer on server"
1545 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1546 "\nnet ads printer publish <printername>"
1547 "\n\tpublish printer in directory"
1548 "\n\t(note: printer name is required)\n"
1549 "\nnet ads printer remove <printername>"
1550 "\n\tremove printer from directory"
1551 "\n\t(note: printer name is required)\n"));
1555 /*******************************************************************
1556 ********************************************************************/
1558 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1562 LDAPMessage *res = NULL;
1564 if (c->display_usage) {
1566 "net ads printer search\n"
1569 _("List printers in the AD"));
1573 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1577 rc = ads_find_printers(ads, &res);
1579 if (!ADS_ERR_OK(rc)) {
1580 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
1581 ads_msgfree(ads, res);
1586 if (ads_count_replies(ads, res) == 0) {
1587 d_fprintf(stderr, _("No results found\n"));
1588 ads_msgfree(ads, res);
1594 ads_msgfree(ads, res);
1599 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1603 const char *servername, *printername;
1604 LDAPMessage *res = NULL;
1606 if (c->display_usage) {
1609 _("net ads printer info [printername [servername]]\n"
1610 " Display printer info from AD\n"
1611 " printername\tPrinter name or wildcard\n"
1612 " servername\tName of the print server\n"));
1616 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1621 printername = argv[0];
1627 servername = argv[1];
1629 servername = global_myname();
1632 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1634 if (!ADS_ERR_OK(rc)) {
1635 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
1636 servername, ads_errstr(rc));
1637 ads_msgfree(ads, res);
1642 if (ads_count_replies(ads, res) == 0) {
1643 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
1644 ads_msgfree(ads, res);
1650 ads_msgfree(ads, res);
1656 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1660 const char *servername, *printername;
1661 struct cli_state *cli = NULL;
1662 struct rpc_pipe_client *pipe_hnd = NULL;
1663 struct sockaddr_storage server_ss;
1665 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1666 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1667 char *prt_dn, *srv_dn, **srv_cn;
1668 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1669 LDAPMessage *res = NULL;
1671 if (argc < 1 || c->display_usage) {
1674 _("net ads printer publish <printername> [servername]\n"
1675 " Publish printer in AD\n"
1676 " printername\tName of the printer\n"
1677 " servername\tName of the print server\n"));
1678 talloc_destroy(mem_ctx);
1682 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1683 talloc_destroy(mem_ctx);
1687 printername = argv[0];
1690 servername = argv[1];
1692 servername = global_myname();
1695 /* Get printer data from SPOOLSS */
1697 resolve_name(servername, &server_ss, 0x20, false);
1699 nt_status = cli_full_connection(&cli, global_myname(), servername,
1702 c->opt_user_name, c->opt_workgroup,
1703 c->opt_password ? c->opt_password : "",
1704 CLI_FULL_CONNECTION_USE_KERBEROS,
1707 if (NT_STATUS_IS_ERR(nt_status)) {
1708 d_fprintf(stderr, _("Unable to open a connnection to %s to "
1709 "obtain data for %s\n"),
1710 servername, printername);
1712 talloc_destroy(mem_ctx);
1716 /* Publish on AD server */
1718 ads_find_machine_acct(ads, &res, servername);
1720 if (ads_count_replies(ads, res) == 0) {
1721 d_fprintf(stderr, _("Could not find machine account for server "
1725 talloc_destroy(mem_ctx);
1729 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1730 srv_cn = ldap_explode_dn(srv_dn, 1);
1732 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1733 printername_escaped = escape_rdn_val_string_alloc(printername);
1734 if (!srv_cn_escaped || !printername_escaped) {
1735 SAFE_FREE(srv_cn_escaped);
1736 SAFE_FREE(printername_escaped);
1737 d_fprintf(stderr, _("Internal error, out of memory!"));
1739 talloc_destroy(mem_ctx);
1743 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1744 SAFE_FREE(srv_cn_escaped);
1745 SAFE_FREE(printername_escaped);
1746 d_fprintf(stderr, _("Internal error, out of memory!"));
1748 talloc_destroy(mem_ctx);
1752 SAFE_FREE(srv_cn_escaped);
1753 SAFE_FREE(printername_escaped);
1755 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
1756 if (!NT_STATUS_IS_OK(nt_status)) {
1757 d_fprintf(stderr, _("Unable to open a connnection to the spoolss pipe on %s\n"),
1761 talloc_destroy(mem_ctx);
1765 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1769 talloc_destroy(mem_ctx);
1773 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1774 if (!ADS_ERR_OK(rc)) {
1775 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1778 talloc_destroy(mem_ctx);
1782 d_printf("published printer\n");
1785 talloc_destroy(mem_ctx);
1790 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1794 const char *servername;
1796 LDAPMessage *res = NULL;
1798 if (argc < 1 || c->display_usage) {
1801 _("net ads printer remove <printername> [servername]\n"
1802 " Remove a printer from the AD\n"
1803 " printername\tName of the printer\n"
1804 " servername\tName of the print server\n"));
1808 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1813 servername = argv[1];
1815 servername = global_myname();
1818 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1820 if (!ADS_ERR_OK(rc)) {
1821 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
1822 ads_msgfree(ads, res);
1827 if (ads_count_replies(ads, res) == 0) {
1828 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
1829 ads_msgfree(ads, res);
1834 prt_dn = ads_get_dn(ads, talloc_tos(), res);
1835 ads_msgfree(ads, res);
1836 rc = ads_del_dn(ads, prt_dn);
1837 TALLOC_FREE(prt_dn);
1839 if (!ADS_ERR_OK(rc)) {
1840 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
1849 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1851 struct functable func[] = {
1854 net_ads_printer_search,
1856 N_("Search for a printer"),
1857 N_("net ads printer search\n"
1858 " Search for a printer")
1862 net_ads_printer_info,
1864 N_("Display printer information"),
1865 N_("net ads printer info\n"
1866 " Display printer information")
1870 net_ads_printer_publish,
1872 N_("Publish a printer"),
1873 N_("net ads printer publish\n"
1874 " Publish a printer")
1878 net_ads_printer_remove,
1880 N_("Delete a printer"),
1881 N_("net ads printer remove\n"
1882 " Delete a printer")
1884 {NULL, NULL, 0, NULL, NULL}
1887 return net_run_function(c, argc, argv, "net ads printer", func);
1891 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1894 const char *auth_principal = c->opt_user_name;
1895 const char *auth_password = c->opt_password;
1897 char *new_password = NULL;
1902 if (c->display_usage) {
1905 _("net ads password <username>\n"
1906 " Change password for user\n"
1907 " username\tName of user to change password for\n"));
1911 if (c->opt_user_name == NULL || c->opt_password == NULL) {
1912 d_fprintf(stderr, _("You must supply an administrator "
1913 "username/password\n"));
1918 d_fprintf(stderr, _("ERROR: You must say which username to "
1919 "change password for\n"));
1924 if (!strchr_m(user, '@')) {
1925 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
1931 use_in_memory_ccache();
1932 chr = strchr_m(auth_principal, '@');
1939 /* use the realm so we can eventually change passwords for users
1940 in realms other than default */
1941 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1945 /* we don't actually need a full connect, but it's the easy way to
1946 fill in the KDC's addresss */
1949 if (!ads->config.realm) {
1950 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
1956 new_password = (char *)argv[1];
1958 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
1961 new_password = getpass(prompt);
1965 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1966 auth_password, user, new_password, ads->auth.time_offset);
1967 if (!ADS_ERR_OK(ret)) {
1968 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
1973 d_printf(_("Password change for %s completed.\n"), user);
1979 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1982 char *host_principal;
1986 if (c->display_usage) {
1988 "net ads changetrustpw\n"
1991 _("Change the machine account's trust password"));
1995 if (!secrets_init()) {
1996 DEBUG(1,("Failed to initialise secrets database\n"));
2000 net_use_krb_machine_account(c);
2002 use_in_memory_ccache();
2004 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2008 fstrcpy(my_name, global_myname());
2009 strlower_m(my_name);
2010 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2014 d_printf(_("Changing password for principal: %s\n"), host_principal);
2016 ret = ads_change_trust_account_password(ads, host_principal);
2018 if (!ADS_ERR_OK(ret)) {
2019 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2021 SAFE_FREE(host_principal);
2025 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2027 if (USE_SYSTEM_KEYTAB) {
2028 d_printf(_("Attempting to update system keytab with new password.\n"));
2029 if (ads_keytab_create_default(ads)) {
2030 d_printf(_("Failed to update system keytab.\n"));
2035 SAFE_FREE(host_principal);
2041 help for net ads search
2043 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2046 "\nnet ads search <expression> <attributes...>\n"
2047 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2048 "The expression is a standard LDAP search expression, and the\n"
2049 "attributes are a list of LDAP fields to show in the results.\n\n"
2050 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2052 net_common_flags_usage(c, argc, argv);
2058 general ADS search function. Useful in diagnosing problems in ADS
2060 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2064 const char *ldap_exp;
2066 LDAPMessage *res = NULL;
2068 if (argc < 1 || c->display_usage) {
2069 return net_ads_search_usage(c, argc, argv);
2072 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2079 rc = ads_do_search_all(ads, ads->config.bind_path,
2081 ldap_exp, attrs, &res);
2082 if (!ADS_ERR_OK(rc)) {
2083 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2088 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2090 /* dump the results */
2093 ads_msgfree(ads, res);
2101 help for net ads search
2103 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2106 "\nnet ads dn <dn> <attributes...>\n"
2107 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2108 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2109 "to show in the results\n\n"
2110 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2111 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2113 net_common_flags_usage(c, argc, argv);
2119 general ADS search function. Useful in diagnosing problems in ADS
2121 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2127 LDAPMessage *res = NULL;
2129 if (argc < 1 || c->display_usage) {
2130 return net_ads_dn_usage(c, argc, argv);
2133 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2140 rc = ads_do_search_all(ads, dn,
2142 "(objectclass=*)", attrs, &res);
2143 if (!ADS_ERR_OK(rc)) {
2144 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2149 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2151 /* dump the results */
2154 ads_msgfree(ads, res);
2161 help for net ads sid search
2163 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2166 "\nnet ads sid <sid> <attributes...>\n"
2167 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2168 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2169 "to show in the results\n\n"
2170 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2172 net_common_flags_usage(c, argc, argv);
2178 general ADS search function. Useful in diagnosing problems in ADS
2180 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2184 const char *sid_string;
2186 LDAPMessage *res = NULL;
2189 if (argc < 1 || c->display_usage) {
2190 return net_ads_sid_usage(c, argc, argv);
2193 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2197 sid_string = argv[0];
2200 if (!string_to_sid(&sid, sid_string)) {
2201 d_fprintf(stderr, _("could not convert sid\n"));
2206 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2207 if (!ADS_ERR_OK(rc)) {
2208 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2213 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2215 /* dump the results */
2218 ads_msgfree(ads, res);
2224 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2229 if (c->display_usage) {
2231 "net ads keytab flush\n"
2234 _("Delete the whole keytab"));
2238 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2241 ret = ads_keytab_flush(ads);
2246 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2252 if (c->display_usage) {
2255 _("net ads keytab add <principal> [principal ...]\n"
2256 " Add principals to local keytab\n"
2257 " principal\tKerberos principal to add to "
2262 d_printf(_("Processing principals to add...\n"));
2263 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2266 for (i = 0; i < argc; i++) {
2267 ret |= ads_keytab_add_entry(ads, argv[i]);
2273 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2278 if (c->display_usage) {
2280 "net ads keytab create\n"
2283 _("Create new default keytab"));
2287 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2290 ret = ads_keytab_create_default(ads);
2295 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2297 const char *keytab = NULL;
2299 if (c->display_usage) {
2302 _("net ads keytab list [keytab]\n"
2303 " List a local keytab\n"
2304 " keytab\tKeytab to list\n"));
2312 return ads_keytab_list(keytab);
2316 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2318 struct functable func[] = {
2323 N_("Add a service principal"),
2324 N_("net ads keytab add\n"
2325 " Add a service principal")
2329 net_ads_keytab_create,
2331 N_("Create a fresh keytab"),
2332 N_("net ads keytab create\n"
2333 " Create a fresh keytab")
2337 net_ads_keytab_flush,
2339 N_("Remove all keytab entries"),
2340 N_("net ads keytab flush\n"
2341 " Remove all keytab entries")
2345 net_ads_keytab_list,
2347 N_("List a keytab"),
2348 N_("net ads keytab list\n"
2351 {NULL, NULL, 0, NULL, NULL}
2354 if (!USE_KERBEROS_KEYTAB) {
2355 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2356 "keytab method to use keytab functions.\n"));
2359 return net_run_function(c, argc, argv, "net ads keytab", func);
2362 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2366 if (c->display_usage) {
2368 "net ads kerberos renew\n"
2371 _("Renew TGT from existing credential cache"));
2375 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2377 d_printf(_("failed to renew kerberos ticket: %s\n"),
2378 error_message(ret));
2383 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2385 struct PAC_LOGON_INFO *info = NULL;
2386 TALLOC_CTX *mem_ctx = NULL;
2389 const char *impersonate_princ_s = NULL;
2391 if (c->display_usage) {
2393 "net ads kerberos pac\n"
2396 _("Dump the Kerberos PAC"));
2400 mem_ctx = talloc_init("net_ads_kerberos_pac");
2406 impersonate_princ_s = argv[0];
2409 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2411 status = kerberos_return_pac(mem_ctx,
2420 2592000, /* one month */
2421 impersonate_princ_s,
2423 if (!NT_STATUS_IS_OK(status)) {
2424 d_printf(_("failed to query kerberos PAC: %s\n"),
2431 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2432 d_printf(_("The Pac: %s\n"), s);
2437 TALLOC_FREE(mem_ctx);
2441 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2443 TALLOC_CTX *mem_ctx = NULL;
2447 if (c->display_usage) {
2449 "net ads kerberos kinit\n"
2452 _("Get Ticket Granting Ticket (TGT) for the user"));
2456 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2461 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2463 ret = kerberos_kinit_password_ext(c->opt_user_name,
2471 2592000, /* one month */
2474 d_printf(_("failed to kinit password: %s\n"),
2481 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2483 struct functable func[] = {
2486 net_ads_kerberos_kinit,
2488 N_("Retrieve Ticket Granting Ticket (TGT)"),
2489 N_("net ads kerberos kinit\n"
2490 " Receive Ticket Granting Ticket (TGT)")
2494 net_ads_kerberos_renew,
2496 N_("Renew Ticket Granting Ticket from credential cache"),
2497 N_("net ads kerberos renew\n"
2498 " Renew Ticket Granting Ticket (TGT) from "
2503 net_ads_kerberos_pac,
2505 N_("Dump Kerberos PAC"),
2506 N_("net ads kerberos pac\n"
2507 " Dump Kerberos PAC")
2509 {NULL, NULL, 0, NULL, NULL}
2512 return net_run_function(c, argc, argv, "net ads kerberos", func);
2515 int net_ads(struct net_context *c, int argc, const char **argv)
2517 struct functable func[] = {
2522 N_("Display details on remote ADS server"),
2524 " Display details on remote ADS server")
2530 N_("Join the local machine to ADS realm"),
2532 " Join the local machine to ADS realm")
2538 N_("Validate machine account"),
2539 N_("net ads testjoin\n"
2540 " Validate machine account")
2546 N_("Remove the local machine from ADS"),
2547 N_("net ads leave\n"
2548 " Remove the local machine from ADS")
2554 N_("Display machine account details"),
2555 N_("net ads status\n"
2556 " Display machine account details")
2562 N_("List/modify users"),
2564 " List/modify users")
2570 N_("List/modify groups"),
2571 N_("net ads group\n"
2572 " List/modify groups")
2578 N_("Issue dynamic DNS update"),
2580 " Issue dynamic DNS update")
2586 N_("Change user passwords"),
2587 N_("net ads password\n"
2588 " Change user passwords")
2592 net_ads_changetrustpw,
2594 N_("Change trust account password"),
2595 N_("net ads changetrustpw\n"
2596 " Change trust account password")
2602 N_("List/modify printer entries"),
2603 N_("net ads printer\n"
2604 " List/modify printer entries")
2610 N_("Issue LDAP search using filter"),
2611 N_("net ads search\n"
2612 " Issue LDAP search using filter")
2618 N_("Issue LDAP search by DN"),
2620 " Issue LDAP search by DN")
2626 N_("Issue LDAP search by SID"),
2628 " Issue LDAP search by SID")
2634 N_("Display workgroup name"),
2635 N_("net ads workgroup\n"
2636 " Display the workgroup name")
2642 N_("Perfom CLDAP query on DC"),
2643 N_("net ads lookup\n"
2644 " Find the ADS DC using CLDAP lookups")
2650 N_("Manage local keytab file"),
2651 N_("net ads keytab\n"
2652 " Manage local keytab file")
2658 N_("Manage group policy objects"),
2660 " Manage group policy objects")
2666 N_("Manage kerberos keytab"),
2667 N_("net ads kerberos\n"
2668 " Manage kerberos keytab")
2670 {NULL, NULL, 0, NULL, NULL}
2673 return net_run_function(c, argc, argv, "net ads", func);
2678 static int net_ads_noads(void)
2680 d_fprintf(stderr, _("ADS support not compiled in\n"));
2684 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2686 return net_ads_noads();
2689 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2691 return net_ads_noads();
2694 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2696 return net_ads_noads();
2699 int net_ads_join(struct net_context *c, int argc, const char **argv)
2701 return net_ads_noads();
2704 int net_ads_user(struct net_context *c, int argc, const char **argv)
2706 return net_ads_noads();
2709 int net_ads_group(struct net_context *c, int argc, const char **argv)
2711 return net_ads_noads();
2714 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
2716 return net_ads_noads();
2719 /* this one shouldn't display a message */
2720 int net_ads_check(struct net_context *c)
2725 int net_ads_check_our_domain(struct net_context *c)
2730 int net_ads(struct net_context *c, int argc, const char **argv)
2732 return net_ads_noads();
2735 #endif /* WITH_ADS */