2 Samba Unix/Linux SMB client library
4 Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
5 Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
6 Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
7 Copyright (C) 2006 Gerald (Jerry) Carter (jerry@samba.org)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "utils/net.h"
25 #include "librpc/gen_ndr/ndr_krb5pac.h"
26 #include "../librpc/gen_ndr/cli_spoolss.h"
27 #include "nsswitch/libwbclient/wbclient.h"
28 #include "libads/cldap.h"
29 #include "libads/dns.h"
33 /* when we do not have sufficient input parameters to contact a remote domain
34 * we always fall back to our own realm - Guenther*/
36 static const char *assume_own_realm(struct net_context *c)
38 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
46 do a cldap netlogon query
48 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
50 char addr[INET6_ADDRSTRLEN];
51 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
53 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
54 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
55 d_fprintf(stderr, _("CLDAP query failed!\n"));
59 d_printf(_("Information for Domain Controller: %s\n\n"),
62 d_printf(_("Response Type: "));
63 switch (reply.command) {
64 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
65 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
67 case LOGON_SAM_LOGON_RESPONSE_EX:
68 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
71 d_printf("0x%x\n", reply.command);
75 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
79 "\tIs a GC of the forest: %s\n"
80 "\tIs an LDAP server: %s\n"
82 "\tIs running a KDC: %s\n"
83 "\tIs running time services: %s\n"
84 "\tIs the closest DC: %s\n"
86 "\tHas a hardware clock: %s\n"
87 "\tIs a non-domain NC serviced by LDAP server: %s\n"
88 "\tIs NT6 DC that has some secrets: %s\n"
89 "\tIs NT6 DC that has all secrets: %s\n"),
90 (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
91 (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
92 (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
93 (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
94 (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
95 (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
96 (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
97 (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
98 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
99 (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
100 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
101 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"));
104 printf(_("Forest:\t\t\t%s\n"), reply.forest);
105 printf(_("Domain:\t\t\t%s\n"), reply.dns_domain);
106 printf(_("Domain Controller:\t%s\n"), reply.pdc_dns_name);
108 printf(_("Pre-Win2k Domain:\t%s\n"), reply.domain_name);
109 printf(_("Pre-Win2k Hostname:\t%s\n"), reply.pdc_name);
111 if (*reply.user_name) printf(_("User name:\t%s\n"), reply.user_name);
113 printf(_("Server Site Name :\t\t%s\n"), reply.server_site);
114 printf(_("Client Site Name :\t\t%s\n"), reply.client_site);
116 d_printf(_("NT Version: %d\n"), reply.nt_version);
117 d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
118 d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
124 this implements the CLDAP based netlogon lookup requests
125 for finding the domain controller of a ADS domain
127 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
132 if (c->display_usage) {
137 _("Find the ADS DC using CLDAP lookup.\n"));
141 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
142 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
147 if (!ads->config.realm) {
148 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
149 ads->ldap.port = 389;
152 ret = net_ads_cldap_netlogon(c, ads);
159 static int net_ads_info(struct net_context *c, int argc, const char **argv)
162 char addr[INET6_ADDRSTRLEN];
164 if (c->display_usage) {
169 _("Display information about an Active Directory "
174 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
175 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
179 if (!ads || !ads->config.realm) {
180 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
185 /* Try to set the server's current time since we didn't do a full
186 TCP LDAP session initially */
188 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
189 d_fprintf( stderr, _("Failed to get server's current time!\n"));
192 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
194 d_printf(_("LDAP server: %s\n"), addr);
195 d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
196 d_printf(_("Realm: %s\n"), ads->config.realm);
197 d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
198 d_printf(_("LDAP port: %d\n"), ads->ldap.port);
199 d_printf(_("Server time: %s\n"),
200 http_timestring(talloc_tos(), ads->config.current_time));
202 d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
203 d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
209 static void use_in_memory_ccache(void) {
210 /* Use in-memory credentials cache so we do not interfere with
211 * existing credentials */
212 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
215 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
216 uint32 auth_flags, ADS_STRUCT **ads_ret)
218 ADS_STRUCT *ads = NULL;
220 bool need_password = false;
221 bool second_time = false;
223 const char *realm = NULL;
224 bool tried_closest_dc = false;
226 /* lp_realm() should be handled by a command line param,
227 However, the join requires that realm be set in smb.conf
228 and compares our realm with the remote server's so this is
229 ok until someone needs more flexibility */
234 if (only_own_domain) {
237 realm = assume_own_realm(c);
240 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
242 if (!c->opt_user_name) {
243 c->opt_user_name = "administrator";
246 if (c->opt_user_specified) {
247 need_password = true;
251 if (!c->opt_password && need_password && !c->opt_machine_pass) {
252 c->opt_password = net_prompt_pass(c, c->opt_user_name);
253 if (!c->opt_password) {
255 return ADS_ERROR(LDAP_NO_MEMORY);
259 if (c->opt_password) {
260 use_in_memory_ccache();
261 SAFE_FREE(ads->auth.password);
262 ads->auth.password = smb_xstrdup(c->opt_password);
265 ads->auth.flags |= auth_flags;
266 SAFE_FREE(ads->auth.user_name);
267 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
270 * If the username is of the form "name@realm",
271 * extract the realm and convert to upper case.
272 * This is only used to establish the connection.
274 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
276 SAFE_FREE(ads->auth.realm);
277 ads->auth.realm = smb_xstrdup(cp);
278 strupper_m(ads->auth.realm);
281 status = ads_connect(ads);
283 if (!ADS_ERR_OK(status)) {
285 if (NT_STATUS_EQUAL(ads_ntstatus(status),
286 NT_STATUS_NO_LOGON_SERVERS)) {
287 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
292 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
293 need_password = true;
302 /* when contacting our own domain, make sure we use the closest DC.
303 * This is done by reconnecting to ADS because only the first call to
304 * ads_connect will give us our own sitename */
306 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
308 tried_closest_dc = true; /* avoid loop */
310 if (!ads_closest_dc(ads)) {
312 namecache_delete(ads->server.realm, 0x1C);
313 namecache_delete(ads->server.workgroup, 0x1C);
326 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
328 return ads_startup_int(c, only_own_domain, 0, ads);
331 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
333 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
337 Check to see if connection can be made via ads.
338 ads_startup() stores the password in opt_password if it needs to so
339 that rpc or rap can use it without re-prompting.
341 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
346 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
350 ads->auth.flags |= ADS_AUTH_NO_BIND;
352 status = ads_connect(ads);
353 if ( !ADS_ERR_OK(status) ) {
361 int net_ads_check_our_domain(struct net_context *c)
363 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
366 int net_ads_check(struct net_context *c)
368 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
372 determine the netbios workgroup name for a domain
374 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
377 char addr[INET6_ADDRSTRLEN];
378 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
380 if (c->display_usage) {
382 "net ads workgroup\n"
385 _("Print the workgroup name"));
389 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
390 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
394 if (!ads->config.realm) {
395 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
396 ads->ldap.port = 389;
399 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
400 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
401 d_fprintf(stderr, _("CLDAP query failed!\n"));
406 d_printf(_("Workgroup: %s\n"), reply.domain_name);
415 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
417 char **disp_fields = (char **) data_area;
419 if (!field) { /* must be end of record */
420 if (disp_fields[0]) {
421 if (!strchr_m(disp_fields[0], '$')) {
423 d_printf("%-21.21s %s\n",
424 disp_fields[0], disp_fields[1]);
426 d_printf("%s\n", disp_fields[0]);
429 SAFE_FREE(disp_fields[0]);
430 SAFE_FREE(disp_fields[1]);
433 if (!values) /* must be new field, indicate string field */
435 if (StrCaseCmp(field, "sAMAccountName") == 0) {
436 disp_fields[0] = SMB_STRDUP((char *) values[0]);
438 if (StrCaseCmp(field, "description") == 0)
439 disp_fields[1] = SMB_STRDUP((char *) values[0]);
443 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
445 return net_user_usage(c, argc, argv);
448 static int ads_user_add(struct net_context *c, int argc, const char **argv)
453 LDAPMessage *res=NULL;
457 if (argc < 1 || c->display_usage)
458 return net_ads_user_usage(c, argc, argv);
460 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
464 status = ads_find_user_acct(ads, &res, argv[0]);
466 if (!ADS_ERR_OK(status)) {
467 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
471 if (ads_count_replies(ads, res)) {
472 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
477 if (c->opt_container) {
478 ou_str = SMB_STRDUP(c->opt_container);
480 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
483 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
485 if (!ADS_ERR_OK(status)) {
486 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
491 /* if no password is to be set, we're done */
493 d_printf(_("User %s added\n"), argv[0]);
498 /* try setting the password */
499 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
502 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
503 ads->auth.time_offset);
505 if (ADS_ERR_OK(status)) {
506 d_printf(_("User %s added\n"), argv[0]);
511 /* password didn't set, delete account */
512 d_fprintf(stderr, _("Could not add user %s. "
513 "Error setting password %s\n"),
514 argv[0], ads_errstr(status));
515 ads_msgfree(ads, res);
516 status=ads_find_user_acct(ads, &res, argv[0]);
517 if (ADS_ERR_OK(status)) {
518 userdn = ads_get_dn(ads, talloc_tos(), res);
519 ads_del_dn(ads, userdn);
525 ads_msgfree(ads, res);
531 static int ads_user_info(struct net_context *c, int argc, const char **argv)
533 ADS_STRUCT *ads = NULL;
535 LDAPMessage *res = NULL;
539 const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
540 char *searchstring=NULL;
544 struct dom_sid primary_group_sid;
546 enum wbcSidType type;
548 if (argc < 1 || c->display_usage) {
549 return net_ads_user_usage(c, argc, argv);
552 frame = talloc_new(talloc_tos());
557 escaped_user = escape_ldap_string(frame, argv[0]);
560 _("ads_user_info: failed to escape user %s\n"),
565 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
570 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
574 rc = ads_search(ads, &res, searchstring, attrs);
575 SAFE_FREE(searchstring);
577 if (!ADS_ERR_OK(rc)) {
578 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(rc));
583 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
584 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
589 rc = ads_domain_sid(ads, &primary_group_sid);
590 if (!ADS_ERR_OK(rc)) {
591 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(rc));
596 sid_append_rid(&primary_group_sid, group_rid);
598 wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
599 NULL, /* don't look up domain */
602 if (!WBC_ERROR_IS_OK(wbc_status)) {
603 d_fprintf(stderr, "wbcLookupSid: %s\n",
604 wbcErrorString(wbc_status));
609 d_printf("%s\n", primary_group);
611 wbcFreeMemory(primary_group);
613 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
614 (LDAPMessage *)res, "memberOf");
619 for (i=0;grouplist[i];i++) {
620 groupname = ldap_explode_dn(grouplist[i], 1);
621 d_printf("%s\n", groupname[0]);
622 ldap_value_free(groupname);
624 ldap_value_free(grouplist);
628 if (res) ads_msgfree(ads, res);
629 if (ads) ads_destroy(&ads);
634 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
638 LDAPMessage *res = NULL;
642 return net_ads_user_usage(c, argc, argv);
645 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
649 rc = ads_find_user_acct(ads, &res, argv[0]);
650 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
651 d_printf(_("User %s does not exist.\n"), argv[0]);
652 ads_msgfree(ads, res);
656 userdn = ads_get_dn(ads, talloc_tos(), res);
657 ads_msgfree(ads, res);
658 rc = ads_del_dn(ads, userdn);
660 if (ADS_ERR_OK(rc)) {
661 d_printf(_("User %s deleted\n"), argv[0]);
665 d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
671 int net_ads_user(struct net_context *c, int argc, const char **argv)
673 struct functable func[] = {
678 N_("Add an AD user"),
679 N_("net ads user add\n"
686 N_("Display information about an AD user"),
687 N_("net ads user info\n"
688 " Display information about an AD user")
694 N_("Delete an AD user"),
695 N_("net ads user delete\n"
696 " Delete an AD user")
698 {NULL, NULL, 0, NULL, NULL}
702 const char *shortattrs[] = {"sAMAccountName", NULL};
703 const char *longattrs[] = {"sAMAccountName", "description", NULL};
704 char *disp_fields[2] = {NULL, NULL};
707 if (c->display_usage) {
713 net_display_usage_from_functable(func);
717 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
721 if (c->opt_long_list_entries)
722 d_printf(_("\nUser name Comment"
723 "\n-----------------------------\n"));
725 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
727 "(objectCategory=user)",
728 c->opt_long_list_entries ? longattrs :
729 shortattrs, usergrp_display,
732 return ADS_ERR_OK(rc) ? 0 : -1;
735 return net_run_function(c, argc, argv, "net ads user", func);
738 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
740 return net_group_usage(c, argc, argv);
743 static int ads_group_add(struct net_context *c, int argc, const char **argv)
747 LDAPMessage *res=NULL;
751 if (argc < 1 || c->display_usage) {
752 return net_ads_group_usage(c, argc, argv);
755 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
759 status = ads_find_user_acct(ads, &res, argv[0]);
761 if (!ADS_ERR_OK(status)) {
762 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
766 if (ads_count_replies(ads, res)) {
767 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
771 if (c->opt_container) {
772 ou_str = SMB_STRDUP(c->opt_container);
774 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
777 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
779 if (ADS_ERR_OK(status)) {
780 d_printf(_("Group %s added\n"), argv[0]);
783 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
789 ads_msgfree(ads, res);
795 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
799 LDAPMessage *res = NULL;
802 if (argc < 1 || c->display_usage) {
803 return net_ads_group_usage(c, argc, argv);
806 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
810 rc = ads_find_user_acct(ads, &res, argv[0]);
811 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
812 d_printf(_("Group %s does not exist.\n"), argv[0]);
813 ads_msgfree(ads, res);
817 groupdn = ads_get_dn(ads, talloc_tos(), res);
818 ads_msgfree(ads, res);
819 rc = ads_del_dn(ads, groupdn);
820 TALLOC_FREE(groupdn);
821 if (ADS_ERR_OK(rc)) {
822 d_printf(_("Group %s deleted\n"), argv[0]);
826 d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
832 int net_ads_group(struct net_context *c, int argc, const char **argv)
834 struct functable func[] = {
839 N_("Add an AD group"),
840 N_("net ads group add\n"
847 N_("Delete an AD group"),
848 N_("net ads group delete\n"
849 " Delete an AD group")
851 {NULL, NULL, 0, NULL, NULL}
855 const char *shortattrs[] = {"sAMAccountName", NULL};
856 const char *longattrs[] = {"sAMAccountName", "description", NULL};
857 char *disp_fields[2] = {NULL, NULL};
860 if (c->display_usage) {
865 _("List AD groups"));
866 net_display_usage_from_functable(func);
870 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
874 if (c->opt_long_list_entries)
875 d_printf(_("\nGroup name Comment"
876 "\n-----------------------------\n"));
877 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
879 "(objectCategory=group)",
880 c->opt_long_list_entries ? longattrs :
881 shortattrs, usergrp_display,
885 return ADS_ERR_OK(rc) ? 0 : -1;
887 return net_run_function(c, argc, argv, "net ads group", func);
890 static int net_ads_status(struct net_context *c, int argc, const char **argv)
896 if (c->display_usage) {
901 _("Display machine account details"));
905 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
909 rc = ads_find_machine_acct(ads, &res, global_myname());
910 if (!ADS_ERR_OK(rc)) {
911 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
916 if (ads_count_replies(ads, res) == 0) {
917 d_fprintf(stderr, _("No machine account for '%s' found\n"), global_myname());
927 /*******************************************************************
928 Leave an AD domain. Windows XP disables the machine account.
929 We'll try the same. The old code would do an LDAP delete.
930 That only worked using the machine creds because added the machine
931 with full control to the computer object's ACL.
932 *******************************************************************/
934 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
937 struct libnet_UnjoinCtx *r = NULL;
940 if (c->display_usage) {
945 _("Leave an AD domain"));
950 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
954 if (!(ctx = talloc_init("net_ads_leave"))) {
955 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
959 if (!c->opt_kerberos) {
960 use_in_memory_ccache();
963 werr = libnet_init_UnjoinCtx(ctx, &r);
964 if (!W_ERROR_IS_OK(werr)) {
965 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
970 r->in.use_kerberos = c->opt_kerberos;
971 r->in.dc_name = c->opt_host;
972 r->in.domain_name = lp_realm();
973 r->in.admin_account = c->opt_user_name;
974 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
975 r->in.modify_config = lp_config_backend_is_registry();
977 /* Try to delete it, but if that fails, disable it. The
978 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
979 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
980 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
981 r->in.delete_machine_account = true;
983 werr = libnet_Unjoin(ctx, r);
984 if (!W_ERROR_IS_OK(werr)) {
985 d_printf(_("Failed to leave domain: %s\n"),
986 r->out.error_string ? r->out.error_string :
987 get_friendly_werror_msg(werr));
991 if (r->out.deleted_machine_account) {
992 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
993 r->in.machine_name, r->out.dns_domain_name);
997 /* We couldn't delete it - see if the disable succeeded. */
998 if (r->out.disabled_machine_account) {
999 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1000 r->in.machine_name, r->out.dns_domain_name);
1005 /* Based on what we requseted, we shouldn't get here, but if
1006 we did, it means the secrets were removed, and therefore
1007 we have left the domain */
1008 d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1009 r->in.machine_name, r->out.dns_domain_name);
1015 if (W_ERROR_IS_OK(werr)) {
1022 static NTSTATUS net_ads_join_ok(struct net_context *c)
1024 ADS_STRUCT *ads = NULL;
1027 struct sockaddr_storage dcip;
1029 if (!secrets_init()) {
1030 DEBUG(1,("Failed to initialise secrets database\n"));
1031 return NT_STATUS_ACCESS_DENIED;
1034 net_use_krb_machine_account(c);
1036 get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1038 status = ads_startup(c, true, &ads);
1039 if (!ADS_ERR_OK(status)) {
1040 return ads_ntstatus(status);
1044 return NT_STATUS_OK;
1048 check that an existing join is OK
1050 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1053 use_in_memory_ccache();
1055 if (c->display_usage) {
1057 "net ads testjoin\n"
1060 _("Test if the existing join is ok"));
1064 /* Display success or failure */
1065 status = net_ads_join_ok(c);
1066 if (!NT_STATUS_IS_OK(status)) {
1067 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1068 get_friendly_nt_error_msg(status));
1072 printf(_("Join is OK\n"));
1076 /*******************************************************************
1077 Simple configu checks before beginning the join
1078 ********************************************************************/
1080 static WERROR check_ads_config( void )
1082 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1083 d_printf(_("Host is not configured as a member server.\n"));
1084 return WERR_INVALID_DOMAIN_ROLE;
1087 if (strlen(global_myname()) > 15) {
1088 d_printf(_("Our netbios name can be at most 15 chars long, "
1089 "\"%s\" is %u chars long\n"), global_myname(),
1090 (unsigned int)strlen(global_myname()));
1091 return WERR_INVALID_COMPUTERNAME;
1094 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1095 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1096 "join to succeed.\n"), get_dyn_CONFIGFILE());
1097 return WERR_INVALID_PARAM;
1103 /*******************************************************************
1104 Send a DNS update request
1105 *******************************************************************/
1107 #if defined(WITH_DNS_UPDATES)
1109 DNS_ERROR DoDNSUpdate(char *pszServerName,
1110 const char *pszDomainName, const char *pszHostName,
1111 const struct sockaddr_storage *sslist,
1114 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1115 const char *machine_name,
1116 const struct sockaddr_storage *addrs,
1119 struct dns_rr_ns *nameservers = NULL;
1121 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1124 const char *dnsdomain = NULL;
1125 char *root_domain = NULL;
1127 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1128 d_printf(_("No DNS domain configured for %s. "
1129 "Unable to perform DNS Update.\n"), machine_name);
1130 status = NT_STATUS_INVALID_PARAMETER;
1135 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1136 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1137 /* Child domains often do not have NS records. Look
1138 for the NS record for the forest root domain
1139 (rootDomainNamingContext in therootDSE) */
1141 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1142 LDAPMessage *msg = NULL;
1144 ADS_STATUS ads_status;
1146 if ( !ads->ldap.ld ) {
1147 ads_status = ads_connect( ads );
1148 if ( !ADS_ERR_OK(ads_status) ) {
1149 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1154 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1155 "(objectclass=*)", rootname_attrs, &msg);
1156 if (!ADS_ERR_OK(ads_status)) {
1160 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1162 ads_msgfree( ads, msg );
1166 root_domain = ads_build_domain( root_dn );
1169 ads_msgfree( ads, msg );
1171 /* try again for NS servers */
1173 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1175 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1176 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1177 "realm\n", ads->config.realm));
1181 dnsdomain = root_domain;
1185 /* Now perform the dns update - we'll try non-secure and if we fail,
1186 we'll follow it up with a secure update */
1188 fstrcpy( dns_server, nameservers[0].hostname );
1190 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1191 if (!ERR_DNS_IS_OK(dns_err)) {
1192 status = NT_STATUS_UNSUCCESSFUL;
1197 SAFE_FREE( root_domain );
1202 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1205 struct sockaddr_storage *iplist = NULL;
1206 fstring machine_name;
1209 name_to_fqdn( machine_name, global_myname() );
1210 strlower_m( machine_name );
1212 /* Get our ip address (not the 127.0.0.x address but a real ip
1215 num_addrs = get_my_ip_address( &iplist );
1216 if ( num_addrs <= 0 ) {
1217 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1219 return NT_STATUS_INVALID_PARAMETER;
1222 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1224 SAFE_FREE( iplist );
1230 /*******************************************************************
1231 ********************************************************************/
1233 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1235 d_printf(_("net ads join [options]\n"
1236 "Valid options:\n"));
1237 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1238 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1239 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1240 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1241 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1242 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1243 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1244 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1245 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1246 " NB: osName and osVer must be specified together for either to take effect.\n"
1247 " Also, the operatingSystemService attribute is also set when along with\n"
1248 " the two other attributes.\n"));
1253 /*******************************************************************
1254 ********************************************************************/
1256 int net_ads_join(struct net_context *c, int argc, const char **argv)
1258 TALLOC_CTX *ctx = NULL;
1259 struct libnet_JoinCtx *r = NULL;
1260 const char *domain = lp_realm();
1261 WERROR werr = WERR_SETUP_NOT_JOINED;
1262 bool createupn = false;
1263 const char *machineupn = NULL;
1264 const char *create_in_ou = NULL;
1266 const char *os_name = NULL;
1267 const char *os_version = NULL;
1268 bool modify_config = lp_config_backend_is_registry();
1270 if (c->display_usage)
1271 return net_ads_join_usage(c, argc, argv);
1273 if (!modify_config) {
1275 werr = check_ads_config();
1276 if (!W_ERROR_IS_OK(werr)) {
1277 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1282 if (!(ctx = talloc_init("net_ads_join"))) {
1283 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1288 if (!c->opt_kerberos) {
1289 use_in_memory_ccache();
1292 werr = libnet_init_JoinCtx(ctx, &r);
1293 if (!W_ERROR_IS_OK(werr)) {
1297 /* process additional command line args */
1299 for ( i=0; i<argc; i++ ) {
1300 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1302 machineupn = get_string_param(argv[i]);
1304 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1305 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1306 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1307 werr = WERR_INVALID_PARAM;
1311 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1312 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1313 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1314 werr = WERR_INVALID_PARAM;
1318 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1319 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1320 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1321 werr = WERR_INVALID_PARAM;
1331 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1332 werr = WERR_INVALID_PARAM;
1336 /* Do the domain join here */
1338 r->in.domain_name = domain;
1339 r->in.create_upn = createupn;
1340 r->in.upn = machineupn;
1341 r->in.account_ou = create_in_ou;
1342 r->in.os_name = os_name;
1343 r->in.os_version = os_version;
1344 r->in.dc_name = c->opt_host;
1345 r->in.admin_account = c->opt_user_name;
1346 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1348 r->in.use_kerberos = c->opt_kerberos;
1349 r->in.modify_config = modify_config;
1350 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1351 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1352 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1354 werr = libnet_Join(ctx, r);
1355 if (!W_ERROR_IS_OK(werr)) {
1359 /* Check the short name of the domain */
1361 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1362 d_printf(_("The workgroup in %s does not match the short\n"
1363 "domain name obtained from the server.\n"
1364 "Using the name [%s] from the server.\n"
1365 "You should set \"workgroup = %s\" in %s.\n"),
1366 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1367 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1370 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1372 if (r->out.dns_domain_name) {
1373 d_printf(_("Joined '%s' to realm '%s'\n"), r->in.machine_name,
1374 r->out.dns_domain_name);
1376 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1377 r->out.netbios_domain_name);
1380 #if defined(WITH_DNS_UPDATES)
1381 if (r->out.domain_is_ad) {
1382 /* We enter this block with user creds */
1383 ADS_STRUCT *ads_dns = NULL;
1385 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1386 /* kinit with the machine password */
1388 use_in_memory_ccache();
1389 if (asprintf( &ads_dns->auth.user_name, "%s$", global_myname()) == -1) {
1392 ads_dns->auth.password = secrets_fetch_machine_password(
1393 r->out.netbios_domain_name, NULL, NULL );
1394 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1395 strupper_m(ads_dns->auth.realm );
1396 ads_kinit_password( ads_dns );
1399 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1400 d_fprintf( stderr, _("DNS update failed!\n") );
1403 /* exit from this block using machine creds */
1404 ads_destroy(&ads_dns);
1413 /* issue an overall failure message at the end. */
1414 d_printf(_("Failed to join domain: %s\n"),
1415 r && r->out.error_string ? r->out.error_string :
1416 get_friendly_werror_msg(werr));
1422 /*******************************************************************
1423 ********************************************************************/
1425 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1427 #if defined(WITH_DNS_UPDATES)
1433 talloc_enable_leak_report();
1436 if (argc > 0 || c->display_usage) {
1438 "net ads dns register\n"
1441 _("Register hostname with DNS\n"));
1445 if (!(ctx = talloc_init("net_ads_dns"))) {
1446 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1450 status = ads_startup(c, true, &ads);
1451 if ( !ADS_ERR_OK(status) ) {
1452 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1457 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1458 d_fprintf( stderr, _("DNS update failed!\n") );
1459 ads_destroy( &ads );
1464 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1472 _("DNS update support not enabled at compile time!\n"));
1477 #if defined(WITH_DNS_UPDATES)
1478 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1481 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1483 #if defined(WITH_DNS_UPDATES)
1487 talloc_enable_leak_report();
1490 if (argc != 2 || c->display_usage) {
1495 _("net ads dns gethostbyname <server> <name>\n"),
1496 _(" Look up hostname from the AD\n"
1497 " server\tName server to use\n"
1498 " name\tName to look up\n"));
1502 err = do_gethostbyname(argv[0], argv[1]);
1504 d_printf(_("do_gethostbyname returned %d\n"), ERROR_DNS_V(err));
1509 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1511 struct functable func[] = {
1514 net_ads_dns_register,
1516 N_("Add host dns entry to AD"),
1517 N_("net ads dns register\n"
1518 " Add host dns entry to AD")
1522 net_ads_dns_gethostbyname,
1525 N_("net ads dns gethostbyname\n"
1528 {NULL, NULL, 0, NULL, NULL}
1531 return net_run_function(c, argc, argv, "net ads dns", func);
1534 /*******************************************************************
1535 ********************************************************************/
1537 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1540 "\nnet ads printer search <printer>"
1541 "\n\tsearch for a printer in the directory\n"
1542 "\nnet ads printer info <printer> <server>"
1543 "\n\tlookup info in directory for printer on server"
1544 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1545 "\nnet ads printer publish <printername>"
1546 "\n\tpublish printer in directory"
1547 "\n\t(note: printer name is required)\n"
1548 "\nnet ads printer remove <printername>"
1549 "\n\tremove printer from directory"
1550 "\n\t(note: printer name is required)\n"));
1554 /*******************************************************************
1555 ********************************************************************/
1557 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1561 LDAPMessage *res = NULL;
1563 if (c->display_usage) {
1565 "net ads printer search\n"
1568 _("List printers in the AD"));
1572 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1576 rc = ads_find_printers(ads, &res);
1578 if (!ADS_ERR_OK(rc)) {
1579 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
1580 ads_msgfree(ads, res);
1585 if (ads_count_replies(ads, res) == 0) {
1586 d_fprintf(stderr, _("No results found\n"));
1587 ads_msgfree(ads, res);
1593 ads_msgfree(ads, res);
1598 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1602 const char *servername, *printername;
1603 LDAPMessage *res = NULL;
1605 if (c->display_usage) {
1608 _("net ads printer info [printername [servername]]\n"
1609 " Display printer info from AD\n"
1610 " printername\tPrinter name or wildcard\n"
1611 " servername\tName of the print server\n"));
1615 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1620 printername = argv[0];
1626 servername = argv[1];
1628 servername = global_myname();
1631 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1633 if (!ADS_ERR_OK(rc)) {
1634 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
1635 servername, ads_errstr(rc));
1636 ads_msgfree(ads, res);
1641 if (ads_count_replies(ads, res) == 0) {
1642 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
1643 ads_msgfree(ads, res);
1649 ads_msgfree(ads, res);
1655 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1659 const char *servername, *printername;
1660 struct cli_state *cli = NULL;
1661 struct rpc_pipe_client *pipe_hnd = NULL;
1662 struct sockaddr_storage server_ss;
1664 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1665 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1666 char *prt_dn, *srv_dn, **srv_cn;
1667 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1668 LDAPMessage *res = NULL;
1670 if (argc < 1 || c->display_usage) {
1673 _("net ads printer publish <printername> [servername]\n"
1674 " Publish printer in AD\n"
1675 " printername\tName of the printer\n"
1676 " servername\tName of the print server\n"));
1677 talloc_destroy(mem_ctx);
1681 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1682 talloc_destroy(mem_ctx);
1686 printername = argv[0];
1689 servername = argv[1];
1691 servername = global_myname();
1694 /* Get printer data from SPOOLSS */
1696 resolve_name(servername, &server_ss, 0x20, false);
1698 nt_status = cli_full_connection(&cli, global_myname(), servername,
1701 c->opt_user_name, c->opt_workgroup,
1702 c->opt_password ? c->opt_password : "",
1703 CLI_FULL_CONNECTION_USE_KERBEROS,
1706 if (NT_STATUS_IS_ERR(nt_status)) {
1707 d_fprintf(stderr, _("Unable to open a connnection to %s to "
1708 "obtain data for %s\n"),
1709 servername, printername);
1711 talloc_destroy(mem_ctx);
1715 /* Publish on AD server */
1717 ads_find_machine_acct(ads, &res, servername);
1719 if (ads_count_replies(ads, res) == 0) {
1720 d_fprintf(stderr, _("Could not find machine account for server "
1724 talloc_destroy(mem_ctx);
1728 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1729 srv_cn = ldap_explode_dn(srv_dn, 1);
1731 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1732 printername_escaped = escape_rdn_val_string_alloc(printername);
1733 if (!srv_cn_escaped || !printername_escaped) {
1734 SAFE_FREE(srv_cn_escaped);
1735 SAFE_FREE(printername_escaped);
1736 d_fprintf(stderr, _("Internal error, out of memory!"));
1738 talloc_destroy(mem_ctx);
1742 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1743 SAFE_FREE(srv_cn_escaped);
1744 SAFE_FREE(printername_escaped);
1745 d_fprintf(stderr, _("Internal error, out of memory!"));
1747 talloc_destroy(mem_ctx);
1751 SAFE_FREE(srv_cn_escaped);
1752 SAFE_FREE(printername_escaped);
1754 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
1755 if (!NT_STATUS_IS_OK(nt_status)) {
1756 d_fprintf(stderr, _("Unable to open a connnection to the spoolss pipe on %s\n"),
1760 talloc_destroy(mem_ctx);
1764 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1768 talloc_destroy(mem_ctx);
1772 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1773 if (!ADS_ERR_OK(rc)) {
1774 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1777 talloc_destroy(mem_ctx);
1781 d_printf("published printer\n");
1784 talloc_destroy(mem_ctx);
1789 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1793 const char *servername;
1795 LDAPMessage *res = NULL;
1797 if (argc < 1 || c->display_usage) {
1800 _("net ads printer remove <printername> [servername]\n"
1801 " Remove a printer from the AD\n"
1802 " printername\tName of the printer\n"
1803 " servername\tName of the print server\n"));
1807 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1812 servername = argv[1];
1814 servername = global_myname();
1817 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1819 if (!ADS_ERR_OK(rc)) {
1820 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
1821 ads_msgfree(ads, res);
1826 if (ads_count_replies(ads, res) == 0) {
1827 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
1828 ads_msgfree(ads, res);
1833 prt_dn = ads_get_dn(ads, talloc_tos(), res);
1834 ads_msgfree(ads, res);
1835 rc = ads_del_dn(ads, prt_dn);
1836 TALLOC_FREE(prt_dn);
1838 if (!ADS_ERR_OK(rc)) {
1839 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
1848 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1850 struct functable func[] = {
1853 net_ads_printer_search,
1855 N_("Search for a printer"),
1856 N_("net ads printer search\n"
1857 " Search for a printer")
1861 net_ads_printer_info,
1863 N_("Display printer information"),
1864 N_("net ads printer info\n"
1865 " Display printer information")
1869 net_ads_printer_publish,
1871 N_("Publish a printer"),
1872 N_("net ads printer publish\n"
1873 " Publish a printer")
1877 net_ads_printer_remove,
1879 N_("Delete a printer"),
1880 N_("net ads printer remove\n"
1881 " Delete a printer")
1883 {NULL, NULL, 0, NULL, NULL}
1886 return net_run_function(c, argc, argv, "net ads printer", func);
1890 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1893 const char *auth_principal = c->opt_user_name;
1894 const char *auth_password = c->opt_password;
1896 char *new_password = NULL;
1901 if (c->display_usage) {
1904 _("net ads password <username>\n"
1905 " Change password for user\n"
1906 " username\tName of user to change password for\n"));
1910 if (c->opt_user_name == NULL || c->opt_password == NULL) {
1911 d_fprintf(stderr, _("You must supply an administrator "
1912 "username/password\n"));
1917 d_fprintf(stderr, _("ERROR: You must say which username to "
1918 "change password for\n"));
1923 if (!strchr_m(user, '@')) {
1924 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
1930 use_in_memory_ccache();
1931 chr = strchr_m(auth_principal, '@');
1938 /* use the realm so we can eventually change passwords for users
1939 in realms other than default */
1940 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1944 /* we don't actually need a full connect, but it's the easy way to
1945 fill in the KDC's addresss */
1948 if (!ads->config.realm) {
1949 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
1955 new_password = (char *)argv[1];
1957 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
1960 new_password = getpass(prompt);
1964 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1965 auth_password, user, new_password, ads->auth.time_offset);
1966 if (!ADS_ERR_OK(ret)) {
1967 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
1972 d_printf(_("Password change for %s completed.\n"), user);
1978 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1981 char *host_principal;
1985 if (c->display_usage) {
1987 "net ads changetrustpw\n"
1990 _("Change the machine account's trust password"));
1994 if (!secrets_init()) {
1995 DEBUG(1,("Failed to initialise secrets database\n"));
1999 net_use_krb_machine_account(c);
2001 use_in_memory_ccache();
2003 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2007 fstrcpy(my_name, global_myname());
2008 strlower_m(my_name);
2009 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2013 d_printf(_("Changing password for principal: %s\n"), host_principal);
2015 ret = ads_change_trust_account_password(ads, host_principal);
2017 if (!ADS_ERR_OK(ret)) {
2018 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2020 SAFE_FREE(host_principal);
2024 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2026 if (USE_SYSTEM_KEYTAB) {
2027 d_printf(_("Attempting to update system keytab with new password.\n"));
2028 if (ads_keytab_create_default(ads)) {
2029 d_printf(_("Failed to update system keytab.\n"));
2034 SAFE_FREE(host_principal);
2040 help for net ads search
2042 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2045 "\nnet ads search <expression> <attributes...>\n"
2046 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2047 "The expression is a standard LDAP search expression, and the\n"
2048 "attributes are a list of LDAP fields to show in the results.\n\n"
2049 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2051 net_common_flags_usage(c, argc, argv);
2057 general ADS search function. Useful in diagnosing problems in ADS
2059 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2063 const char *ldap_exp;
2065 LDAPMessage *res = NULL;
2067 if (argc < 1 || c->display_usage) {
2068 return net_ads_search_usage(c, argc, argv);
2071 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2078 rc = ads_do_search_all(ads, ads->config.bind_path,
2080 ldap_exp, attrs, &res);
2081 if (!ADS_ERR_OK(rc)) {
2082 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2087 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2089 /* dump the results */
2092 ads_msgfree(ads, res);
2100 help for net ads search
2102 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2105 "\nnet ads dn <dn> <attributes...>\n"
2106 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2107 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2108 "to show in the results\n\n"
2109 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2110 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2112 net_common_flags_usage(c, argc, argv);
2118 general ADS search function. Useful in diagnosing problems in ADS
2120 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2126 LDAPMessage *res = NULL;
2128 if (argc < 1 || c->display_usage) {
2129 return net_ads_dn_usage(c, argc, argv);
2132 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2139 rc = ads_do_search_all(ads, dn,
2141 "(objectclass=*)", attrs, &res);
2142 if (!ADS_ERR_OK(rc)) {
2143 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2148 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2150 /* dump the results */
2153 ads_msgfree(ads, res);
2160 help for net ads sid search
2162 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2165 "\nnet ads sid <sid> <attributes...>\n"
2166 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2167 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2168 "to show in the results\n\n"
2169 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2171 net_common_flags_usage(c, argc, argv);
2177 general ADS search function. Useful in diagnosing problems in ADS
2179 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2183 const char *sid_string;
2185 LDAPMessage *res = NULL;
2188 if (argc < 1 || c->display_usage) {
2189 return net_ads_sid_usage(c, argc, argv);
2192 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2196 sid_string = argv[0];
2199 if (!string_to_sid(&sid, sid_string)) {
2200 d_fprintf(stderr, _("could not convert sid\n"));
2205 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2206 if (!ADS_ERR_OK(rc)) {
2207 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2212 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2214 /* dump the results */
2217 ads_msgfree(ads, res);
2223 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2228 if (c->display_usage) {
2230 "net ads keytab flush\n"
2233 _("Delete the whole keytab"));
2237 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2240 ret = ads_keytab_flush(ads);
2245 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2251 if (c->display_usage) {
2254 _("net ads keytab add <principal> [principal ...]\n"
2255 " Add principals to local keytab\n"
2256 " principal\tKerberos principal to add to "
2261 d_printf(_("Processing principals to add...\n"));
2262 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2265 for (i = 0; i < argc; i++) {
2266 ret |= ads_keytab_add_entry(ads, argv[i]);
2272 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2277 if (c->display_usage) {
2279 "net ads keytab create\n"
2282 _("Create new default keytab"));
2286 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2289 ret = ads_keytab_create_default(ads);
2294 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2296 const char *keytab = NULL;
2298 if (c->display_usage) {
2301 _("net ads keytab list [keytab]\n"
2302 " List a local keytab\n"
2303 " keytab\tKeytab to list\n"));
2311 return ads_keytab_list(keytab);
2315 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2317 struct functable func[] = {
2322 N_("Add a service principal"),
2323 N_("net ads keytab add\n"
2324 " Add a service principal")
2328 net_ads_keytab_create,
2330 N_("Create a fresh keytab"),
2331 N_("net ads keytab create\n"
2332 " Create a fresh keytab")
2336 net_ads_keytab_flush,
2338 N_("Remove all keytab entries"),
2339 N_("net ads keytab flush\n"
2340 " Remove all keytab entries")
2344 net_ads_keytab_list,
2346 N_("List a keytab"),
2347 N_("net ads keytab list\n"
2350 {NULL, NULL, 0, NULL, NULL}
2353 if (!USE_KERBEROS_KEYTAB) {
2354 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2355 "keytab method to use keytab functions.\n"));
2358 return net_run_function(c, argc, argv, "net ads keytab", func);
2361 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2365 if (c->display_usage) {
2367 "net ads kerberos renew\n"
2370 _("Renew TGT from existing credential cache"));
2374 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2376 d_printf(_("failed to renew kerberos ticket: %s\n"),
2377 error_message(ret));
2382 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2384 struct PAC_LOGON_INFO *info = NULL;
2385 TALLOC_CTX *mem_ctx = NULL;
2388 const char *impersonate_princ_s = NULL;
2390 if (c->display_usage) {
2392 "net ads kerberos pac\n"
2395 _("Dump the Kerberos PAC"));
2399 mem_ctx = talloc_init("net_ads_kerberos_pac");
2405 impersonate_princ_s = argv[0];
2408 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2410 status = kerberos_return_pac(mem_ctx,
2419 2592000, /* one month */
2420 impersonate_princ_s,
2422 if (!NT_STATUS_IS_OK(status)) {
2423 d_printf(_("failed to query kerberos PAC: %s\n"),
2430 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2431 d_printf(_("The Pac: %s\n"), s);
2436 TALLOC_FREE(mem_ctx);
2440 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2442 TALLOC_CTX *mem_ctx = NULL;
2446 if (c->display_usage) {
2448 "net ads kerberos kinit\n"
2451 _("Get Ticket Granting Ticket (TGT) for the user"));
2455 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2460 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2462 ret = kerberos_kinit_password_ext(c->opt_user_name,
2470 2592000, /* one month */
2473 d_printf(_("failed to kinit password: %s\n"),
2480 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2482 struct functable func[] = {
2485 net_ads_kerberos_kinit,
2487 N_("Retrieve Ticket Granting Ticket (TGT)"),
2488 N_("net ads kerberos kinit\n"
2489 " Receive Ticket Granting Ticket (TGT)")
2493 net_ads_kerberos_renew,
2495 N_("Renew Ticket Granting Ticket from credential cache"),
2496 N_("net ads kerberos renew\n"
2497 " Renew Ticket Granting Ticket (TGT) from "
2502 net_ads_kerberos_pac,
2504 N_("Dump Kerberos PAC"),
2505 N_("net ads kerberos pac\n"
2506 " Dump Kerberos PAC")
2508 {NULL, NULL, 0, NULL, NULL}
2511 return net_run_function(c, argc, argv, "net ads kerberos", func);
2514 int net_ads(struct net_context *c, int argc, const char **argv)
2516 struct functable func[] = {
2521 N_("Display details on remote ADS server"),
2523 " Display details on remote ADS server")
2529 N_("Join the local machine to ADS realm"),
2531 " Join the local machine to ADS realm")
2537 N_("Validate machine account"),
2538 N_("net ads testjoin\n"
2539 " Validate machine account")
2545 N_("Remove the local machine from ADS"),
2546 N_("net ads leave\n"
2547 " Remove the local machine from ADS")
2553 N_("Display machine account details"),
2554 N_("net ads status\n"
2555 " Display machine account details")
2561 N_("List/modify users"),
2563 " List/modify users")
2569 N_("List/modify groups"),
2570 N_("net ads group\n"
2571 " List/modify groups")
2577 N_("Issue dynamic DNS update"),
2579 " Issue dynamic DNS update")
2585 N_("Change user passwords"),
2586 N_("net ads password\n"
2587 " Change user passwords")
2591 net_ads_changetrustpw,
2593 N_("Change trust account password"),
2594 N_("net ads changetrustpw\n"
2595 " Change trust account password")
2601 N_("List/modify printer entries"),
2602 N_("net ads printer\n"
2603 " List/modify printer entries")
2609 N_("Issue LDAP search using filter"),
2610 N_("net ads search\n"
2611 " Issue LDAP search using filter")
2617 N_("Issue LDAP search by DN"),
2619 " Issue LDAP search by DN")
2625 N_("Issue LDAP search by SID"),
2627 " Issue LDAP search by SID")
2633 N_("Display workgroup name"),
2634 N_("net ads workgroup\n"
2635 " Display the workgroup name")
2641 N_("Perfom CLDAP query on DC"),
2642 N_("net ads lookup\n"
2643 " Find the ADS DC using CLDAP lookups")
2649 N_("Manage local keytab file"),
2650 N_("net ads keytab\n"
2651 " Manage local keytab file")
2657 N_("Manage group policy objects"),
2659 " Manage group policy objects")
2665 N_("Manage kerberos keytab"),
2666 N_("net ads kerberos\n"
2667 " Manage kerberos keytab")
2669 {NULL, NULL, 0, NULL, NULL}
2672 return net_run_function(c, argc, argv, "net ads", func);
2677 static int net_ads_noads(void)
2679 d_fprintf(stderr, _("ADS support not compiled in\n"));
2683 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2685 return net_ads_noads();
2688 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2690 return net_ads_noads();
2693 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2695 return net_ads_noads();
2698 int net_ads_join(struct net_context *c, int argc, const char **argv)
2700 return net_ads_noads();
2703 int net_ads_user(struct net_context *c, int argc, const char **argv)
2705 return net_ads_noads();
2708 int net_ads_group(struct net_context *c, int argc, const char **argv)
2710 return net_ads_noads();
2713 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
2715 return net_ads_noads();
2718 /* this one shouldn't display a message */
2719 int net_ads_check(struct net_context *c)
2724 int net_ads_check_our_domain(struct net_context *c)
2729 int net_ads(struct net_context *c, int argc, const char **argv)
2731 return net_ads_noads();
2734 #endif /* WITH_ADS */