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"
32 /* when we do not have sufficient input parameters to contact a remote domain
33 * we always fall back to our own realm - Guenther*/
35 static const char *assume_own_realm(struct net_context *c)
37 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
45 do a cldap netlogon query
47 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
49 char addr[INET6_ADDRSTRLEN];
50 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
52 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
53 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
54 d_fprintf(stderr, _("CLDAP query failed!\n"));
58 d_printf(_("Information for Domain Controller: %s\n\n"),
61 d_printf(_("Response Type: "));
62 switch (reply.command) {
63 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
64 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
66 case LOGON_SAM_LOGON_RESPONSE_EX:
67 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
70 d_printf("0x%x\n", reply.command);
74 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
78 "\tIs a GC of the forest: %s\n"
79 "\tIs an LDAP server: %s\n"
81 "\tIs running a KDC: %s\n"
82 "\tIs running time services: %s\n"
83 "\tIs the closest DC: %s\n"
85 "\tHas a hardware clock: %s\n"
86 "\tIs a non-domain NC serviced by LDAP server: %s\n"
87 "\tIs NT6 DC that has some secrets: %s\n"
88 "\tIs NT6 DC that has all secrets: %s\n"),
89 (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
90 (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
91 (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
92 (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
93 (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
94 (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
95 (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
96 (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
97 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
98 (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
99 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
100 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"));
103 printf(_("Forest:\t\t\t%s\n"), reply.forest);
104 printf(_("Domain:\t\t\t%s\n"), reply.dns_domain);
105 printf(_("Domain Controller:\t%s\n"), reply.pdc_dns_name);
107 printf(_("Pre-Win2k Domain:\t%s\n"), reply.domain_name);
108 printf(_("Pre-Win2k Hostname:\t%s\n"), reply.pdc_name);
110 if (*reply.user_name) printf(_("User name:\t%s\n"), reply.user_name);
112 printf(_("Server Site Name :\t\t%s\n"), reply.server_site);
113 printf(_("Client Site Name :\t\t%s\n"), reply.client_site);
115 d_printf(_("NT Version: %d\n"), reply.nt_version);
116 d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
117 d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
123 this implements the CLDAP based netlogon lookup requests
124 for finding the domain controller of a ADS domain
126 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
131 if (c->display_usage) {
136 _("Find the ADS DC using CLDAP lookup.\n"));
140 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
141 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
146 if (!ads->config.realm) {
147 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
148 ads->ldap.port = 389;
151 ret = net_ads_cldap_netlogon(c, ads);
158 static int net_ads_info(struct net_context *c, int argc, const char **argv)
161 char addr[INET6_ADDRSTRLEN];
163 if (c->display_usage) {
168 _("Display information about an Active Directory "
173 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
174 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
178 if (!ads || !ads->config.realm) {
179 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
184 /* Try to set the server's current time since we didn't do a full
185 TCP LDAP session initially */
187 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
188 d_fprintf( stderr, _("Failed to get server's current time!\n"));
191 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
193 d_printf(_("LDAP server: %s\n"), addr);
194 d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
195 d_printf(_("Realm: %s\n"), ads->config.realm);
196 d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
197 d_printf(_("LDAP port: %d\n"), ads->ldap.port);
198 d_printf(_("Server time: %s\n"),
199 http_timestring(talloc_tos(), ads->config.current_time));
201 d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
202 d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
208 static void use_in_memory_ccache(void) {
209 /* Use in-memory credentials cache so we do not interfere with
210 * existing credentials */
211 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
214 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
215 uint32 auth_flags, ADS_STRUCT **ads_ret)
217 ADS_STRUCT *ads = NULL;
219 bool need_password = false;
220 bool second_time = false;
222 const char *realm = NULL;
223 bool tried_closest_dc = false;
225 /* lp_realm() should be handled by a command line param,
226 However, the join requires that realm be set in smb.conf
227 and compares our realm with the remote server's so this is
228 ok until someone needs more flexibility */
233 if (only_own_domain) {
236 realm = assume_own_realm(c);
239 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
241 if (!c->opt_user_name) {
242 c->opt_user_name = "administrator";
245 if (c->opt_user_specified) {
246 need_password = true;
250 if (!c->opt_password && need_password && !c->opt_machine_pass) {
251 c->opt_password = net_prompt_pass(c, c->opt_user_name);
252 if (!c->opt_password) {
254 return ADS_ERROR(LDAP_NO_MEMORY);
258 if (c->opt_password) {
259 use_in_memory_ccache();
260 SAFE_FREE(ads->auth.password);
261 ads->auth.password = smb_xstrdup(c->opt_password);
264 ads->auth.flags |= auth_flags;
265 SAFE_FREE(ads->auth.user_name);
266 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
269 * If the username is of the form "name@realm",
270 * extract the realm and convert to upper case.
271 * This is only used to establish the connection.
273 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
275 SAFE_FREE(ads->auth.realm);
276 ads->auth.realm = smb_xstrdup(cp);
277 strupper_m(ads->auth.realm);
280 status = ads_connect(ads);
282 if (!ADS_ERR_OK(status)) {
284 if (NT_STATUS_EQUAL(ads_ntstatus(status),
285 NT_STATUS_NO_LOGON_SERVERS)) {
286 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
291 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
292 need_password = true;
301 /* when contacting our own domain, make sure we use the closest DC.
302 * This is done by reconnecting to ADS because only the first call to
303 * ads_connect will give us our own sitename */
305 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
307 tried_closest_dc = true; /* avoid loop */
309 if (!ads_closest_dc(ads)) {
311 namecache_delete(ads->server.realm, 0x1C);
312 namecache_delete(ads->server.workgroup, 0x1C);
325 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
327 return ads_startup_int(c, only_own_domain, 0, ads);
330 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
332 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
336 Check to see if connection can be made via ads.
337 ads_startup() stores the password in opt_password if it needs to so
338 that rpc or rap can use it without re-prompting.
340 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
345 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
349 ads->auth.flags |= ADS_AUTH_NO_BIND;
351 status = ads_connect(ads);
352 if ( !ADS_ERR_OK(status) ) {
360 int net_ads_check_our_domain(struct net_context *c)
362 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
365 int net_ads_check(struct net_context *c)
367 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
371 determine the netbios workgroup name for a domain
373 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
376 char addr[INET6_ADDRSTRLEN];
377 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
379 if (c->display_usage) {
381 "net ads workgroup\n"
384 _("Print the workgroup name"));
388 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
389 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
393 if (!ads->config.realm) {
394 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
395 ads->ldap.port = 389;
398 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
399 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
400 d_fprintf(stderr, _("CLDAP query failed!\n"));
405 d_printf(_("Workgroup: %s\n"), reply.domain_name);
414 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
416 char **disp_fields = (char **) data_area;
418 if (!field) { /* must be end of record */
419 if (disp_fields[0]) {
420 if (!strchr_m(disp_fields[0], '$')) {
422 d_printf("%-21.21s %s\n",
423 disp_fields[0], disp_fields[1]);
425 d_printf("%s\n", disp_fields[0]);
428 SAFE_FREE(disp_fields[0]);
429 SAFE_FREE(disp_fields[1]);
432 if (!values) /* must be new field, indicate string field */
434 if (StrCaseCmp(field, "sAMAccountName") == 0) {
435 disp_fields[0] = SMB_STRDUP((char *) values[0]);
437 if (StrCaseCmp(field, "description") == 0)
438 disp_fields[1] = SMB_STRDUP((char *) values[0]);
442 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
444 return net_user_usage(c, argc, argv);
447 static int ads_user_add(struct net_context *c, int argc, const char **argv)
452 LDAPMessage *res=NULL;
456 if (argc < 1 || c->display_usage)
457 return net_ads_user_usage(c, argc, argv);
459 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
463 status = ads_find_user_acct(ads, &res, argv[0]);
465 if (!ADS_ERR_OK(status)) {
466 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
470 if (ads_count_replies(ads, res)) {
471 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
476 if (c->opt_container) {
477 ou_str = SMB_STRDUP(c->opt_container);
479 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
482 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
484 if (!ADS_ERR_OK(status)) {
485 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
490 /* if no password is to be set, we're done */
492 d_printf(_("User %s added\n"), argv[0]);
497 /* try setting the password */
498 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
501 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
502 ads->auth.time_offset);
504 if (ADS_ERR_OK(status)) {
505 d_printf(_("User %s added\n"), argv[0]);
510 /* password didn't set, delete account */
511 d_fprintf(stderr, _("Could not add user %s. "
512 "Error setting password %s\n"),
513 argv[0], ads_errstr(status));
514 ads_msgfree(ads, res);
515 status=ads_find_user_acct(ads, &res, argv[0]);
516 if (ADS_ERR_OK(status)) {
517 userdn = ads_get_dn(ads, talloc_tos(), res);
518 ads_del_dn(ads, userdn);
524 ads_msgfree(ads, res);
530 static int ads_user_info(struct net_context *c, int argc, const char **argv)
532 ADS_STRUCT *ads = NULL;
534 LDAPMessage *res = NULL;
538 const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
539 char *searchstring=NULL;
543 struct dom_sid primary_group_sid;
545 enum wbcSidType type;
547 if (argc < 1 || c->display_usage) {
548 return net_ads_user_usage(c, argc, argv);
551 frame = talloc_new(talloc_tos());
556 escaped_user = escape_ldap_string(frame, argv[0]);
559 _("ads_user_info: failed to escape user %s\n"),
564 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
569 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
573 rc = ads_search(ads, &res, searchstring, attrs);
574 SAFE_FREE(searchstring);
576 if (!ADS_ERR_OK(rc)) {
577 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(rc));
582 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
583 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
588 rc = ads_domain_sid(ads, &primary_group_sid);
589 if (!ADS_ERR_OK(rc)) {
590 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(rc));
595 sid_append_rid(&primary_group_sid, group_rid);
597 wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
598 NULL, /* don't look up domain */
601 if (!WBC_ERROR_IS_OK(wbc_status)) {
602 d_fprintf(stderr, "wbcLookupSid: %s\n",
603 wbcErrorString(wbc_status));
608 d_printf("%s\n", primary_group);
610 wbcFreeMemory(primary_group);
612 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
613 (LDAPMessage *)res, "memberOf");
618 for (i=0;grouplist[i];i++) {
619 groupname = ldap_explode_dn(grouplist[i], 1);
620 d_printf("%s\n", groupname[0]);
621 ldap_value_free(groupname);
623 ldap_value_free(grouplist);
627 if (res) ads_msgfree(ads, res);
628 if (ads) ads_destroy(&ads);
633 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
637 LDAPMessage *res = NULL;
641 return net_ads_user_usage(c, argc, argv);
644 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
648 rc = ads_find_user_acct(ads, &res, argv[0]);
649 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
650 d_printf(_("User %s does not exist.\n"), argv[0]);
651 ads_msgfree(ads, res);
655 userdn = ads_get_dn(ads, talloc_tos(), res);
656 ads_msgfree(ads, res);
657 rc = ads_del_dn(ads, userdn);
659 if (ADS_ERR_OK(rc)) {
660 d_printf(_("User %s deleted\n"), argv[0]);
664 d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
670 int net_ads_user(struct net_context *c, int argc, const char **argv)
672 struct functable func[] = {
677 N_("Add an AD user"),
678 N_("net ads user add\n"
685 N_("Display information about an AD user"),
686 N_("net ads user info\n"
687 " Display information about an AD user")
693 N_("Delete an AD user"),
694 N_("net ads user delete\n"
695 " Delete an AD user")
697 {NULL, NULL, 0, NULL, NULL}
701 const char *shortattrs[] = {"sAMAccountName", NULL};
702 const char *longattrs[] = {"sAMAccountName", "description", NULL};
703 char *disp_fields[2] = {NULL, NULL};
706 if (c->display_usage) {
712 net_display_usage_from_functable(func);
716 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
720 if (c->opt_long_list_entries)
721 d_printf(_("\nUser name Comment"
722 "\n-----------------------------\n"));
724 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
726 "(objectCategory=user)",
727 c->opt_long_list_entries ? longattrs :
728 shortattrs, usergrp_display,
731 return ADS_ERR_OK(rc) ? 0 : -1;
734 return net_run_function(c, argc, argv, "net ads user", func);
737 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
739 return net_group_usage(c, argc, argv);
742 static int ads_group_add(struct net_context *c, int argc, const char **argv)
746 LDAPMessage *res=NULL;
750 if (argc < 1 || c->display_usage) {
751 return net_ads_group_usage(c, argc, argv);
754 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
758 status = ads_find_user_acct(ads, &res, argv[0]);
760 if (!ADS_ERR_OK(status)) {
761 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
765 if (ads_count_replies(ads, res)) {
766 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
770 if (c->opt_container) {
771 ou_str = SMB_STRDUP(c->opt_container);
773 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
776 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
778 if (ADS_ERR_OK(status)) {
779 d_printf(_("Group %s added\n"), argv[0]);
782 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
788 ads_msgfree(ads, res);
794 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
798 LDAPMessage *res = NULL;
801 if (argc < 1 || c->display_usage) {
802 return net_ads_group_usage(c, argc, argv);
805 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
809 rc = ads_find_user_acct(ads, &res, argv[0]);
810 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
811 d_printf(_("Group %s does not exist.\n"), argv[0]);
812 ads_msgfree(ads, res);
816 groupdn = ads_get_dn(ads, talloc_tos(), res);
817 ads_msgfree(ads, res);
818 rc = ads_del_dn(ads, groupdn);
819 TALLOC_FREE(groupdn);
820 if (ADS_ERR_OK(rc)) {
821 d_printf(_("Group %s deleted\n"), argv[0]);
825 d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
831 int net_ads_group(struct net_context *c, int argc, const char **argv)
833 struct functable func[] = {
838 N_("Add an AD group"),
839 N_("net ads group add\n"
846 N_("Delete an AD group"),
847 N_("net ads group delete\n"
848 " Delete an AD group")
850 {NULL, NULL, 0, NULL, NULL}
854 const char *shortattrs[] = {"sAMAccountName", NULL};
855 const char *longattrs[] = {"sAMAccountName", "description", NULL};
856 char *disp_fields[2] = {NULL, NULL};
859 if (c->display_usage) {
864 _("List AD groups"));
865 net_display_usage_from_functable(func);
869 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
873 if (c->opt_long_list_entries)
874 d_printf(_("\nGroup name Comment"
875 "\n-----------------------------\n"));
876 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
878 "(objectCategory=group)",
879 c->opt_long_list_entries ? longattrs :
880 shortattrs, usergrp_display,
884 return ADS_ERR_OK(rc) ? 0 : -1;
886 return net_run_function(c, argc, argv, "net ads group", func);
889 static int net_ads_status(struct net_context *c, int argc, const char **argv)
895 if (c->display_usage) {
900 _("Display machine account details"));
904 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
908 rc = ads_find_machine_acct(ads, &res, global_myname());
909 if (!ADS_ERR_OK(rc)) {
910 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
915 if (ads_count_replies(ads, res) == 0) {
916 d_fprintf(stderr, _("No machine account for '%s' found\n"), global_myname());
926 /*******************************************************************
927 Leave an AD domain. Windows XP disables the machine account.
928 We'll try the same. The old code would do an LDAP delete.
929 That only worked using the machine creds because added the machine
930 with full control to the computer object's ACL.
931 *******************************************************************/
933 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
936 struct libnet_UnjoinCtx *r = NULL;
939 if (c->display_usage) {
944 _("Leave an AD domain"));
949 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
953 if (!(ctx = talloc_init("net_ads_leave"))) {
954 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
958 if (!c->opt_kerberos) {
959 use_in_memory_ccache();
962 werr = libnet_init_UnjoinCtx(ctx, &r);
963 if (!W_ERROR_IS_OK(werr)) {
964 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
969 r->in.use_kerberos = c->opt_kerberos;
970 r->in.dc_name = c->opt_host;
971 r->in.domain_name = lp_realm();
972 r->in.admin_account = c->opt_user_name;
973 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
974 r->in.modify_config = lp_config_backend_is_registry();
976 /* Try to delete it, but if that fails, disable it. The
977 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
978 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
979 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
980 r->in.delete_machine_account = true;
982 werr = libnet_Unjoin(ctx, r);
983 if (!W_ERROR_IS_OK(werr)) {
984 d_printf(_("Failed to leave domain: %s\n"),
985 r->out.error_string ? r->out.error_string :
986 get_friendly_werror_msg(werr));
990 if (r->out.deleted_machine_account) {
991 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
992 r->in.machine_name, r->out.dns_domain_name);
996 /* We couldn't delete it - see if the disable succeeded. */
997 if (r->out.disabled_machine_account) {
998 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
999 r->in.machine_name, r->out.dns_domain_name);
1004 /* Based on what we requseted, we shouldn't get here, but if
1005 we did, it means the secrets were removed, and therefore
1006 we have left the domain */
1007 d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1008 r->in.machine_name, r->out.dns_domain_name);
1014 if (W_ERROR_IS_OK(werr)) {
1021 static NTSTATUS net_ads_join_ok(struct net_context *c)
1023 ADS_STRUCT *ads = NULL;
1026 struct sockaddr_storage dcip;
1028 if (!secrets_init()) {
1029 DEBUG(1,("Failed to initialise secrets database\n"));
1030 return NT_STATUS_ACCESS_DENIED;
1033 net_use_krb_machine_account(c);
1035 get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1037 status = ads_startup(c, true, &ads);
1038 if (!ADS_ERR_OK(status)) {
1039 return ads_ntstatus(status);
1043 return NT_STATUS_OK;
1047 check that an existing join is OK
1049 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1052 use_in_memory_ccache();
1054 if (c->display_usage) {
1056 "net ads testjoin\n"
1059 _("Test if the existing join is ok"));
1063 /* Display success or failure */
1064 status = net_ads_join_ok(c);
1065 if (!NT_STATUS_IS_OK(status)) {
1066 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1067 get_friendly_nt_error_msg(status));
1071 printf(_("Join is OK\n"));
1075 /*******************************************************************
1076 Simple configu checks before beginning the join
1077 ********************************************************************/
1079 static WERROR check_ads_config( void )
1081 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1082 d_printf(_("Host is not configured as a member server.\n"));
1083 return WERR_INVALID_DOMAIN_ROLE;
1086 if (strlen(global_myname()) > 15) {
1087 d_printf(_("Our netbios name can be at most 15 chars long, "
1088 "\"%s\" is %u chars long\n"), global_myname(),
1089 (unsigned int)strlen(global_myname()));
1090 return WERR_INVALID_COMPUTERNAME;
1093 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1094 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1095 "join to succeed.\n"), get_dyn_CONFIGFILE());
1096 return WERR_INVALID_PARAM;
1102 /*******************************************************************
1103 Send a DNS update request
1104 *******************************************************************/
1106 #if defined(WITH_DNS_UPDATES)
1108 DNS_ERROR DoDNSUpdate(char *pszServerName,
1109 const char *pszDomainName, const char *pszHostName,
1110 const struct sockaddr_storage *sslist,
1113 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1114 const char *machine_name,
1115 const struct sockaddr_storage *addrs,
1118 struct dns_rr_ns *nameservers = NULL;
1120 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1123 const char *dnsdomain = NULL;
1124 char *root_domain = NULL;
1126 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1127 d_printf(_("No DNS domain configured for %s. "
1128 "Unable to perform DNS Update.\n"), machine_name);
1129 status = NT_STATUS_INVALID_PARAMETER;
1134 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1135 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1136 /* Child domains often do not have NS records. Look
1137 for the NS record for the forest root domain
1138 (rootDomainNamingContext in therootDSE) */
1140 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1141 LDAPMessage *msg = NULL;
1143 ADS_STATUS ads_status;
1145 if ( !ads->ldap.ld ) {
1146 ads_status = ads_connect( ads );
1147 if ( !ADS_ERR_OK(ads_status) ) {
1148 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1153 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1154 "(objectclass=*)", rootname_attrs, &msg);
1155 if (!ADS_ERR_OK(ads_status)) {
1159 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1161 ads_msgfree( ads, msg );
1165 root_domain = ads_build_domain( root_dn );
1168 ads_msgfree( ads, msg );
1170 /* try again for NS servers */
1172 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1174 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1175 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1176 "realm\n", ads->config.realm));
1180 dnsdomain = root_domain;
1184 /* Now perform the dns update - we'll try non-secure and if we fail,
1185 we'll follow it up with a secure update */
1187 fstrcpy( dns_server, nameservers[0].hostname );
1189 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1190 if (!ERR_DNS_IS_OK(dns_err)) {
1191 status = NT_STATUS_UNSUCCESSFUL;
1196 SAFE_FREE( root_domain );
1201 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1204 struct sockaddr_storage *iplist = NULL;
1205 fstring machine_name;
1208 name_to_fqdn( machine_name, global_myname() );
1209 strlower_m( machine_name );
1211 /* Get our ip address (not the 127.0.0.x address but a real ip
1214 num_addrs = get_my_ip_address( &iplist );
1215 if ( num_addrs <= 0 ) {
1216 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1218 return NT_STATUS_INVALID_PARAMETER;
1221 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1223 SAFE_FREE( iplist );
1229 /*******************************************************************
1230 ********************************************************************/
1232 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1234 d_printf(_("net ads join [options]\n"
1235 "Valid options:\n"));
1236 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1237 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1238 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1239 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1240 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1241 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1242 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1243 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1244 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1245 " NB: osName and osVer must be specified together for either to take effect.\n"
1246 " Also, the operatingSystemService attribute is also set when along with\n"
1247 " the two other attributes.\n"));
1252 /*******************************************************************
1253 ********************************************************************/
1255 int net_ads_join(struct net_context *c, int argc, const char **argv)
1257 TALLOC_CTX *ctx = NULL;
1258 struct libnet_JoinCtx *r = NULL;
1259 const char *domain = lp_realm();
1260 WERROR werr = WERR_SETUP_NOT_JOINED;
1261 bool createupn = false;
1262 const char *machineupn = NULL;
1263 const char *create_in_ou = NULL;
1265 const char *os_name = NULL;
1266 const char *os_version = NULL;
1267 bool modify_config = lp_config_backend_is_registry();
1269 if (c->display_usage)
1270 return net_ads_join_usage(c, argc, argv);
1272 if (!modify_config) {
1274 werr = check_ads_config();
1275 if (!W_ERROR_IS_OK(werr)) {
1276 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1281 if (!(ctx = talloc_init("net_ads_join"))) {
1282 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1287 if (!c->opt_kerberos) {
1288 use_in_memory_ccache();
1291 werr = libnet_init_JoinCtx(ctx, &r);
1292 if (!W_ERROR_IS_OK(werr)) {
1296 /* process additional command line args */
1298 for ( i=0; i<argc; i++ ) {
1299 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1301 machineupn = get_string_param(argv[i]);
1303 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1304 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1305 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1306 werr = WERR_INVALID_PARAM;
1310 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1311 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1312 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1313 werr = WERR_INVALID_PARAM;
1317 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1318 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1319 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1320 werr = WERR_INVALID_PARAM;
1330 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1331 werr = WERR_INVALID_PARAM;
1335 /* Do the domain join here */
1337 r->in.domain_name = domain;
1338 r->in.create_upn = createupn;
1339 r->in.upn = machineupn;
1340 r->in.account_ou = create_in_ou;
1341 r->in.os_name = os_name;
1342 r->in.os_version = os_version;
1343 r->in.dc_name = c->opt_host;
1344 r->in.admin_account = c->opt_user_name;
1345 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1347 r->in.use_kerberos = c->opt_kerberos;
1348 r->in.modify_config = modify_config;
1349 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1350 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1351 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1353 werr = libnet_Join(ctx, r);
1354 if (!W_ERROR_IS_OK(werr)) {
1358 /* Check the short name of the domain */
1360 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1361 d_printf(_("The workgroup in %s does not match the short\n"
1362 "domain name obtained from the server.\n"
1363 "Using the name [%s] from the server.\n"
1364 "You should set \"workgroup = %s\" in %s.\n"),
1365 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1366 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1369 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1371 if (r->out.dns_domain_name) {
1372 d_printf(_("Joined '%s' to realm '%s'\n"), r->in.machine_name,
1373 r->out.dns_domain_name);
1375 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1376 r->out.netbios_domain_name);
1379 #if defined(WITH_DNS_UPDATES)
1380 if (r->out.domain_is_ad) {
1381 /* We enter this block with user creds */
1382 ADS_STRUCT *ads_dns = NULL;
1384 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1385 /* kinit with the machine password */
1387 use_in_memory_ccache();
1388 if (asprintf( &ads_dns->auth.user_name, "%s$", global_myname()) == -1) {
1391 ads_dns->auth.password = secrets_fetch_machine_password(
1392 r->out.netbios_domain_name, NULL, NULL );
1393 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1394 strupper_m(ads_dns->auth.realm );
1395 ads_kinit_password( ads_dns );
1398 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1399 d_fprintf( stderr, _("DNS update failed!\n") );
1402 /* exit from this block using machine creds */
1403 ads_destroy(&ads_dns);
1412 /* issue an overall failure message at the end. */
1413 d_printf(_("Failed to join domain: %s\n"),
1414 r && r->out.error_string ? r->out.error_string :
1415 get_friendly_werror_msg(werr));
1421 /*******************************************************************
1422 ********************************************************************/
1424 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1426 #if defined(WITH_DNS_UPDATES)
1432 talloc_enable_leak_report();
1435 if (argc > 0 || c->display_usage) {
1437 "net ads dns register\n"
1440 _("Register hostname with DNS\n"));
1444 if (!(ctx = talloc_init("net_ads_dns"))) {
1445 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1449 status = ads_startup(c, true, &ads);
1450 if ( !ADS_ERR_OK(status) ) {
1451 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1456 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1457 d_fprintf( stderr, _("DNS update failed!\n") );
1458 ads_destroy( &ads );
1463 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1471 _("DNS update support not enabled at compile time!\n"));
1476 #if defined(WITH_DNS_UPDATES)
1477 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1480 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1482 #if defined(WITH_DNS_UPDATES)
1486 talloc_enable_leak_report();
1489 if (argc != 2 || c->display_usage) {
1494 _("net ads dns gethostbyname <server> <name>\n"),
1495 _(" Look up hostname from the AD\n"
1496 " server\tName server to use\n"
1497 " name\tName to look up\n"));
1501 err = do_gethostbyname(argv[0], argv[1]);
1503 d_printf(_("do_gethostbyname returned %d\n"), ERROR_DNS_V(err));
1508 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1510 struct functable func[] = {
1513 net_ads_dns_register,
1515 N_("Add host dns entry to AD"),
1516 N_("net ads dns register\n"
1517 " Add host dns entry to AD")
1521 net_ads_dns_gethostbyname,
1524 N_("net ads dns gethostbyname\n"
1527 {NULL, NULL, 0, NULL, NULL}
1530 return net_run_function(c, argc, argv, "net ads dns", func);
1533 /*******************************************************************
1534 ********************************************************************/
1536 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1539 "\nnet ads printer search <printer>"
1540 "\n\tsearch for a printer in the directory\n"
1541 "\nnet ads printer info <printer> <server>"
1542 "\n\tlookup info in directory for printer on server"
1543 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1544 "\nnet ads printer publish <printername>"
1545 "\n\tpublish printer in directory"
1546 "\n\t(note: printer name is required)\n"
1547 "\nnet ads printer remove <printername>"
1548 "\n\tremove printer from directory"
1549 "\n\t(note: printer name is required)\n"));
1553 /*******************************************************************
1554 ********************************************************************/
1556 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1560 LDAPMessage *res = NULL;
1562 if (c->display_usage) {
1564 "net ads printer search\n"
1567 _("List printers in the AD"));
1571 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1575 rc = ads_find_printers(ads, &res);
1577 if (!ADS_ERR_OK(rc)) {
1578 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
1579 ads_msgfree(ads, res);
1584 if (ads_count_replies(ads, res) == 0) {
1585 d_fprintf(stderr, _("No results found\n"));
1586 ads_msgfree(ads, res);
1592 ads_msgfree(ads, res);
1597 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1601 const char *servername, *printername;
1602 LDAPMessage *res = NULL;
1604 if (c->display_usage) {
1607 _("net ads printer info [printername [servername]]\n"
1608 " Display printer info from AD\n"
1609 " printername\tPrinter name or wildcard\n"
1610 " servername\tName of the print server\n"));
1614 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1619 printername = argv[0];
1625 servername = argv[1];
1627 servername = global_myname();
1630 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1632 if (!ADS_ERR_OK(rc)) {
1633 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
1634 servername, ads_errstr(rc));
1635 ads_msgfree(ads, res);
1640 if (ads_count_replies(ads, res) == 0) {
1641 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
1642 ads_msgfree(ads, res);
1648 ads_msgfree(ads, res);
1654 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1658 const char *servername, *printername;
1659 struct cli_state *cli = NULL;
1660 struct rpc_pipe_client *pipe_hnd = NULL;
1661 struct sockaddr_storage server_ss;
1663 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1664 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1665 char *prt_dn, *srv_dn, **srv_cn;
1666 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1667 LDAPMessage *res = NULL;
1669 if (argc < 1 || c->display_usage) {
1672 _("net ads printer publish <printername> [servername]\n"
1673 " Publish printer in AD\n"
1674 " printername\tName of the printer\n"
1675 " servername\tName of the print server\n"));
1676 talloc_destroy(mem_ctx);
1680 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1681 talloc_destroy(mem_ctx);
1685 printername = argv[0];
1688 servername = argv[1];
1690 servername = global_myname();
1693 /* Get printer data from SPOOLSS */
1695 resolve_name(servername, &server_ss, 0x20, false);
1697 nt_status = cli_full_connection(&cli, global_myname(), servername,
1700 c->opt_user_name, c->opt_workgroup,
1701 c->opt_password ? c->opt_password : "",
1702 CLI_FULL_CONNECTION_USE_KERBEROS,
1705 if (NT_STATUS_IS_ERR(nt_status)) {
1706 d_fprintf(stderr, _("Unable to open a connnection to %s to "
1707 "obtain data for %s\n"),
1708 servername, printername);
1710 talloc_destroy(mem_ctx);
1714 /* Publish on AD server */
1716 ads_find_machine_acct(ads, &res, servername);
1718 if (ads_count_replies(ads, res) == 0) {
1719 d_fprintf(stderr, _("Could not find machine account for server "
1723 talloc_destroy(mem_ctx);
1727 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1728 srv_cn = ldap_explode_dn(srv_dn, 1);
1730 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1731 printername_escaped = escape_rdn_val_string_alloc(printername);
1732 if (!srv_cn_escaped || !printername_escaped) {
1733 SAFE_FREE(srv_cn_escaped);
1734 SAFE_FREE(printername_escaped);
1735 d_fprintf(stderr, _("Internal error, out of memory!"));
1737 talloc_destroy(mem_ctx);
1741 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1742 SAFE_FREE(srv_cn_escaped);
1743 SAFE_FREE(printername_escaped);
1744 d_fprintf(stderr, _("Internal error, out of memory!"));
1746 talloc_destroy(mem_ctx);
1750 SAFE_FREE(srv_cn_escaped);
1751 SAFE_FREE(printername_escaped);
1753 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
1754 if (!NT_STATUS_IS_OK(nt_status)) {
1755 d_fprintf(stderr, _("Unable to open a connnection to the spoolss pipe on %s\n"),
1759 talloc_destroy(mem_ctx);
1763 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1767 talloc_destroy(mem_ctx);
1771 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1772 if (!ADS_ERR_OK(rc)) {
1773 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1776 talloc_destroy(mem_ctx);
1780 d_printf("published printer\n");
1783 talloc_destroy(mem_ctx);
1788 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1792 const char *servername;
1794 LDAPMessage *res = NULL;
1796 if (argc < 1 || c->display_usage) {
1799 _("net ads printer remove <printername> [servername]\n"
1800 " Remove a printer from the AD\n"
1801 " printername\tName of the printer\n"
1802 " servername\tName of the print server\n"));
1806 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1811 servername = argv[1];
1813 servername = global_myname();
1816 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1818 if (!ADS_ERR_OK(rc)) {
1819 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
1820 ads_msgfree(ads, res);
1825 if (ads_count_replies(ads, res) == 0) {
1826 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
1827 ads_msgfree(ads, res);
1832 prt_dn = ads_get_dn(ads, talloc_tos(), res);
1833 ads_msgfree(ads, res);
1834 rc = ads_del_dn(ads, prt_dn);
1835 TALLOC_FREE(prt_dn);
1837 if (!ADS_ERR_OK(rc)) {
1838 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
1847 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1849 struct functable func[] = {
1852 net_ads_printer_search,
1854 N_("Search for a printer"),
1855 N_("net ads printer search\n"
1856 " Search for a printer")
1860 net_ads_printer_info,
1862 N_("Display printer information"),
1863 N_("net ads printer info\n"
1864 " Display printer information")
1868 net_ads_printer_publish,
1870 N_("Publish a printer"),
1871 N_("net ads printer publish\n"
1872 " Publish a printer")
1876 net_ads_printer_remove,
1878 N_("Delete a printer"),
1879 N_("net ads printer remove\n"
1880 " Delete a printer")
1882 {NULL, NULL, 0, NULL, NULL}
1885 return net_run_function(c, argc, argv, "net ads printer", func);
1889 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1892 const char *auth_principal = c->opt_user_name;
1893 const char *auth_password = c->opt_password;
1895 char *new_password = NULL;
1900 if (c->display_usage) {
1903 _("net ads password <username>\n"
1904 " Change password for user\n"
1905 " username\tName of user to change password for\n"));
1909 if (c->opt_user_name == NULL || c->opt_password == NULL) {
1910 d_fprintf(stderr, _("You must supply an administrator "
1911 "username/password\n"));
1916 d_fprintf(stderr, _("ERROR: You must say which username to "
1917 "change password for\n"));
1922 if (!strchr_m(user, '@')) {
1923 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
1929 use_in_memory_ccache();
1930 chr = strchr_m(auth_principal, '@');
1937 /* use the realm so we can eventually change passwords for users
1938 in realms other than default */
1939 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1943 /* we don't actually need a full connect, but it's the easy way to
1944 fill in the KDC's addresss */
1947 if (!ads->config.realm) {
1948 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
1954 new_password = (char *)argv[1];
1956 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
1959 new_password = getpass(prompt);
1963 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1964 auth_password, user, new_password, ads->auth.time_offset);
1965 if (!ADS_ERR_OK(ret)) {
1966 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
1971 d_printf(_("Password change for %s completed.\n"), user);
1977 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1980 char *host_principal;
1984 if (c->display_usage) {
1986 "net ads changetrustpw\n"
1989 _("Change the machine account's trust password"));
1993 if (!secrets_init()) {
1994 DEBUG(1,("Failed to initialise secrets database\n"));
1998 net_use_krb_machine_account(c);
2000 use_in_memory_ccache();
2002 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2006 fstrcpy(my_name, global_myname());
2007 strlower_m(my_name);
2008 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2012 d_printf(_("Changing password for principal: %s\n"), host_principal);
2014 ret = ads_change_trust_account_password(ads, host_principal);
2016 if (!ADS_ERR_OK(ret)) {
2017 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2019 SAFE_FREE(host_principal);
2023 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2025 if (USE_SYSTEM_KEYTAB) {
2026 d_printf(_("Attempting to update system keytab with new password.\n"));
2027 if (ads_keytab_create_default(ads)) {
2028 d_printf(_("Failed to update system keytab.\n"));
2033 SAFE_FREE(host_principal);
2039 help for net ads search
2041 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2044 "\nnet ads search <expression> <attributes...>\n"
2045 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2046 "The expression is a standard LDAP search expression, and the\n"
2047 "attributes are a list of LDAP fields to show in the results.\n\n"
2048 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2050 net_common_flags_usage(c, argc, argv);
2056 general ADS search function. Useful in diagnosing problems in ADS
2058 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2062 const char *ldap_exp;
2064 LDAPMessage *res = NULL;
2066 if (argc < 1 || c->display_usage) {
2067 return net_ads_search_usage(c, argc, argv);
2070 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2077 rc = ads_do_search_all(ads, ads->config.bind_path,
2079 ldap_exp, attrs, &res);
2080 if (!ADS_ERR_OK(rc)) {
2081 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2086 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2088 /* dump the results */
2091 ads_msgfree(ads, res);
2099 help for net ads search
2101 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2104 "\nnet ads dn <dn> <attributes...>\n"
2105 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2106 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2107 "to show in the results\n\n"
2108 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2109 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2111 net_common_flags_usage(c, argc, argv);
2117 general ADS search function. Useful in diagnosing problems in ADS
2119 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2125 LDAPMessage *res = NULL;
2127 if (argc < 1 || c->display_usage) {
2128 return net_ads_dn_usage(c, argc, argv);
2131 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2138 rc = ads_do_search_all(ads, dn,
2140 "(objectclass=*)", attrs, &res);
2141 if (!ADS_ERR_OK(rc)) {
2142 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2147 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2149 /* dump the results */
2152 ads_msgfree(ads, res);
2159 help for net ads sid search
2161 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2164 "\nnet ads sid <sid> <attributes...>\n"
2165 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2166 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2167 "to show in the results\n\n"
2168 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2170 net_common_flags_usage(c, argc, argv);
2176 general ADS search function. Useful in diagnosing problems in ADS
2178 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2182 const char *sid_string;
2184 LDAPMessage *res = NULL;
2187 if (argc < 1 || c->display_usage) {
2188 return net_ads_sid_usage(c, argc, argv);
2191 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2195 sid_string = argv[0];
2198 if (!string_to_sid(&sid, sid_string)) {
2199 d_fprintf(stderr, _("could not convert sid\n"));
2204 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2205 if (!ADS_ERR_OK(rc)) {
2206 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2211 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2213 /* dump the results */
2216 ads_msgfree(ads, res);
2222 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2227 if (c->display_usage) {
2229 "net ads keytab flush\n"
2232 _("Delete the whole keytab"));
2236 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2239 ret = ads_keytab_flush(ads);
2244 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2250 if (c->display_usage) {
2253 _("net ads keytab add <principal> [principal ...]\n"
2254 " Add principals to local keytab\n"
2255 " principal\tKerberos principal to add to "
2260 d_printf(_("Processing principals to add...\n"));
2261 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2264 for (i = 0; i < argc; i++) {
2265 ret |= ads_keytab_add_entry(ads, argv[i]);
2271 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2276 if (c->display_usage) {
2278 "net ads keytab create\n"
2281 _("Create new default keytab"));
2285 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2288 ret = ads_keytab_create_default(ads);
2293 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2295 const char *keytab = NULL;
2297 if (c->display_usage) {
2300 _("net ads keytab list [keytab]\n"
2301 " List a local keytab\n"
2302 " keytab\tKeytab to list\n"));
2310 return ads_keytab_list(keytab);
2314 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2316 struct functable func[] = {
2321 N_("Add a service principal"),
2322 N_("net ads keytab add\n"
2323 " Add a service principal")
2327 net_ads_keytab_create,
2329 N_("Create a fresh keytab"),
2330 N_("net ads keytab create\n"
2331 " Create a fresh keytab")
2335 net_ads_keytab_flush,
2337 N_("Remove all keytab entries"),
2338 N_("net ads keytab flush\n"
2339 " Remove all keytab entries")
2343 net_ads_keytab_list,
2345 N_("List a keytab"),
2346 N_("net ads keytab list\n"
2349 {NULL, NULL, 0, NULL, NULL}
2352 if (!USE_KERBEROS_KEYTAB) {
2353 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2354 "keytab method to use keytab functions.\n"));
2357 return net_run_function(c, argc, argv, "net ads keytab", func);
2360 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2364 if (c->display_usage) {
2366 "net ads kerberos renew\n"
2369 _("Renew TGT from existing credential cache"));
2373 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2375 d_printf(_("failed to renew kerberos ticket: %s\n"),
2376 error_message(ret));
2381 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2383 struct PAC_LOGON_INFO *info = NULL;
2384 TALLOC_CTX *mem_ctx = NULL;
2387 const char *impersonate_princ_s = NULL;
2389 if (c->display_usage) {
2391 "net ads kerberos pac\n"
2394 _("Dump the Kerberos PAC"));
2398 mem_ctx = talloc_init("net_ads_kerberos_pac");
2404 impersonate_princ_s = argv[0];
2407 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2409 status = kerberos_return_pac(mem_ctx,
2418 2592000, /* one month */
2419 impersonate_princ_s,
2421 if (!NT_STATUS_IS_OK(status)) {
2422 d_printf(_("failed to query kerberos PAC: %s\n"),
2429 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2430 d_printf(_("The Pac: %s\n"), s);
2435 TALLOC_FREE(mem_ctx);
2439 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2441 TALLOC_CTX *mem_ctx = NULL;
2445 if (c->display_usage) {
2447 "net ads kerberos kinit\n"
2450 _("Get Ticket Granting Ticket (TGT) for the user"));
2454 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2459 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2461 ret = kerberos_kinit_password_ext(c->opt_user_name,
2469 2592000, /* one month */
2472 d_printf(_("failed to kinit password: %s\n"),
2479 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2481 struct functable func[] = {
2484 net_ads_kerberos_kinit,
2486 N_("Retrieve Ticket Granting Ticket (TGT)"),
2487 N_("net ads kerberos kinit\n"
2488 " Receive Ticket Granting Ticket (TGT)")
2492 net_ads_kerberos_renew,
2494 N_("Renew Ticket Granting Ticket from credential cache"),
2495 N_("net ads kerberos renew\n"
2496 " Renew Ticket Granting Ticket (TGT) from "
2501 net_ads_kerberos_pac,
2503 N_("Dump Kerberos PAC"),
2504 N_("net ads kerberos pac\n"
2505 " Dump Kerberos PAC")
2507 {NULL, NULL, 0, NULL, NULL}
2510 return net_run_function(c, argc, argv, "net ads kerberos", func);
2513 int net_ads(struct net_context *c, int argc, const char **argv)
2515 struct functable func[] = {
2520 N_("Display details on remote ADS server"),
2522 " Display details on remote ADS server")
2528 N_("Join the local machine to ADS realm"),
2530 " Join the local machine to ADS realm")
2536 N_("Validate machine account"),
2537 N_("net ads testjoin\n"
2538 " Validate machine account")
2544 N_("Remove the local machine from ADS"),
2545 N_("net ads leave\n"
2546 " Remove the local machine from ADS")
2552 N_("Display machine account details"),
2553 N_("net ads status\n"
2554 " Display machine account details")
2560 N_("List/modify users"),
2562 " List/modify users")
2568 N_("List/modify groups"),
2569 N_("net ads group\n"
2570 " List/modify groups")
2576 N_("Issue dynamic DNS update"),
2578 " Issue dynamic DNS update")
2584 N_("Change user passwords"),
2585 N_("net ads password\n"
2586 " Change user passwords")
2590 net_ads_changetrustpw,
2592 N_("Change trust account password"),
2593 N_("net ads changetrustpw\n"
2594 " Change trust account password")
2600 N_("List/modify printer entries"),
2601 N_("net ads printer\n"
2602 " List/modify printer entries")
2608 N_("Issue LDAP search using filter"),
2609 N_("net ads search\n"
2610 " Issue LDAP search using filter")
2616 N_("Issue LDAP search by DN"),
2618 " Issue LDAP search by DN")
2624 N_("Issue LDAP search by SID"),
2626 " Issue LDAP search by SID")
2632 N_("Display workgroup name"),
2633 N_("net ads workgroup\n"
2634 " Display the workgroup name")
2640 N_("Perfom CLDAP query on DC"),
2641 N_("net ads lookup\n"
2642 " Find the ADS DC using CLDAP lookups")
2648 N_("Manage local keytab file"),
2649 N_("net ads keytab\n"
2650 " Manage local keytab file")
2656 N_("Manage group policy objects"),
2658 " Manage group policy objects")
2664 N_("Manage kerberos keytab"),
2665 N_("net ads kerberos\n"
2666 " Manage kerberos keytab")
2668 {NULL, NULL, 0, NULL, NULL}
2671 return net_run_function(c, argc, argv, "net ads", func);
2676 static int net_ads_noads(void)
2678 d_fprintf(stderr, _("ADS support not compiled in\n"));
2682 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2684 return net_ads_noads();
2687 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2689 return net_ads_noads();
2692 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2694 return net_ads_noads();
2697 int net_ads_join(struct net_context *c, int argc, const char **argv)
2699 return net_ads_noads();
2702 int net_ads_user(struct net_context *c, int argc, const char **argv)
2704 return net_ads_noads();
2707 int net_ads_group(struct net_context *c, int argc, const char **argv)
2709 return net_ads_noads();
2712 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
2714 return net_ads_noads();
2717 /* this one shouldn't display a message */
2718 int net_ads_check(struct net_context *c)
2723 int net_ads_check_our_domain(struct net_context *c)
2728 int net_ads(struct net_context *c, int argc, const char **argv)
2730 return net_ads_noads();
2733 #endif /* WITH_ADS */