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"
29 #include "libads/cldap.h"
30 #include "libads/dns.h"
31 #include "../libds/common/flags.h"
32 #include "librpc/gen_ndr/libnet_join.h"
33 #include "libnet/libnet_join.h"
39 /* when we do not have sufficient input parameters to contact a remote domain
40 * we always fall back to our own realm - Guenther*/
42 static const char *assume_own_realm(struct net_context *c)
44 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
52 do a cldap netlogon query
54 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
56 char addr[INET6_ADDRSTRLEN];
57 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
59 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
60 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
61 d_fprintf(stderr, _("CLDAP query failed!\n"));
65 d_printf(_("Information for Domain Controller: %s\n\n"),
68 d_printf(_("Response Type: "));
69 switch (reply.command) {
70 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
71 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
73 case LOGON_SAM_LOGON_RESPONSE_EX:
74 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
77 d_printf("0x%x\n", reply.command);
81 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
85 "\tIs a GC of the forest: %s\n"
86 "\tIs an LDAP server: %s\n"
88 "\tIs running a KDC: %s\n"
89 "\tIs running time services: %s\n"
90 "\tIs the closest DC: %s\n"
92 "\tHas a hardware clock: %s\n"
93 "\tIs a non-domain NC serviced by LDAP server: %s\n"
94 "\tIs NT6 DC that has some secrets: %s\n"
95 "\tIs NT6 DC that has all secrets: %s\n"),
96 (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
97 (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
98 (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
99 (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
100 (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
101 (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
102 (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
103 (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
104 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
105 (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
106 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
107 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"));
110 printf(_("Forest:\t\t\t%s\n"), reply.forest);
111 printf(_("Domain:\t\t\t%s\n"), reply.dns_domain);
112 printf(_("Domain Controller:\t%s\n"), reply.pdc_dns_name);
114 printf(_("Pre-Win2k Domain:\t%s\n"), reply.domain_name);
115 printf(_("Pre-Win2k Hostname:\t%s\n"), reply.pdc_name);
117 if (*reply.user_name) printf(_("User name:\t%s\n"), reply.user_name);
119 printf(_("Server Site Name :\t\t%s\n"), reply.server_site);
120 printf(_("Client Site Name :\t\t%s\n"), reply.client_site);
122 d_printf(_("NT Version: %d\n"), reply.nt_version);
123 d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
124 d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
130 this implements the CLDAP based netlogon lookup requests
131 for finding the domain controller of a ADS domain
133 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
138 if (c->display_usage) {
143 _("Find the ADS DC using CLDAP lookup.\n"));
147 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
148 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
153 if (!ads->config.realm) {
154 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
155 ads->ldap.port = 389;
158 ret = net_ads_cldap_netlogon(c, ads);
165 static int net_ads_info(struct net_context *c, int argc, const char **argv)
168 char addr[INET6_ADDRSTRLEN];
170 if (c->display_usage) {
175 _("Display information about an Active Directory "
180 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
181 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
185 if (!ads || !ads->config.realm) {
186 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
191 /* Try to set the server's current time since we didn't do a full
192 TCP LDAP session initially */
194 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
195 d_fprintf( stderr, _("Failed to get server's current time!\n"));
198 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
200 d_printf(_("LDAP server: %s\n"), addr);
201 d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
202 d_printf(_("Realm: %s\n"), ads->config.realm);
203 d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
204 d_printf(_("LDAP port: %d\n"), ads->ldap.port);
205 d_printf(_("Server time: %s\n"),
206 http_timestring(talloc_tos(), ads->config.current_time));
208 d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
209 d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
215 static void use_in_memory_ccache(void) {
216 /* Use in-memory credentials cache so we do not interfere with
217 * existing credentials */
218 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
221 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
222 uint32 auth_flags, ADS_STRUCT **ads_ret)
224 ADS_STRUCT *ads = NULL;
226 bool need_password = false;
227 bool second_time = false;
229 const char *realm = NULL;
230 bool tried_closest_dc = false;
232 /* lp_realm() should be handled by a command line param,
233 However, the join requires that realm be set in smb.conf
234 and compares our realm with the remote server's so this is
235 ok until someone needs more flexibility */
240 if (only_own_domain) {
243 realm = assume_own_realm(c);
246 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
248 if (!c->opt_user_name) {
249 c->opt_user_name = "administrator";
252 if (c->opt_user_specified) {
253 need_password = true;
257 if (!c->opt_password && need_password && !c->opt_machine_pass) {
258 c->opt_password = net_prompt_pass(c, c->opt_user_name);
259 if (!c->opt_password) {
261 return ADS_ERROR(LDAP_NO_MEMORY);
265 if (c->opt_password) {
266 use_in_memory_ccache();
267 SAFE_FREE(ads->auth.password);
268 ads->auth.password = smb_xstrdup(c->opt_password);
271 ads->auth.flags |= auth_flags;
272 SAFE_FREE(ads->auth.user_name);
273 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
276 * If the username is of the form "name@realm",
277 * extract the realm and convert to upper case.
278 * This is only used to establish the connection.
280 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
282 SAFE_FREE(ads->auth.realm);
283 ads->auth.realm = smb_xstrdup(cp);
284 strupper_m(ads->auth.realm);
287 status = ads_connect(ads);
289 if (!ADS_ERR_OK(status)) {
291 if (NT_STATUS_EQUAL(ads_ntstatus(status),
292 NT_STATUS_NO_LOGON_SERVERS)) {
293 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
298 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
299 need_password = true;
308 /* when contacting our own domain, make sure we use the closest DC.
309 * This is done by reconnecting to ADS because only the first call to
310 * ads_connect will give us our own sitename */
312 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
314 tried_closest_dc = true; /* avoid loop */
316 if (!ads_closest_dc(ads)) {
318 namecache_delete(ads->server.realm, 0x1C);
319 namecache_delete(ads->server.workgroup, 0x1C);
332 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
334 return ads_startup_int(c, only_own_domain, 0, ads);
337 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
339 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
343 Check to see if connection can be made via ads.
344 ads_startup() stores the password in opt_password if it needs to so
345 that rpc or rap can use it without re-prompting.
347 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
352 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
356 ads->auth.flags |= ADS_AUTH_NO_BIND;
358 status = ads_connect(ads);
359 if ( !ADS_ERR_OK(status) ) {
367 int net_ads_check_our_domain(struct net_context *c)
369 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
372 int net_ads_check(struct net_context *c)
374 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
378 determine the netbios workgroup name for a domain
380 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
383 char addr[INET6_ADDRSTRLEN];
384 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
386 if (c->display_usage) {
388 "net ads workgroup\n"
391 _("Print the workgroup name"));
395 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
396 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
400 if (!ads->config.realm) {
401 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
402 ads->ldap.port = 389;
405 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
406 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
407 d_fprintf(stderr, _("CLDAP query failed!\n"));
412 d_printf(_("Workgroup: %s\n"), reply.domain_name);
421 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
423 char **disp_fields = (char **) data_area;
425 if (!field) { /* must be end of record */
426 if (disp_fields[0]) {
427 if (!strchr_m(disp_fields[0], '$')) {
429 d_printf("%-21.21s %s\n",
430 disp_fields[0], disp_fields[1]);
432 d_printf("%s\n", disp_fields[0]);
435 SAFE_FREE(disp_fields[0]);
436 SAFE_FREE(disp_fields[1]);
439 if (!values) /* must be new field, indicate string field */
441 if (StrCaseCmp(field, "sAMAccountName") == 0) {
442 disp_fields[0] = SMB_STRDUP((char *) values[0]);
444 if (StrCaseCmp(field, "description") == 0)
445 disp_fields[1] = SMB_STRDUP((char *) values[0]);
449 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
451 return net_user_usage(c, argc, argv);
454 static int ads_user_add(struct net_context *c, int argc, const char **argv)
459 LDAPMessage *res=NULL;
463 if (argc < 1 || c->display_usage)
464 return net_ads_user_usage(c, argc, argv);
466 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
470 status = ads_find_user_acct(ads, &res, argv[0]);
472 if (!ADS_ERR_OK(status)) {
473 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
477 if (ads_count_replies(ads, res)) {
478 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
483 if (c->opt_container) {
484 ou_str = SMB_STRDUP(c->opt_container);
486 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
489 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
491 if (!ADS_ERR_OK(status)) {
492 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
497 /* if no password is to be set, we're done */
499 d_printf(_("User %s added\n"), argv[0]);
504 /* try setting the password */
505 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
508 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
509 ads->auth.time_offset);
511 if (ADS_ERR_OK(status)) {
512 d_printf(_("User %s added\n"), argv[0]);
517 /* password didn't set, delete account */
518 d_fprintf(stderr, _("Could not add user %s. "
519 "Error setting password %s\n"),
520 argv[0], ads_errstr(status));
521 ads_msgfree(ads, res);
522 status=ads_find_user_acct(ads, &res, argv[0]);
523 if (ADS_ERR_OK(status)) {
524 userdn = ads_get_dn(ads, talloc_tos(), res);
525 ads_del_dn(ads, userdn);
531 ads_msgfree(ads, res);
537 static int ads_user_info(struct net_context *c, int argc, const char **argv)
539 ADS_STRUCT *ads = NULL;
541 LDAPMessage *res = NULL;
545 const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
546 char *searchstring=NULL;
550 struct dom_sid primary_group_sid;
552 enum wbcSidType type;
554 if (argc < 1 || c->display_usage) {
555 return net_ads_user_usage(c, argc, argv);
558 frame = talloc_new(talloc_tos());
563 escaped_user = escape_ldap_string(frame, argv[0]);
566 _("ads_user_info: failed to escape user %s\n"),
571 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
576 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
580 rc = ads_search(ads, &res, searchstring, attrs);
581 SAFE_FREE(searchstring);
583 if (!ADS_ERR_OK(rc)) {
584 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(rc));
589 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
590 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
595 rc = ads_domain_sid(ads, &primary_group_sid);
596 if (!ADS_ERR_OK(rc)) {
597 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(rc));
602 sid_append_rid(&primary_group_sid, group_rid);
604 wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
605 NULL, /* don't look up domain */
608 if (!WBC_ERROR_IS_OK(wbc_status)) {
609 d_fprintf(stderr, "wbcLookupSid: %s\n",
610 wbcErrorString(wbc_status));
615 d_printf("%s\n", primary_group);
617 wbcFreeMemory(primary_group);
619 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
620 (LDAPMessage *)res, "memberOf");
625 for (i=0;grouplist[i];i++) {
626 groupname = ldap_explode_dn(grouplist[i], 1);
627 d_printf("%s\n", groupname[0]);
628 ldap_value_free(groupname);
630 ldap_value_free(grouplist);
634 if (res) ads_msgfree(ads, res);
635 if (ads) ads_destroy(&ads);
640 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
644 LDAPMessage *res = NULL;
648 return net_ads_user_usage(c, argc, argv);
651 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
655 rc = ads_find_user_acct(ads, &res, argv[0]);
656 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
657 d_printf(_("User %s does not exist.\n"), argv[0]);
658 ads_msgfree(ads, res);
662 userdn = ads_get_dn(ads, talloc_tos(), res);
663 ads_msgfree(ads, res);
664 rc = ads_del_dn(ads, userdn);
666 if (ADS_ERR_OK(rc)) {
667 d_printf(_("User %s deleted\n"), argv[0]);
671 d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
677 int net_ads_user(struct net_context *c, int argc, const char **argv)
679 struct functable func[] = {
684 N_("Add an AD user"),
685 N_("net ads user add\n"
692 N_("Display information about an AD user"),
693 N_("net ads user info\n"
694 " Display information about an AD user")
700 N_("Delete an AD user"),
701 N_("net ads user delete\n"
702 " Delete an AD user")
704 {NULL, NULL, 0, NULL, NULL}
708 const char *shortattrs[] = {"sAMAccountName", NULL};
709 const char *longattrs[] = {"sAMAccountName", "description", NULL};
710 char *disp_fields[2] = {NULL, NULL};
713 if (c->display_usage) {
719 net_display_usage_from_functable(func);
723 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
727 if (c->opt_long_list_entries)
728 d_printf(_("\nUser name Comment"
729 "\n-----------------------------\n"));
731 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
733 "(objectCategory=user)",
734 c->opt_long_list_entries ? longattrs :
735 shortattrs, usergrp_display,
738 return ADS_ERR_OK(rc) ? 0 : -1;
741 return net_run_function(c, argc, argv, "net ads user", func);
744 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
746 return net_group_usage(c, argc, argv);
749 static int ads_group_add(struct net_context *c, int argc, const char **argv)
753 LDAPMessage *res=NULL;
757 if (argc < 1 || c->display_usage) {
758 return net_ads_group_usage(c, argc, argv);
761 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
765 status = ads_find_user_acct(ads, &res, argv[0]);
767 if (!ADS_ERR_OK(status)) {
768 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
772 if (ads_count_replies(ads, res)) {
773 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
777 if (c->opt_container) {
778 ou_str = SMB_STRDUP(c->opt_container);
780 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
783 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
785 if (ADS_ERR_OK(status)) {
786 d_printf(_("Group %s added\n"), argv[0]);
789 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
795 ads_msgfree(ads, res);
801 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
805 LDAPMessage *res = NULL;
808 if (argc < 1 || c->display_usage) {
809 return net_ads_group_usage(c, argc, argv);
812 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
816 rc = ads_find_user_acct(ads, &res, argv[0]);
817 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
818 d_printf(_("Group %s does not exist.\n"), argv[0]);
819 ads_msgfree(ads, res);
823 groupdn = ads_get_dn(ads, talloc_tos(), res);
824 ads_msgfree(ads, res);
825 rc = ads_del_dn(ads, groupdn);
826 TALLOC_FREE(groupdn);
827 if (ADS_ERR_OK(rc)) {
828 d_printf(_("Group %s deleted\n"), argv[0]);
832 d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
838 int net_ads_group(struct net_context *c, int argc, const char **argv)
840 struct functable func[] = {
845 N_("Add an AD group"),
846 N_("net ads group add\n"
853 N_("Delete an AD group"),
854 N_("net ads group delete\n"
855 " Delete an AD group")
857 {NULL, NULL, 0, NULL, NULL}
861 const char *shortattrs[] = {"sAMAccountName", NULL};
862 const char *longattrs[] = {"sAMAccountName", "description", NULL};
863 char *disp_fields[2] = {NULL, NULL};
866 if (c->display_usage) {
871 _("List AD groups"));
872 net_display_usage_from_functable(func);
876 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
880 if (c->opt_long_list_entries)
881 d_printf(_("\nGroup name Comment"
882 "\n-----------------------------\n"));
883 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
885 "(objectCategory=group)",
886 c->opt_long_list_entries ? longattrs :
887 shortattrs, usergrp_display,
891 return ADS_ERR_OK(rc) ? 0 : -1;
893 return net_run_function(c, argc, argv, "net ads group", func);
896 static int net_ads_status(struct net_context *c, int argc, const char **argv)
902 if (c->display_usage) {
907 _("Display machine account details"));
911 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
915 rc = ads_find_machine_acct(ads, &res, global_myname());
916 if (!ADS_ERR_OK(rc)) {
917 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
922 if (ads_count_replies(ads, res) == 0) {
923 d_fprintf(stderr, _("No machine account for '%s' found\n"), global_myname());
933 /*******************************************************************
934 Leave an AD domain. Windows XP disables the machine account.
935 We'll try the same. The old code would do an LDAP delete.
936 That only worked using the machine creds because added the machine
937 with full control to the computer object's ACL.
938 *******************************************************************/
940 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
943 struct libnet_UnjoinCtx *r = NULL;
946 if (c->display_usage) {
951 _("Leave an AD domain"));
956 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
960 if (!(ctx = talloc_init("net_ads_leave"))) {
961 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
965 if (!c->opt_kerberos) {
966 use_in_memory_ccache();
969 werr = libnet_init_UnjoinCtx(ctx, &r);
970 if (!W_ERROR_IS_OK(werr)) {
971 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
976 r->in.use_kerberos = c->opt_kerberos;
977 r->in.dc_name = c->opt_host;
978 r->in.domain_name = lp_realm();
979 r->in.admin_account = c->opt_user_name;
980 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
981 r->in.modify_config = lp_config_backend_is_registry();
983 /* Try to delete it, but if that fails, disable it. The
984 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
985 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
986 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
987 r->in.delete_machine_account = true;
989 werr = libnet_Unjoin(ctx, r);
990 if (!W_ERROR_IS_OK(werr)) {
991 d_printf(_("Failed to leave domain: %s\n"),
992 r->out.error_string ? r->out.error_string :
993 get_friendly_werror_msg(werr));
997 if (r->out.deleted_machine_account) {
998 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
999 r->in.machine_name, r->out.dns_domain_name);
1003 /* We couldn't delete it - see if the disable succeeded. */
1004 if (r->out.disabled_machine_account) {
1005 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1006 r->in.machine_name, r->out.dns_domain_name);
1011 /* Based on what we requseted, we shouldn't get here, but if
1012 we did, it means the secrets were removed, and therefore
1013 we have left the domain */
1014 d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1015 r->in.machine_name, r->out.dns_domain_name);
1021 if (W_ERROR_IS_OK(werr)) {
1028 static NTSTATUS net_ads_join_ok(struct net_context *c)
1030 ADS_STRUCT *ads = NULL;
1033 struct sockaddr_storage dcip;
1035 if (!secrets_init()) {
1036 DEBUG(1,("Failed to initialise secrets database\n"));
1037 return NT_STATUS_ACCESS_DENIED;
1040 net_use_krb_machine_account(c);
1042 get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1044 status = ads_startup(c, true, &ads);
1045 if (!ADS_ERR_OK(status)) {
1046 return ads_ntstatus(status);
1050 return NT_STATUS_OK;
1054 check that an existing join is OK
1056 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1059 use_in_memory_ccache();
1061 if (c->display_usage) {
1063 "net ads testjoin\n"
1066 _("Test if the existing join is ok"));
1070 /* Display success or failure */
1071 status = net_ads_join_ok(c);
1072 if (!NT_STATUS_IS_OK(status)) {
1073 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1074 get_friendly_nt_error_msg(status));
1078 printf(_("Join is OK\n"));
1082 /*******************************************************************
1083 Simple configu checks before beginning the join
1084 ********************************************************************/
1086 static WERROR check_ads_config( void )
1088 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1089 d_printf(_("Host is not configured as a member server.\n"));
1090 return WERR_INVALID_DOMAIN_ROLE;
1093 if (strlen(global_myname()) > 15) {
1094 d_printf(_("Our netbios name can be at most 15 chars long, "
1095 "\"%s\" is %u chars long\n"), global_myname(),
1096 (unsigned int)strlen(global_myname()));
1097 return WERR_INVALID_COMPUTERNAME;
1100 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1101 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1102 "join to succeed.\n"), get_dyn_CONFIGFILE());
1103 return WERR_INVALID_PARAM;
1109 /*******************************************************************
1110 Send a DNS update request
1111 *******************************************************************/
1113 #if defined(WITH_DNS_UPDATES)
1115 DNS_ERROR DoDNSUpdate(char *pszServerName,
1116 const char *pszDomainName, const char *pszHostName,
1117 const struct sockaddr_storage *sslist,
1120 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1121 const char *machine_name,
1122 const struct sockaddr_storage *addrs,
1125 struct dns_rr_ns *nameservers = NULL;
1127 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1130 const char *dnsdomain = NULL;
1131 char *root_domain = NULL;
1133 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1134 d_printf(_("No DNS domain configured for %s. "
1135 "Unable to perform DNS Update.\n"), machine_name);
1136 status = NT_STATUS_INVALID_PARAMETER;
1141 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1142 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1143 /* Child domains often do not have NS records. Look
1144 for the NS record for the forest root domain
1145 (rootDomainNamingContext in therootDSE) */
1147 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1148 LDAPMessage *msg = NULL;
1150 ADS_STATUS ads_status;
1152 if ( !ads->ldap.ld ) {
1153 ads_status = ads_connect( ads );
1154 if ( !ADS_ERR_OK(ads_status) ) {
1155 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1160 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1161 "(objectclass=*)", rootname_attrs, &msg);
1162 if (!ADS_ERR_OK(ads_status)) {
1166 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1168 ads_msgfree( ads, msg );
1172 root_domain = ads_build_domain( root_dn );
1175 ads_msgfree( ads, msg );
1177 /* try again for NS servers */
1179 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1181 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1182 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1183 "realm\n", ads->config.realm));
1187 dnsdomain = root_domain;
1191 /* Now perform the dns update - we'll try non-secure and if we fail,
1192 we'll follow it up with a secure update */
1194 fstrcpy( dns_server, nameservers[0].hostname );
1196 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1197 if (!ERR_DNS_IS_OK(dns_err)) {
1198 status = NT_STATUS_UNSUCCESSFUL;
1203 SAFE_FREE( root_domain );
1208 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1211 struct sockaddr_storage *iplist = NULL;
1212 fstring machine_name;
1215 name_to_fqdn( machine_name, global_myname() );
1216 strlower_m( machine_name );
1218 /* Get our ip address (not the 127.0.0.x address but a real ip
1221 num_addrs = get_my_ip_address( &iplist );
1222 if ( num_addrs <= 0 ) {
1223 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1225 return NT_STATUS_INVALID_PARAMETER;
1228 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1230 SAFE_FREE( iplist );
1236 /*******************************************************************
1237 ********************************************************************/
1239 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1241 d_printf(_("net ads join [options]\n"
1242 "Valid options:\n"));
1243 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1244 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1245 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1246 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1247 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1248 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1249 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1250 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1251 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1252 " NB: osName and osVer must be specified together for either to take effect.\n"
1253 " Also, the operatingSystemService attribute is also set when along with\n"
1254 " the two other attributes.\n"));
1259 /*******************************************************************
1260 ********************************************************************/
1262 int net_ads_join(struct net_context *c, int argc, const char **argv)
1264 TALLOC_CTX *ctx = NULL;
1265 struct libnet_JoinCtx *r = NULL;
1266 const char *domain = lp_realm();
1267 WERROR werr = WERR_SETUP_NOT_JOINED;
1268 bool createupn = false;
1269 const char *machineupn = NULL;
1270 const char *create_in_ou = NULL;
1272 const char *os_name = NULL;
1273 const char *os_version = NULL;
1274 bool modify_config = lp_config_backend_is_registry();
1276 if (c->display_usage)
1277 return net_ads_join_usage(c, argc, argv);
1279 if (!modify_config) {
1281 werr = check_ads_config();
1282 if (!W_ERROR_IS_OK(werr)) {
1283 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1288 if (!(ctx = talloc_init("net_ads_join"))) {
1289 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1294 if (!c->opt_kerberos) {
1295 use_in_memory_ccache();
1298 werr = libnet_init_JoinCtx(ctx, &r);
1299 if (!W_ERROR_IS_OK(werr)) {
1303 /* process additional command line args */
1305 for ( i=0; i<argc; i++ ) {
1306 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1308 machineupn = get_string_param(argv[i]);
1310 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1311 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1312 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1313 werr = WERR_INVALID_PARAM;
1317 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1318 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1319 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1320 werr = WERR_INVALID_PARAM;
1324 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1325 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1326 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1327 werr = WERR_INVALID_PARAM;
1337 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1338 werr = WERR_INVALID_PARAM;
1342 /* Do the domain join here */
1344 r->in.domain_name = domain;
1345 r->in.create_upn = createupn;
1346 r->in.upn = machineupn;
1347 r->in.account_ou = create_in_ou;
1348 r->in.os_name = os_name;
1349 r->in.os_version = os_version;
1350 r->in.dc_name = c->opt_host;
1351 r->in.admin_account = c->opt_user_name;
1352 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1354 r->in.use_kerberos = c->opt_kerberos;
1355 r->in.modify_config = modify_config;
1356 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1357 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1358 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1360 werr = libnet_Join(ctx, r);
1361 if (!W_ERROR_IS_OK(werr)) {
1365 /* Check the short name of the domain */
1367 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1368 d_printf(_("The workgroup in %s does not match the short\n"
1369 "domain name obtained from the server.\n"
1370 "Using the name [%s] from the server.\n"
1371 "You should set \"workgroup = %s\" in %s.\n"),
1372 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1373 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1376 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1378 if (r->out.dns_domain_name) {
1379 d_printf(_("Joined '%s' to realm '%s'\n"), r->in.machine_name,
1380 r->out.dns_domain_name);
1382 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1383 r->out.netbios_domain_name);
1386 #if defined(WITH_DNS_UPDATES)
1387 if (r->out.domain_is_ad) {
1388 /* We enter this block with user creds */
1389 ADS_STRUCT *ads_dns = NULL;
1391 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1392 /* kinit with the machine password */
1394 use_in_memory_ccache();
1395 if (asprintf( &ads_dns->auth.user_name, "%s$", global_myname()) == -1) {
1398 ads_dns->auth.password = secrets_fetch_machine_password(
1399 r->out.netbios_domain_name, NULL, NULL );
1400 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1401 strupper_m(ads_dns->auth.realm );
1402 ads_kinit_password( ads_dns );
1405 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1406 d_fprintf( stderr, _("DNS update failed!\n") );
1409 /* exit from this block using machine creds */
1410 ads_destroy(&ads_dns);
1419 /* issue an overall failure message at the end. */
1420 d_printf(_("Failed to join domain: %s\n"),
1421 r && r->out.error_string ? r->out.error_string :
1422 get_friendly_werror_msg(werr));
1428 /*******************************************************************
1429 ********************************************************************/
1431 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1433 #if defined(WITH_DNS_UPDATES)
1439 talloc_enable_leak_report();
1442 if (argc > 0 || c->display_usage) {
1444 "net ads dns register\n"
1447 _("Register hostname with DNS\n"));
1451 if (!(ctx = talloc_init("net_ads_dns"))) {
1452 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1456 status = ads_startup(c, true, &ads);
1457 if ( !ADS_ERR_OK(status) ) {
1458 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1463 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1464 d_fprintf( stderr, _("DNS update failed!\n") );
1465 ads_destroy( &ads );
1470 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1478 _("DNS update support not enabled at compile time!\n"));
1483 #if defined(WITH_DNS_UPDATES)
1484 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1487 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1489 #if defined(WITH_DNS_UPDATES)
1493 talloc_enable_leak_report();
1496 if (argc != 2 || c->display_usage) {
1501 _("net ads dns gethostbyname <server> <name>\n"),
1502 _(" Look up hostname from the AD\n"
1503 " server\tName server to use\n"
1504 " name\tName to look up\n"));
1508 err = do_gethostbyname(argv[0], argv[1]);
1510 d_printf(_("do_gethostbyname returned %d\n"), ERROR_DNS_V(err));
1515 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1517 struct functable func[] = {
1520 net_ads_dns_register,
1522 N_("Add host dns entry to AD"),
1523 N_("net ads dns register\n"
1524 " Add host dns entry to AD")
1528 net_ads_dns_gethostbyname,
1531 N_("net ads dns gethostbyname\n"
1534 {NULL, NULL, 0, NULL, NULL}
1537 return net_run_function(c, argc, argv, "net ads dns", func);
1540 /*******************************************************************
1541 ********************************************************************/
1543 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1546 "\nnet ads printer search <printer>"
1547 "\n\tsearch for a printer in the directory\n"
1548 "\nnet ads printer info <printer> <server>"
1549 "\n\tlookup info in directory for printer on server"
1550 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1551 "\nnet ads printer publish <printername>"
1552 "\n\tpublish printer in directory"
1553 "\n\t(note: printer name is required)\n"
1554 "\nnet ads printer remove <printername>"
1555 "\n\tremove printer from directory"
1556 "\n\t(note: printer name is required)\n"));
1560 /*******************************************************************
1561 ********************************************************************/
1563 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1567 LDAPMessage *res = NULL;
1569 if (c->display_usage) {
1571 "net ads printer search\n"
1574 _("List printers in the AD"));
1578 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1582 rc = ads_find_printers(ads, &res);
1584 if (!ADS_ERR_OK(rc)) {
1585 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
1586 ads_msgfree(ads, res);
1591 if (ads_count_replies(ads, res) == 0) {
1592 d_fprintf(stderr, _("No results found\n"));
1593 ads_msgfree(ads, res);
1599 ads_msgfree(ads, res);
1604 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1608 const char *servername, *printername;
1609 LDAPMessage *res = NULL;
1611 if (c->display_usage) {
1614 _("net ads printer info [printername [servername]]\n"
1615 " Display printer info from AD\n"
1616 " printername\tPrinter name or wildcard\n"
1617 " servername\tName of the print server\n"));
1621 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1626 printername = argv[0];
1632 servername = argv[1];
1634 servername = global_myname();
1637 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1639 if (!ADS_ERR_OK(rc)) {
1640 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
1641 servername, ads_errstr(rc));
1642 ads_msgfree(ads, res);
1647 if (ads_count_replies(ads, res) == 0) {
1648 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
1649 ads_msgfree(ads, res);
1655 ads_msgfree(ads, res);
1661 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1665 const char *servername, *printername;
1666 struct cli_state *cli = NULL;
1667 struct rpc_pipe_client *pipe_hnd = NULL;
1668 struct sockaddr_storage server_ss;
1670 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1671 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1672 char *prt_dn, *srv_dn, **srv_cn;
1673 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1674 LDAPMessage *res = NULL;
1676 if (argc < 1 || c->display_usage) {
1679 _("net ads printer publish <printername> [servername]\n"
1680 " Publish printer in AD\n"
1681 " printername\tName of the printer\n"
1682 " servername\tName of the print server\n"));
1683 talloc_destroy(mem_ctx);
1687 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1688 talloc_destroy(mem_ctx);
1692 printername = argv[0];
1695 servername = argv[1];
1697 servername = global_myname();
1700 /* Get printer data from SPOOLSS */
1702 resolve_name(servername, &server_ss, 0x20, false);
1704 nt_status = cli_full_connection(&cli, global_myname(), servername,
1707 c->opt_user_name, c->opt_workgroup,
1708 c->opt_password ? c->opt_password : "",
1709 CLI_FULL_CONNECTION_USE_KERBEROS,
1712 if (NT_STATUS_IS_ERR(nt_status)) {
1713 d_fprintf(stderr, _("Unable to open a connnection to %s to "
1714 "obtain data for %s\n"),
1715 servername, printername);
1717 talloc_destroy(mem_ctx);
1721 /* Publish on AD server */
1723 ads_find_machine_acct(ads, &res, servername);
1725 if (ads_count_replies(ads, res) == 0) {
1726 d_fprintf(stderr, _("Could not find machine account for server "
1730 talloc_destroy(mem_ctx);
1734 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1735 srv_cn = ldap_explode_dn(srv_dn, 1);
1737 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1738 printername_escaped = escape_rdn_val_string_alloc(printername);
1739 if (!srv_cn_escaped || !printername_escaped) {
1740 SAFE_FREE(srv_cn_escaped);
1741 SAFE_FREE(printername_escaped);
1742 d_fprintf(stderr, _("Internal error, out of memory!"));
1744 talloc_destroy(mem_ctx);
1748 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1749 SAFE_FREE(srv_cn_escaped);
1750 SAFE_FREE(printername_escaped);
1751 d_fprintf(stderr, _("Internal error, out of memory!"));
1753 talloc_destroy(mem_ctx);
1757 SAFE_FREE(srv_cn_escaped);
1758 SAFE_FREE(printername_escaped);
1760 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
1761 if (!NT_STATUS_IS_OK(nt_status)) {
1762 d_fprintf(stderr, _("Unable to open a connnection to the spoolss pipe on %s\n"),
1766 talloc_destroy(mem_ctx);
1770 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1774 talloc_destroy(mem_ctx);
1778 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1779 if (!ADS_ERR_OK(rc)) {
1780 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1783 talloc_destroy(mem_ctx);
1787 d_printf("published printer\n");
1790 talloc_destroy(mem_ctx);
1795 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1799 const char *servername;
1801 LDAPMessage *res = NULL;
1803 if (argc < 1 || c->display_usage) {
1806 _("net ads printer remove <printername> [servername]\n"
1807 " Remove a printer from the AD\n"
1808 " printername\tName of the printer\n"
1809 " servername\tName of the print server\n"));
1813 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1818 servername = argv[1];
1820 servername = global_myname();
1823 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1825 if (!ADS_ERR_OK(rc)) {
1826 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
1827 ads_msgfree(ads, res);
1832 if (ads_count_replies(ads, res) == 0) {
1833 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
1834 ads_msgfree(ads, res);
1839 prt_dn = ads_get_dn(ads, talloc_tos(), res);
1840 ads_msgfree(ads, res);
1841 rc = ads_del_dn(ads, prt_dn);
1842 TALLOC_FREE(prt_dn);
1844 if (!ADS_ERR_OK(rc)) {
1845 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
1854 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1856 struct functable func[] = {
1859 net_ads_printer_search,
1861 N_("Search for a printer"),
1862 N_("net ads printer search\n"
1863 " Search for a printer")
1867 net_ads_printer_info,
1869 N_("Display printer information"),
1870 N_("net ads printer info\n"
1871 " Display printer information")
1875 net_ads_printer_publish,
1877 N_("Publish a printer"),
1878 N_("net ads printer publish\n"
1879 " Publish a printer")
1883 net_ads_printer_remove,
1885 N_("Delete a printer"),
1886 N_("net ads printer remove\n"
1887 " Delete a printer")
1889 {NULL, NULL, 0, NULL, NULL}
1892 return net_run_function(c, argc, argv, "net ads printer", func);
1896 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1899 const char *auth_principal = c->opt_user_name;
1900 const char *auth_password = c->opt_password;
1902 char *new_password = NULL;
1907 if (c->display_usage) {
1910 _("net ads password <username>\n"
1911 " Change password for user\n"
1912 " username\tName of user to change password for\n"));
1916 if (c->opt_user_name == NULL || c->opt_password == NULL) {
1917 d_fprintf(stderr, _("You must supply an administrator "
1918 "username/password\n"));
1923 d_fprintf(stderr, _("ERROR: You must say which username to "
1924 "change password for\n"));
1929 if (!strchr_m(user, '@')) {
1930 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
1936 use_in_memory_ccache();
1937 chr = strchr_m(auth_principal, '@');
1944 /* use the realm so we can eventually change passwords for users
1945 in realms other than default */
1946 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1950 /* we don't actually need a full connect, but it's the easy way to
1951 fill in the KDC's addresss */
1954 if (!ads->config.realm) {
1955 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
1961 new_password = (char *)argv[1];
1963 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
1966 new_password = getpass(prompt);
1970 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1971 auth_password, user, new_password, ads->auth.time_offset);
1972 if (!ADS_ERR_OK(ret)) {
1973 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
1978 d_printf(_("Password change for %s completed.\n"), user);
1984 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1987 char *host_principal;
1991 if (c->display_usage) {
1993 "net ads changetrustpw\n"
1996 _("Change the machine account's trust password"));
2000 if (!secrets_init()) {
2001 DEBUG(1,("Failed to initialise secrets database\n"));
2005 net_use_krb_machine_account(c);
2007 use_in_memory_ccache();
2009 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2013 fstrcpy(my_name, global_myname());
2014 strlower_m(my_name);
2015 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2019 d_printf(_("Changing password for principal: %s\n"), host_principal);
2021 ret = ads_change_trust_account_password(ads, host_principal);
2023 if (!ADS_ERR_OK(ret)) {
2024 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2026 SAFE_FREE(host_principal);
2030 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2032 if (USE_SYSTEM_KEYTAB) {
2033 d_printf(_("Attempting to update system keytab with new password.\n"));
2034 if (ads_keytab_create_default(ads)) {
2035 d_printf(_("Failed to update system keytab.\n"));
2040 SAFE_FREE(host_principal);
2046 help for net ads search
2048 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2051 "\nnet ads search <expression> <attributes...>\n"
2052 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2053 "The expression is a standard LDAP search expression, and the\n"
2054 "attributes are a list of LDAP fields to show in the results.\n\n"
2055 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2057 net_common_flags_usage(c, argc, argv);
2063 general ADS search function. Useful in diagnosing problems in ADS
2065 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2069 const char *ldap_exp;
2071 LDAPMessage *res = NULL;
2073 if (argc < 1 || c->display_usage) {
2074 return net_ads_search_usage(c, argc, argv);
2077 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2084 rc = ads_do_search_all(ads, ads->config.bind_path,
2086 ldap_exp, attrs, &res);
2087 if (!ADS_ERR_OK(rc)) {
2088 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2093 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2095 /* dump the results */
2098 ads_msgfree(ads, res);
2106 help for net ads search
2108 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2111 "\nnet ads dn <dn> <attributes...>\n"
2112 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2113 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2114 "to show in the results\n\n"
2115 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2116 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2118 net_common_flags_usage(c, argc, argv);
2124 general ADS search function. Useful in diagnosing problems in ADS
2126 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2132 LDAPMessage *res = NULL;
2134 if (argc < 1 || c->display_usage) {
2135 return net_ads_dn_usage(c, argc, argv);
2138 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2145 rc = ads_do_search_all(ads, dn,
2147 "(objectclass=*)", attrs, &res);
2148 if (!ADS_ERR_OK(rc)) {
2149 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2154 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2156 /* dump the results */
2159 ads_msgfree(ads, res);
2166 help for net ads sid search
2168 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2171 "\nnet ads sid <sid> <attributes...>\n"
2172 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2173 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2174 "to show in the results\n\n"
2175 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2177 net_common_flags_usage(c, argc, argv);
2183 general ADS search function. Useful in diagnosing problems in ADS
2185 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2189 const char *sid_string;
2191 LDAPMessage *res = NULL;
2194 if (argc < 1 || c->display_usage) {
2195 return net_ads_sid_usage(c, argc, argv);
2198 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2202 sid_string = argv[0];
2205 if (!string_to_sid(&sid, sid_string)) {
2206 d_fprintf(stderr, _("could not convert sid\n"));
2211 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2212 if (!ADS_ERR_OK(rc)) {
2213 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2218 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2220 /* dump the results */
2223 ads_msgfree(ads, res);
2229 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2234 if (c->display_usage) {
2236 "net ads keytab flush\n"
2239 _("Delete the whole keytab"));
2243 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2246 ret = ads_keytab_flush(ads);
2251 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2257 if (c->display_usage) {
2260 _("net ads keytab add <principal> [principal ...]\n"
2261 " Add principals to local keytab\n"
2262 " principal\tKerberos principal to add to "
2267 d_printf(_("Processing principals to add...\n"));
2268 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2271 for (i = 0; i < argc; i++) {
2272 ret |= ads_keytab_add_entry(ads, argv[i]);
2278 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2283 if (c->display_usage) {
2285 "net ads keytab create\n"
2288 _("Create new default keytab"));
2292 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2295 ret = ads_keytab_create_default(ads);
2300 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2302 const char *keytab = NULL;
2304 if (c->display_usage) {
2307 _("net ads keytab list [keytab]\n"
2308 " List a local keytab\n"
2309 " keytab\tKeytab to list\n"));
2317 return ads_keytab_list(keytab);
2321 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2323 struct functable func[] = {
2328 N_("Add a service principal"),
2329 N_("net ads keytab add\n"
2330 " Add a service principal")
2334 net_ads_keytab_create,
2336 N_("Create a fresh keytab"),
2337 N_("net ads keytab create\n"
2338 " Create a fresh keytab")
2342 net_ads_keytab_flush,
2344 N_("Remove all keytab entries"),
2345 N_("net ads keytab flush\n"
2346 " Remove all keytab entries")
2350 net_ads_keytab_list,
2352 N_("List a keytab"),
2353 N_("net ads keytab list\n"
2356 {NULL, NULL, 0, NULL, NULL}
2359 if (!USE_KERBEROS_KEYTAB) {
2360 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2361 "keytab method to use keytab functions.\n"));
2364 return net_run_function(c, argc, argv, "net ads keytab", func);
2367 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2371 if (c->display_usage) {
2373 "net ads kerberos renew\n"
2376 _("Renew TGT from existing credential cache"));
2380 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2382 d_printf(_("failed to renew kerberos ticket: %s\n"),
2383 error_message(ret));
2388 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2390 struct PAC_LOGON_INFO *info = NULL;
2391 TALLOC_CTX *mem_ctx = NULL;
2394 const char *impersonate_princ_s = NULL;
2396 if (c->display_usage) {
2398 "net ads kerberos pac\n"
2401 _("Dump the Kerberos PAC"));
2405 mem_ctx = talloc_init("net_ads_kerberos_pac");
2411 impersonate_princ_s = argv[0];
2414 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2416 status = kerberos_return_pac(mem_ctx,
2425 2592000, /* one month */
2426 impersonate_princ_s,
2428 if (!NT_STATUS_IS_OK(status)) {
2429 d_printf(_("failed to query kerberos PAC: %s\n"),
2436 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2437 d_printf(_("The Pac: %s\n"), s);
2442 TALLOC_FREE(mem_ctx);
2446 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2448 TALLOC_CTX *mem_ctx = NULL;
2452 if (c->display_usage) {
2454 "net ads kerberos kinit\n"
2457 _("Get Ticket Granting Ticket (TGT) for the user"));
2461 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2466 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2468 ret = kerberos_kinit_password_ext(c->opt_user_name,
2476 2592000, /* one month */
2479 d_printf(_("failed to kinit password: %s\n"),
2486 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2488 struct functable func[] = {
2491 net_ads_kerberos_kinit,
2493 N_("Retrieve Ticket Granting Ticket (TGT)"),
2494 N_("net ads kerberos kinit\n"
2495 " Receive Ticket Granting Ticket (TGT)")
2499 net_ads_kerberos_renew,
2501 N_("Renew Ticket Granting Ticket from credential cache"),
2502 N_("net ads kerberos renew\n"
2503 " Renew Ticket Granting Ticket (TGT) from "
2508 net_ads_kerberos_pac,
2510 N_("Dump Kerberos PAC"),
2511 N_("net ads kerberos pac\n"
2512 " Dump Kerberos PAC")
2514 {NULL, NULL, 0, NULL, NULL}
2517 return net_run_function(c, argc, argv, "net ads kerberos", func);
2520 int net_ads(struct net_context *c, int argc, const char **argv)
2522 struct functable func[] = {
2527 N_("Display details on remote ADS server"),
2529 " Display details on remote ADS server")
2535 N_("Join the local machine to ADS realm"),
2537 " Join the local machine to ADS realm")
2543 N_("Validate machine account"),
2544 N_("net ads testjoin\n"
2545 " Validate machine account")
2551 N_("Remove the local machine from ADS"),
2552 N_("net ads leave\n"
2553 " Remove the local machine from ADS")
2559 N_("Display machine account details"),
2560 N_("net ads status\n"
2561 " Display machine account details")
2567 N_("List/modify users"),
2569 " List/modify users")
2575 N_("List/modify groups"),
2576 N_("net ads group\n"
2577 " List/modify groups")
2583 N_("Issue dynamic DNS update"),
2585 " Issue dynamic DNS update")
2591 N_("Change user passwords"),
2592 N_("net ads password\n"
2593 " Change user passwords")
2597 net_ads_changetrustpw,
2599 N_("Change trust account password"),
2600 N_("net ads changetrustpw\n"
2601 " Change trust account password")
2607 N_("List/modify printer entries"),
2608 N_("net ads printer\n"
2609 " List/modify printer entries")
2615 N_("Issue LDAP search using filter"),
2616 N_("net ads search\n"
2617 " Issue LDAP search using filter")
2623 N_("Issue LDAP search by DN"),
2625 " Issue LDAP search by DN")
2631 N_("Issue LDAP search by SID"),
2633 " Issue LDAP search by SID")
2639 N_("Display workgroup name"),
2640 N_("net ads workgroup\n"
2641 " Display the workgroup name")
2647 N_("Perfom CLDAP query on DC"),
2648 N_("net ads lookup\n"
2649 " Find the ADS DC using CLDAP lookups")
2655 N_("Manage local keytab file"),
2656 N_("net ads keytab\n"
2657 " Manage local keytab file")
2663 N_("Manage group policy objects"),
2665 " Manage group policy objects")
2671 N_("Manage kerberos keytab"),
2672 N_("net ads kerberos\n"
2673 " Manage kerberos keytab")
2675 {NULL, NULL, 0, NULL, NULL}
2678 return net_run_function(c, argc, argv, "net ads", func);
2683 static int net_ads_noads(void)
2685 d_fprintf(stderr, _("ADS support not compiled in\n"));
2689 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2691 return net_ads_noads();
2694 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2696 return net_ads_noads();
2699 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2701 return net_ads_noads();
2704 int net_ads_join(struct net_context *c, int argc, const char **argv)
2706 return net_ads_noads();
2709 int net_ads_user(struct net_context *c, int argc, const char **argv)
2711 return net_ads_noads();
2714 int net_ads_group(struct net_context *c, int argc, const char **argv)
2716 return net_ads_noads();
2719 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
2721 return net_ads_noads();
2724 /* this one shouldn't display a message */
2725 int net_ads_check(struct net_context *c)
2730 int net_ads_check_our_domain(struct net_context *c)
2735 int net_ads(struct net_context *c, int argc, const char **argv)
2737 return net_ads_noads();
2740 #endif /* WITH_ADS */