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"
28 /* when we do not have sufficient input parameters to contact a remote domain
29 * we always fall back to our own realm - Guenther*/
31 static const char *assume_own_realm(struct net_context *c)
33 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
41 do a cldap netlogon query
43 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
45 char addr[INET6_ADDRSTRLEN];
46 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
48 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
49 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
50 d_fprintf(stderr, "CLDAP query failed!\n");
54 d_printf("Information for Domain Controller: %s\n\n",
57 d_printf("Response Type: ");
58 switch (reply.command) {
59 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
60 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
62 case LOGON_SAM_LOGON_RESPONSE_EX:
63 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
66 d_printf("0x%x\n", reply.command);
70 d_printf("GUID: %s\n", GUID_string(talloc_tos(), &reply.domain_uuid));
74 "\tIs a GC of the forest: %s\n"
75 "\tIs an LDAP server: %s\n"
77 "\tIs running a KDC: %s\n"
78 "\tIs running time services: %s\n"
79 "\tIs the closest DC: %s\n"
81 "\tHas a hardware clock: %s\n"
82 "\tIs a non-domain NC serviced by LDAP server: %s\n"
83 "\tIs NT6 DC that has some secrets: %s\n"
84 "\tIs NT6 DC that has all secrets: %s\n",
85 (reply.server_type & NBT_SERVER_PDC) ? "yes" : "no",
86 (reply.server_type & NBT_SERVER_GC) ? "yes" : "no",
87 (reply.server_type & NBT_SERVER_LDAP) ? "yes" : "no",
88 (reply.server_type & NBT_SERVER_DS) ? "yes" : "no",
89 (reply.server_type & NBT_SERVER_KDC) ? "yes" : "no",
90 (reply.server_type & NBT_SERVER_TIMESERV) ? "yes" : "no",
91 (reply.server_type & NBT_SERVER_CLOSEST) ? "yes" : "no",
92 (reply.server_type & NBT_SERVER_WRITABLE) ? "yes" : "no",
93 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? "yes" : "no",
94 (reply.server_type & NBT_SERVER_NDNC) ? "yes" : "no",
95 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? "yes" : "no",
96 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? "yes" : "no");
99 printf("Forest:\t\t\t%s\n", reply.forest);
100 printf("Domain:\t\t\t%s\n", reply.dns_domain);
101 printf("Domain Controller:\t%s\n", reply.pdc_dns_name);
103 printf("Pre-Win2k Domain:\t%s\n", reply.domain);
104 printf("Pre-Win2k Hostname:\t%s\n", reply.pdc_name);
106 if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
108 printf("Server Site Name :\t\t%s\n", reply.server_site);
109 printf("Client Site Name :\t\t%s\n", reply.client_site);
111 d_printf("NT Version: %d\n", reply.nt_version);
112 d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
113 d_printf("LM20 Token: %.2x\n", reply.lm20_token);
119 this implements the CLDAP based netlogon lookup requests
120 for finding the domain controller of a ADS domain
122 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
126 if (c->display_usage) {
129 " Find the ADS DC using CLDAP lookup.\n");
133 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
134 d_fprintf(stderr, "Didn't find the cldap server!\n");
138 if (!ads->config.realm) {
139 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
140 ads->ldap.port = 389;
143 return net_ads_cldap_netlogon(c, ads);
148 static int net_ads_info(struct net_context *c, int argc, const char **argv)
151 char addr[INET6_ADDRSTRLEN];
153 if (c->display_usage) {
156 " Display information about an Active Directory "
161 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
162 d_fprintf(stderr, "Didn't find the ldap server!\n");
166 if (!ads || !ads->config.realm) {
167 d_fprintf(stderr, "Didn't find the ldap server!\n");
171 /* Try to set the server's current time since we didn't do a full
172 TCP LDAP session initially */
174 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
175 d_fprintf( stderr, "Failed to get server's current time!\n");
178 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
180 d_printf("LDAP server: %s\n", addr);
181 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
182 d_printf("Realm: %s\n", ads->config.realm);
183 d_printf("Bind Path: %s\n", ads->config.bind_path);
184 d_printf("LDAP port: %d\n", ads->ldap.port);
185 d_printf("Server time: %s\n",
186 http_timestring(talloc_tos(), ads->config.current_time));
188 d_printf("KDC server: %s\n", ads->auth.kdc_server );
189 d_printf("Server time offset: %d\n", ads->auth.time_offset );
194 static void use_in_memory_ccache(void) {
195 /* Use in-memory credentials cache so we do not interfere with
196 * existing credentials */
197 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
200 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
201 uint32 auth_flags, ADS_STRUCT **ads_ret)
203 ADS_STRUCT *ads = NULL;
205 bool need_password = false;
206 bool second_time = false;
208 const char *realm = NULL;
209 bool tried_closest_dc = false;
211 /* lp_realm() should be handled by a command line param,
212 However, the join requires that realm be set in smb.conf
213 and compares our realm with the remote server's so this is
214 ok until someone needs more flexibility */
219 if (only_own_domain) {
222 realm = assume_own_realm(c);
225 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
227 if (!c->opt_user_name) {
228 c->opt_user_name = "administrator";
231 if (c->opt_user_specified) {
232 need_password = true;
236 if (!c->opt_password && need_password && !c->opt_machine_pass) {
237 c->opt_password = net_prompt_pass(c, c->opt_user_name);
238 if (!c->opt_password) {
240 return ADS_ERROR(LDAP_NO_MEMORY);
244 if (c->opt_password) {
245 use_in_memory_ccache();
246 SAFE_FREE(ads->auth.password);
247 ads->auth.password = smb_xstrdup(c->opt_password);
250 ads->auth.flags |= auth_flags;
251 SAFE_FREE(ads->auth.user_name);
252 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
255 * If the username is of the form "name@realm",
256 * extract the realm and convert to upper case.
257 * This is only used to establish the connection.
259 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
261 SAFE_FREE(ads->auth.realm);
262 ads->auth.realm = smb_xstrdup(cp);
263 strupper_m(ads->auth.realm);
266 status = ads_connect(ads);
268 if (!ADS_ERR_OK(status)) {
270 if (NT_STATUS_EQUAL(ads_ntstatus(status),
271 NT_STATUS_NO_LOGON_SERVERS)) {
272 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
277 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
278 need_password = true;
287 /* when contacting our own domain, make sure we use the closest DC.
288 * This is done by reconnecting to ADS because only the first call to
289 * ads_connect will give us our own sitename */
291 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
293 tried_closest_dc = true; /* avoid loop */
295 if (!ads->config.tried_closest_dc) {
297 namecache_delete(ads->server.realm, 0x1C);
298 namecache_delete(ads->server.workgroup, 0x1C);
311 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
313 return ads_startup_int(c, only_own_domain, 0, ads);
316 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
318 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
322 Check to see if connection can be made via ads.
323 ads_startup() stores the password in opt_password if it needs to so
324 that rpc or rap can use it without re-prompting.
326 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
331 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
335 ads->auth.flags |= ADS_AUTH_NO_BIND;
337 status = ads_connect(ads);
338 if ( !ADS_ERR_OK(status) ) {
346 int net_ads_check_our_domain(struct net_context *c)
348 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
351 int net_ads_check(struct net_context *c)
353 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
357 determine the netbios workgroup name for a domain
359 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
362 char addr[INET6_ADDRSTRLEN];
363 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
365 if (c->display_usage) {
367 "net ads workgroup\n"
368 " Print the workgroup name\n");
372 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
373 d_fprintf(stderr, "Didn't find the cldap server!\n");
377 if (!ads->config.realm) {
378 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
379 ads->ldap.port = 389;
382 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
383 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
384 d_fprintf(stderr, "CLDAP query failed!\n");
388 d_printf("Workgroup: %s\n", reply.domain);
397 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
399 char **disp_fields = (char **) data_area;
401 if (!field) { /* must be end of record */
402 if (disp_fields[0]) {
403 if (!strchr_m(disp_fields[0], '$')) {
405 d_printf("%-21.21s %s\n",
406 disp_fields[0], disp_fields[1]);
408 d_printf("%s\n", disp_fields[0]);
411 SAFE_FREE(disp_fields[0]);
412 SAFE_FREE(disp_fields[1]);
415 if (!values) /* must be new field, indicate string field */
417 if (StrCaseCmp(field, "sAMAccountName") == 0) {
418 disp_fields[0] = SMB_STRDUP((char *) values[0]);
420 if (StrCaseCmp(field, "description") == 0)
421 disp_fields[1] = SMB_STRDUP((char *) values[0]);
425 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
427 return net_user_usage(c, argc, argv);
430 static int ads_user_add(struct net_context *c, int argc, const char **argv)
435 LDAPMessage *res=NULL;
439 if (argc < 1 || c->display_usage)
440 return net_ads_user_usage(c, argc, argv);
442 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
446 status = ads_find_user_acct(ads, &res, argv[0]);
448 if (!ADS_ERR_OK(status)) {
449 d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
453 if (ads_count_replies(ads, res)) {
454 d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
458 if (c->opt_container) {
459 ou_str = SMB_STRDUP(c->opt_container);
461 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
464 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
466 if (!ADS_ERR_OK(status)) {
467 d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
472 /* if no password is to be set, we're done */
474 d_printf("User %s added\n", argv[0]);
479 /* try setting the password */
480 asprintf(&upn, "%s@%s", argv[0], ads->config.realm);
481 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
482 ads->auth.time_offset);
484 if (ADS_ERR_OK(status)) {
485 d_printf("User %s added\n", argv[0]);
490 /* password didn't set, delete account */
491 d_fprintf(stderr, "Could not add user %s. Error setting password %s\n",
492 argv[0], ads_errstr(status));
493 ads_msgfree(ads, res);
494 status=ads_find_user_acct(ads, &res, argv[0]);
495 if (ADS_ERR_OK(status)) {
496 userdn = ads_get_dn(ads, res);
497 ads_del_dn(ads, userdn);
498 ads_memfree(ads, userdn);
503 ads_msgfree(ads, res);
509 static int ads_user_info(struct net_context *c, int argc, const char **argv)
514 const char *attrs[] = {"memberOf", NULL};
515 char *searchstring=NULL;
519 if (argc < 1 || c->display_usage) {
520 return net_ads_user_usage(c, argc, argv);
523 escaped_user = escape_ldap_string_alloc(argv[0]);
526 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
530 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
531 SAFE_FREE(escaped_user);
535 asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user);
536 rc = ads_search(ads, &res, searchstring, attrs);
537 safe_free(searchstring);
539 if (!ADS_ERR_OK(rc)) {
540 d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
542 SAFE_FREE(escaped_user);
546 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
547 (LDAPMessage *)res, "memberOf");
552 for (i=0;grouplist[i];i++) {
553 groupname = ldap_explode_dn(grouplist[i], 1);
554 d_printf("%s\n", groupname[0]);
555 ldap_value_free(groupname);
557 ldap_value_free(grouplist);
560 ads_msgfree(ads, res);
562 SAFE_FREE(escaped_user);
566 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
570 LDAPMessage *res = NULL;
574 return net_ads_user_usage(c, argc, argv);
577 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
581 rc = ads_find_user_acct(ads, &res, argv[0]);
582 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
583 d_printf("User %s does not exist.\n", argv[0]);
584 ads_msgfree(ads, res);
588 userdn = ads_get_dn(ads, res);
589 ads_msgfree(ads, res);
590 rc = ads_del_dn(ads, userdn);
591 ads_memfree(ads, userdn);
592 if (ADS_ERR_OK(rc)) {
593 d_printf("User %s deleted\n", argv[0]);
597 d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
603 int net_ads_user(struct net_context *c, int argc, const char **argv)
605 struct functable func[] = {
618 "Display information about an AD user",
619 "net ads user info\n"
620 " Display information about an AD user"
627 "net ads user delete\n"
630 {NULL, NULL, 0, NULL, NULL}
634 const char *shortattrs[] = {"sAMAccountName", NULL};
635 const char *longattrs[] = {"sAMAccountName", "description", NULL};
636 char *disp_fields[2] = {NULL, NULL};
639 if (c->display_usage) {
640 d_printf("Usage:\n");
641 d_printf("net ads user\n"
643 net_display_usage_from_functable(func);
647 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
651 if (c->opt_long_list_entries)
652 d_printf("\nUser name Comment"
653 "\n-----------------------------\n");
655 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
657 "(objectCategory=user)",
658 c->opt_long_list_entries ? longattrs :
659 shortattrs, usergrp_display,
662 return ADS_ERR_OK(rc) ? 0 : -1;
665 return net_run_function(c, argc, argv, "net ads user", func);
668 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
670 return net_group_usage(c, argc, argv);
673 static int ads_group_add(struct net_context *c, int argc, const char **argv)
677 LDAPMessage *res=NULL;
681 if (argc < 1 || c->display_usage) {
682 return net_ads_group_usage(c, argc, argv);
685 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
689 status = ads_find_user_acct(ads, &res, argv[0]);
691 if (!ADS_ERR_OK(status)) {
692 d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
696 if (ads_count_replies(ads, res)) {
697 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
701 if (c->opt_container) {
702 ou_str = SMB_STRDUP(c->opt_container);
704 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
707 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
709 if (ADS_ERR_OK(status)) {
710 d_printf("Group %s added\n", argv[0]);
713 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
719 ads_msgfree(ads, res);
725 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
729 LDAPMessage *res = NULL;
732 if (argc < 1 || c->display_usage) {
733 return net_ads_group_usage(c, argc, argv);
736 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
740 rc = ads_find_user_acct(ads, &res, argv[0]);
741 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
742 d_printf("Group %s does not exist.\n", argv[0]);
743 ads_msgfree(ads, res);
747 groupdn = ads_get_dn(ads, res);
748 ads_msgfree(ads, res);
749 rc = ads_del_dn(ads, groupdn);
750 ads_memfree(ads, groupdn);
751 if (ADS_ERR_OK(rc)) {
752 d_printf("Group %s deleted\n", argv[0]);
756 d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
762 int net_ads_group(struct net_context *c, int argc, const char **argv)
764 struct functable func[] = {
770 "net ads group add\n"
777 "Delete an AD group",
778 "net ads group delete\n"
779 " Delete an AD group"
781 {NULL, NULL, 0, NULL, NULL}
785 const char *shortattrs[] = {"sAMAccountName", NULL};
786 const char *longattrs[] = {"sAMAccountName", "description", NULL};
787 char *disp_fields[2] = {NULL, NULL};
790 if (c->display_usage) {
791 d_printf("Usage:\n");
792 d_printf("net ads group\n"
793 " List AD groups\n");
794 net_display_usage_from_functable(func);
798 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
802 if (c->opt_long_list_entries)
803 d_printf("\nGroup name Comment"
804 "\n-----------------------------\n");
805 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
807 "(objectCategory=group)",
808 c->opt_long_list_entries ? longattrs :
809 shortattrs, usergrp_display,
813 return ADS_ERR_OK(rc) ? 0 : -1;
815 return net_run_function(c, argc, argv, "net ads group", func);
818 static int net_ads_status(struct net_context *c, int argc, const char **argv)
824 if (c->display_usage) {
827 " Display machine account details\n");
831 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
835 rc = ads_find_machine_acct(ads, &res, global_myname());
836 if (!ADS_ERR_OK(rc)) {
837 d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
842 if (ads_count_replies(ads, res) == 0) {
843 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
853 /*******************************************************************
854 Leave an AD domain. Windows XP disables the machine account.
855 We'll try the same. The old code would do an LDAP delete.
856 That only worked using the machine creds because added the machine
857 with full control to the computer object's ACL.
858 *******************************************************************/
860 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
863 struct libnet_UnjoinCtx *r = NULL;
866 if (c->display_usage) {
869 " Leave an AD domain\n");
874 d_fprintf(stderr, "No realm set, are we joined ?\n");
878 if (!(ctx = talloc_init("net_ads_leave"))) {
879 d_fprintf(stderr, "Could not initialise talloc context.\n");
883 if (!c->opt_kerberos) {
884 use_in_memory_ccache();
887 werr = libnet_init_UnjoinCtx(ctx, &r);
888 if (!W_ERROR_IS_OK(werr)) {
889 d_fprintf(stderr, "Could not initialise unjoin context.\n");
894 r->in.use_kerberos = c->opt_kerberos;
895 r->in.dc_name = c->opt_host;
896 r->in.domain_name = lp_realm();
897 r->in.admin_account = c->opt_user_name;
898 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
899 r->in.modify_config = lp_config_backend_is_registry();
900 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
901 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
903 werr = libnet_Unjoin(ctx, r);
904 if (!W_ERROR_IS_OK(werr)) {
905 d_printf("Failed to leave domain: %s\n",
906 r->out.error_string ? r->out.error_string :
907 get_friendly_werror_msg(werr));
911 if (W_ERROR_IS_OK(werr)) {
912 d_printf("Deleted account for '%s' in realm '%s'\n",
913 r->in.machine_name, r->out.dns_domain_name);
917 /* We couldn't delete it - see if the disable succeeded. */
918 if (r->out.disabled_machine_account) {
919 d_printf("Disabled account for '%s' in realm '%s'\n",
920 r->in.machine_name, r->out.dns_domain_name);
925 d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
926 r->in.machine_name, r->out.dns_domain_name);
932 if (W_ERROR_IS_OK(werr)) {
939 static NTSTATUS net_ads_join_ok(struct net_context *c)
941 ADS_STRUCT *ads = NULL;
944 if (!secrets_init()) {
945 DEBUG(1,("Failed to initialise secrets database\n"));
946 return NT_STATUS_ACCESS_DENIED;
949 net_use_krb_machine_account(c);
951 status = ads_startup(c, true, &ads);
952 if (!ADS_ERR_OK(status)) {
953 return ads_ntstatus(status);
961 check that an existing join is OK
963 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
966 use_in_memory_ccache();
968 if (c->display_usage) {
971 " Test if the existing join is ok\n");
975 /* Display success or failure */
976 status = net_ads_join_ok(c);
977 if (!NT_STATUS_IS_OK(status)) {
978 fprintf(stderr,"Join to domain is not valid: %s\n",
979 get_friendly_nt_error_msg(status));
983 printf("Join is OK\n");
987 /*******************************************************************
988 Simple configu checks before beginning the join
989 ********************************************************************/
991 static WERROR check_ads_config( void )
993 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
994 d_printf("Host is not configured as a member server.\n");
995 return WERR_INVALID_DOMAIN_ROLE;
998 if (strlen(global_myname()) > 15) {
999 d_printf("Our netbios name can be at most 15 chars long, "
1000 "\"%s\" is %u chars long\n", global_myname(),
1001 (unsigned int)strlen(global_myname()));
1002 return WERR_INVALID_COMPUTER_NAME;
1005 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1006 d_fprintf(stderr, "realm must be set in in %s for ADS "
1007 "join to succeed.\n", get_dyn_CONFIGFILE());
1008 return WERR_INVALID_PARAM;
1014 /*******************************************************************
1015 Send a DNS update request
1016 *******************************************************************/
1018 #if defined(WITH_DNS_UPDATES)
1020 DNS_ERROR DoDNSUpdate(char *pszServerName,
1021 const char *pszDomainName, const char *pszHostName,
1022 const struct sockaddr_storage *sslist,
1025 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1026 const char *machine_name,
1027 const struct sockaddr_storage *addrs,
1030 struct dns_rr_ns *nameservers = NULL;
1032 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1035 const char *dnsdomain = NULL;
1036 char *root_domain = NULL;
1038 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1039 d_printf("No DNS domain configured for %s. "
1040 "Unable to perform DNS Update.\n", machine_name);
1041 status = NT_STATUS_INVALID_PARAMETER;
1046 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1047 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1048 /* Child domains often do not have NS records. Look
1049 for the NS record for the forest root domain
1050 (rootDomainNamingContext in therootDSE) */
1052 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1053 LDAPMessage *msg = NULL;
1055 ADS_STATUS ads_status;
1057 if ( !ads->ldap.ld ) {
1058 ads_status = ads_connect( ads );
1059 if ( !ADS_ERR_OK(ads_status) ) {
1060 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1065 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1066 "(objectclass=*)", rootname_attrs, &msg);
1067 if (!ADS_ERR_OK(ads_status)) {
1071 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1073 ads_msgfree( ads, msg );
1077 root_domain = ads_build_domain( root_dn );
1080 ads_msgfree( ads, msg );
1082 /* try again for NS servers */
1084 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1086 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1087 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1088 "realm\n", ads->config.realm));
1092 dnsdomain = root_domain;
1096 /* Now perform the dns update - we'll try non-secure and if we fail,
1097 we'll follow it up with a secure update */
1099 fstrcpy( dns_server, nameservers[0].hostname );
1101 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1102 if (!ERR_DNS_IS_OK(dns_err)) {
1103 status = NT_STATUS_UNSUCCESSFUL;
1108 SAFE_FREE( root_domain );
1113 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1116 struct sockaddr_storage *iplist = NULL;
1117 fstring machine_name;
1120 name_to_fqdn( machine_name, global_myname() );
1121 strlower_m( machine_name );
1123 /* Get our ip address (not the 127.0.0.x address but a real ip
1126 num_addrs = get_my_ip_address( &iplist );
1127 if ( num_addrs <= 0 ) {
1128 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1130 return NT_STATUS_INVALID_PARAMETER;
1133 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1135 SAFE_FREE( iplist );
1141 /*******************************************************************
1142 ********************************************************************/
1144 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1146 d_printf("net ads join [options]\n");
1147 d_printf("Valid options:\n");
1148 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1149 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1150 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1151 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1152 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1153 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1154 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1155 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1156 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1157 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1158 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1159 d_printf(" the two other attributes.\n");
1164 /*******************************************************************
1165 ********************************************************************/
1167 int net_ads_join(struct net_context *c, int argc, const char **argv)
1169 TALLOC_CTX *ctx = NULL;
1170 struct libnet_JoinCtx *r = NULL;
1171 const char *domain = lp_realm();
1172 WERROR werr = WERR_SETUP_NOT_JOINED;
1173 bool createupn = false;
1174 const char *machineupn = NULL;
1175 const char *create_in_ou = NULL;
1177 const char *os_name = NULL;
1178 const char *os_version = NULL;
1179 bool modify_config = lp_config_backend_is_registry();
1181 if (c->display_usage)
1182 return net_ads_join_usage(c, argc, argv);
1184 if (!modify_config) {
1186 werr = check_ads_config();
1187 if (!W_ERROR_IS_OK(werr)) {
1188 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1193 if (!(ctx = talloc_init("net_ads_join"))) {
1194 d_fprintf(stderr, "Could not initialise talloc context.\n");
1199 if (!c->opt_kerberos) {
1200 use_in_memory_ccache();
1203 werr = libnet_init_JoinCtx(ctx, &r);
1204 if (!W_ERROR_IS_OK(werr)) {
1208 /* process additional command line args */
1210 for ( i=0; i<argc; i++ ) {
1211 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1213 machineupn = get_string_param(argv[i]);
1215 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1216 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1217 d_fprintf(stderr, "Please supply a valid OU path.\n");
1218 werr = WERR_INVALID_PARAM;
1222 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1223 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1224 d_fprintf(stderr, "Please supply a operating system name.\n");
1225 werr = WERR_INVALID_PARAM;
1229 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1230 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1231 d_fprintf(stderr, "Please supply a valid operating system version.\n");
1232 werr = WERR_INVALID_PARAM;
1242 d_fprintf(stderr, "Please supply a valid domain name\n");
1243 werr = WERR_INVALID_PARAM;
1247 /* Do the domain join here */
1249 r->in.domain_name = domain;
1250 r->in.create_upn = createupn;
1251 r->in.upn = machineupn;
1252 r->in.account_ou = create_in_ou;
1253 r->in.os_name = os_name;
1254 r->in.os_version = os_version;
1255 r->in.dc_name = c->opt_host;
1256 r->in.admin_account = c->opt_user_name;
1257 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1259 r->in.use_kerberos = c->opt_kerberos;
1260 r->in.modify_config = modify_config;
1261 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1262 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1263 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1265 werr = libnet_Join(ctx, r);
1266 if (!W_ERROR_IS_OK(werr)) {
1270 /* Check the short name of the domain */
1272 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1273 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1274 d_printf("domain name obtained from the server.\n");
1275 d_printf("Using the name [%s] from the server.\n", r->out.netbios_domain_name);
1276 d_printf("You should set \"workgroup = %s\" in %s.\n",
1277 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1280 d_printf("Using short domain name -- %s\n", r->out.netbios_domain_name);
1282 if (r->out.dns_domain_name) {
1283 d_printf("Joined '%s' to realm '%s'\n", r->in.machine_name,
1284 r->out.dns_domain_name);
1286 d_printf("Joined '%s' to domain '%s'\n", r->in.machine_name,
1287 r->out.netbios_domain_name);
1290 #if defined(WITH_DNS_UPDATES)
1291 if (r->out.domain_is_ad) {
1292 /* We enter this block with user creds */
1293 ADS_STRUCT *ads_dns = NULL;
1295 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1296 /* kinit with the machine password */
1298 use_in_memory_ccache();
1299 asprintf( &ads_dns->auth.user_name, "%s$", global_myname() );
1300 ads_dns->auth.password = secrets_fetch_machine_password(
1301 r->out.netbios_domain_name, NULL, NULL );
1302 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1303 strupper_m(ads_dns->auth.realm );
1304 ads_kinit_password( ads_dns );
1307 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1308 d_fprintf( stderr, "DNS update failed!\n" );
1311 /* exit from this block using machine creds */
1312 ads_destroy(&ads_dns);
1321 /* issue an overall failure message at the end. */
1322 d_printf("Failed to join domain: %s\n",
1323 r && r->out.error_string ? r->out.error_string :
1324 get_friendly_werror_msg(werr));
1330 /*******************************************************************
1331 ********************************************************************/
1333 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1335 #if defined(WITH_DNS_UPDATES)
1341 talloc_enable_leak_report();
1344 if (argc > 0 || c->display_usage) {
1346 "net ads dns register\n"
1347 " Register hostname with DNS\n");
1351 if (!(ctx = talloc_init("net_ads_dns"))) {
1352 d_fprintf(stderr, "Could not initialise talloc context\n");
1356 status = ads_startup(c, true, &ads);
1357 if ( !ADS_ERR_OK(status) ) {
1358 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1363 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1364 d_fprintf( stderr, "DNS update failed!\n" );
1365 ads_destroy( &ads );
1370 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1377 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1382 #if defined(WITH_DNS_UPDATES)
1383 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1386 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1388 #if defined(WITH_DNS_UPDATES)
1392 talloc_enable_leak_report();
1395 if (argc != 2 || c->display_usage) {
1397 "net ads dns gethostbyname <server> <name>\n"
1398 " Look up hostname from the AD\n"
1399 " server\tName server to use\n"
1400 " name\tName to look up\n");
1404 err = do_gethostbyname(argv[0], argv[1]);
1406 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1411 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1413 struct functable func[] = {
1416 net_ads_dns_register,
1418 "Add host dns entry to AD",
1419 "net ads dns register\n"
1420 " Add host dns entry to AD"
1424 net_ads_dns_gethostbyname,
1427 "net ads dns gethostbyname\n"
1430 {NULL, NULL, 0, NULL, NULL}
1433 return net_run_function(c, argc, argv, "net ads dns", func);
1436 /*******************************************************************
1437 ********************************************************************/
1439 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1442 "\nnet ads printer search <printer>"
1443 "\n\tsearch for a printer in the directory\n"
1444 "\nnet ads printer info <printer> <server>"
1445 "\n\tlookup info in directory for printer on server"
1446 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1447 "\nnet ads printer publish <printername>"
1448 "\n\tpublish printer in directory"
1449 "\n\t(note: printer name is required)\n"
1450 "\nnet ads printer remove <printername>"
1451 "\n\tremove printer from directory"
1452 "\n\t(note: printer name is required)\n");
1456 /*******************************************************************
1457 ********************************************************************/
1459 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1463 LDAPMessage *res = NULL;
1465 if (c->display_usage) {
1467 "net ads printer search\n"
1468 " List printers in the AD\n");
1472 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1476 rc = ads_find_printers(ads, &res);
1478 if (!ADS_ERR_OK(rc)) {
1479 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1480 ads_msgfree(ads, res);
1485 if (ads_count_replies(ads, res) == 0) {
1486 d_fprintf(stderr, "No results found\n");
1487 ads_msgfree(ads, res);
1493 ads_msgfree(ads, res);
1498 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1502 const char *servername, *printername;
1503 LDAPMessage *res = NULL;
1505 if (c->display_usage) {
1507 "net ads printer info [printername [servername]]\n"
1508 " Display printer info from AD\n"
1509 " printername\tPrinter name or wildcard\n"
1510 " servername\tName of the print server\n");
1514 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1519 printername = argv[0];
1525 servername = argv[1];
1527 servername = global_myname();
1530 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1532 if (!ADS_ERR_OK(rc)) {
1533 d_fprintf(stderr, "Server '%s' not found: %s\n",
1534 servername, ads_errstr(rc));
1535 ads_msgfree(ads, res);
1540 if (ads_count_replies(ads, res) == 0) {
1541 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1542 ads_msgfree(ads, res);
1548 ads_msgfree(ads, res);
1554 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1558 const char *servername, *printername;
1559 struct cli_state *cli;
1560 struct rpc_pipe_client *pipe_hnd;
1561 struct sockaddr_storage server_ss;
1563 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1564 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1565 char *prt_dn, *srv_dn, **srv_cn;
1566 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1567 LDAPMessage *res = NULL;
1569 if (argc < 1 || c->display_usage) {
1571 "net ads printer publish <printername> [servername]\n"
1572 " Publish printer in AD\n"
1573 " printername\tName of the printer\n"
1574 " servername\tName of the print server\n");
1575 talloc_destroy(mem_ctx);
1579 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1580 talloc_destroy(mem_ctx);
1584 printername = argv[0];
1587 servername = argv[1];
1589 servername = global_myname();
1592 /* Get printer data from SPOOLSS */
1594 resolve_name(servername, &server_ss, 0x20);
1596 nt_status = cli_full_connection(&cli, global_myname(), servername,
1599 c->opt_user_name, c->opt_workgroup,
1600 c->opt_password ? c->opt_password : "",
1601 CLI_FULL_CONNECTION_USE_KERBEROS,
1604 if (NT_STATUS_IS_ERR(nt_status)) {
1605 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1606 "for %s\n", servername, printername);
1608 talloc_destroy(mem_ctx);
1612 /* Publish on AD server */
1614 ads_find_machine_acct(ads, &res, servername);
1616 if (ads_count_replies(ads, res) == 0) {
1617 d_fprintf(stderr, "Could not find machine account for server %s\n",
1620 talloc_destroy(mem_ctx);
1624 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1625 srv_cn = ldap_explode_dn(srv_dn, 1);
1627 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1628 printername_escaped = escape_rdn_val_string_alloc(printername);
1629 if (!srv_cn_escaped || !printername_escaped) {
1630 SAFE_FREE(srv_cn_escaped);
1631 SAFE_FREE(printername_escaped);
1632 d_fprintf(stderr, "Internal error, out of memory!");
1634 talloc_destroy(mem_ctx);
1638 asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn);
1640 SAFE_FREE(srv_cn_escaped);
1641 SAFE_FREE(printername_escaped);
1643 nt_status = cli_rpc_pipe_open_noauth(cli, &syntax_spoolss, &pipe_hnd);
1644 if (!NT_STATUS_IS_OK(nt_status)) {
1645 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1649 talloc_destroy(mem_ctx);
1653 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1657 talloc_destroy(mem_ctx);
1661 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1662 if (!ADS_ERR_OK(rc)) {
1663 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1666 talloc_destroy(mem_ctx);
1670 d_printf("published printer\n");
1673 talloc_destroy(mem_ctx);
1678 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1682 const char *servername;
1684 LDAPMessage *res = NULL;
1686 if (argc < 1 || c->display_usage) {
1688 "net ads printer remove <printername> [servername]\n"
1689 " Remove a printer from the AD\n"
1690 " printername\tName of the printer\n"
1691 " servername\tName of the print server\n");
1695 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1700 servername = argv[1];
1702 servername = global_myname();
1705 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1707 if (!ADS_ERR_OK(rc)) {
1708 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1709 ads_msgfree(ads, res);
1714 if (ads_count_replies(ads, res) == 0) {
1715 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1716 ads_msgfree(ads, res);
1721 prt_dn = ads_get_dn(ads, res);
1722 ads_msgfree(ads, res);
1723 rc = ads_del_dn(ads, prt_dn);
1724 ads_memfree(ads, prt_dn);
1726 if (!ADS_ERR_OK(rc)) {
1727 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1736 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1738 struct functable func[] = {
1741 net_ads_printer_search,
1743 "Search for a printer",
1744 "net ads printer search\n"
1745 " Search for a printer"
1749 net_ads_printer_info,
1751 "Display printer information",
1752 "net ads printer info\n"
1753 " Display printer information"
1757 net_ads_printer_publish,
1759 "Publish a printer",
1760 "net ads printer publish\n"
1761 " Publish a printer"
1765 net_ads_printer_remove,
1768 "net ads printer remove\n"
1771 {NULL, NULL, 0, NULL, NULL}
1774 return net_run_function(c, argc, argv, "net ads printer", func);
1778 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1781 const char *auth_principal = c->opt_user_name;
1782 const char *auth_password = c->opt_password;
1784 char *new_password = NULL;
1789 if (c->display_usage) {
1791 "net ads password <username>\n"
1792 " Change password for user\n"
1793 " username\tName of user to change password for\n");
1797 if (c->opt_user_name == NULL || c->opt_password == NULL) {
1798 d_fprintf(stderr, "You must supply an administrator username/password\n");
1803 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1808 if (!strchr_m(user, '@')) {
1809 asprintf(&chr, "%s@%s", argv[0], lp_realm());
1813 use_in_memory_ccache();
1814 chr = strchr_m(auth_principal, '@');
1821 /* use the realm so we can eventually change passwords for users
1822 in realms other than default */
1823 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1827 /* we don't actually need a full connect, but it's the easy way to
1828 fill in the KDC's addresss */
1831 if (!ads->config.realm) {
1832 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1837 new_password = (char *)argv[1];
1839 asprintf(&prompt, "Enter new password for %s:", user);
1840 new_password = getpass(prompt);
1844 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1845 auth_password, user, new_password, ads->auth.time_offset);
1846 if (!ADS_ERR_OK(ret)) {
1847 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1852 d_printf("Password change for %s completed.\n", user);
1858 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1861 char *host_principal;
1865 if (c->display_usage) {
1867 "net ads changetrustpw\n"
1868 " Change the machine account's trust password\n");
1872 if (!secrets_init()) {
1873 DEBUG(1,("Failed to initialise secrets database\n"));
1877 net_use_krb_machine_account(c);
1879 use_in_memory_ccache();
1881 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1885 fstrcpy(my_name, global_myname());
1886 strlower_m(my_name);
1887 asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm);
1888 d_printf("Changing password for principal: %s\n", host_principal);
1890 ret = ads_change_trust_account_password(ads, host_principal);
1892 if (!ADS_ERR_OK(ret)) {
1893 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1895 SAFE_FREE(host_principal);
1899 d_printf("Password change for principal %s succeeded.\n", host_principal);
1901 if (lp_use_kerberos_keytab()) {
1902 d_printf("Attempting to update system keytab with new password.\n");
1903 if (ads_keytab_create_default(ads)) {
1904 d_printf("Failed to update system keytab.\n");
1909 SAFE_FREE(host_principal);
1915 help for net ads search
1917 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
1920 "\nnet ads search <expression> <attributes...>\n"
1921 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
1922 "The expression is a standard LDAP search expression, and the\n"
1923 "attributes are a list of LDAP fields to show in the results.\n\n"
1924 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1926 net_common_flags_usage(c, argc, argv);
1932 general ADS search function. Useful in diagnosing problems in ADS
1934 static int net_ads_search(struct net_context *c, int argc, const char **argv)
1938 const char *ldap_exp;
1940 LDAPMessage *res = NULL;
1942 if (argc < 1 || c->display_usage) {
1943 return net_ads_search_usage(c, argc, argv);
1946 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1953 rc = ads_do_search_all(ads, ads->config.bind_path,
1955 ldap_exp, attrs, &res);
1956 if (!ADS_ERR_OK(rc)) {
1957 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1962 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1964 /* dump the results */
1967 ads_msgfree(ads, res);
1975 help for net ads search
1977 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
1980 "\nnet ads dn <dn> <attributes...>\n"
1981 "\nperform a raw LDAP search on a ADS server and dump the results\n"
1982 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
1983 "to show in the results\n\n"
1984 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
1985 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
1987 net_common_flags_usage(c, argc, argv);
1993 general ADS search function. Useful in diagnosing problems in ADS
1995 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2001 LDAPMessage *res = NULL;
2003 if (argc < 1 || c->display_usage) {
2004 return net_ads_dn_usage(c, argc, argv);
2007 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2014 rc = ads_do_search_all(ads, dn,
2016 "(objectclass=*)", attrs, &res);
2017 if (!ADS_ERR_OK(rc)) {
2018 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2023 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2025 /* dump the results */
2028 ads_msgfree(ads, res);
2035 help for net ads sid search
2037 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2040 "\nnet ads sid <sid> <attributes...>\n"
2041 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2042 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2043 "to show in the results\n\n"
2044 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2046 net_common_flags_usage(c, argc, argv);
2052 general ADS search function. Useful in diagnosing problems in ADS
2054 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2058 const char *sid_string;
2060 LDAPMessage *res = NULL;
2063 if (argc < 1 || c->display_usage) {
2064 return net_ads_sid_usage(c, argc, argv);
2067 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2071 sid_string = argv[0];
2074 if (!string_to_sid(&sid, sid_string)) {
2075 d_fprintf(stderr, "could not convert sid\n");
2080 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
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);
2098 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2103 if (c->display_usage) {
2105 "net ads keytab flush\n"
2106 " Delete the whole keytab\n");
2110 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2113 ret = ads_keytab_flush(ads);
2118 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2124 if (c->display_usage) {
2126 "net ads keytab add <principal> [principal ...]\n"
2127 " Add principals to local keytab\n"
2128 " principal\tKerberos principal to add to "
2133 d_printf("Processing principals to add...\n");
2134 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2137 for (i = 0; i < argc; i++) {
2138 ret |= ads_keytab_add_entry(ads, argv[i]);
2144 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2149 if (c->display_usage) {
2151 "net ads keytab create\n"
2152 " Create new default keytab\n");
2156 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2159 ret = ads_keytab_create_default(ads);
2164 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2166 const char *keytab = NULL;
2168 if (c->display_usage) {
2170 "net ads keytab list [keytab]\n"
2171 " List a local keytab\n"
2172 " keytab\tKeytab to list\n");
2180 return ads_keytab_list(keytab);
2184 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2186 struct functable func[] = {
2191 "Add a service principal",
2192 "net ads keytab add\n"
2193 " Add a service principal"
2197 net_ads_keytab_create,
2199 "Create a fresh keytab",
2200 "net ads keytab create\n"
2201 " Create a fresh keytab"
2205 net_ads_keytab_flush,
2207 "Remove all keytab entries",
2208 "net ads keytab flush\n"
2209 " Remove all keytab entries"
2213 net_ads_keytab_list,
2216 "net ads keytab list\n"
2219 {NULL, NULL, 0, NULL, NULL}
2222 if (!lp_use_kerberos_keytab()) {
2223 d_printf("\nWarning: \"use kerberos keytab\" must be set to \"true\" in order to \
2224 use keytab functions.\n");
2227 return net_run_function(c, argc, argv, "net ads keytab", func);
2230 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2234 if (c->display_usage) {
2236 "net ads kerberos renew\n"
2237 " Renew TGT from existing credential cache\n");
2241 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2243 d_printf("failed to renew kerberos ticket: %s\n",
2244 error_message(ret));
2249 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2251 struct PAC_DATA *pac = NULL;
2252 struct PAC_LOGON_INFO *info = NULL;
2253 TALLOC_CTX *mem_ctx = NULL;
2257 if (c->display_usage) {
2259 "net ads kerberos pac\n"
2260 " Dump the Kerberos PAC\n");
2264 mem_ctx = talloc_init("net_ads_kerberos_pac");
2269 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2271 status = kerberos_return_pac(mem_ctx,
2280 2592000, /* one month */
2282 if (!NT_STATUS_IS_OK(status)) {
2283 d_printf("failed to query kerberos PAC: %s\n",
2288 info = get_logon_info_from_pac(pac);
2291 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2292 d_printf("The Pac: %s\n", s);
2297 TALLOC_FREE(mem_ctx);
2301 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2303 TALLOC_CTX *mem_ctx = NULL;
2307 if (c->display_usage) {
2309 "net ads kerberos kinit\n"
2310 " Get Ticket Granting Ticket (TGT) for the user\n");
2314 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2319 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2321 ret = kerberos_kinit_password_ext(c->opt_user_name,
2329 2592000, /* one month */
2332 d_printf("failed to kinit password: %s\n",
2339 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2341 struct functable func[] = {
2344 net_ads_kerberos_kinit,
2346 "Retrieve Ticket Granting Ticket (TGT)",
2347 "net ads kerberos kinit\n"
2348 " Receive Ticket Granting Ticket (TGT)"
2352 net_ads_kerberos_renew,
2354 "Renew Ticket Granting Ticket from credential cache"
2355 "net ads kerberos renew\n"
2356 " Renew Ticket Granting Ticket from credential cache"
2360 net_ads_kerberos_pac,
2362 "Dump Kerberos PAC",
2363 "net ads kerberos pac\n"
2364 " Dump Kerberos PAC"
2366 {NULL, NULL, 0, NULL, NULL}
2369 return net_run_function(c, argc, argv, "net ads kerberos", func);
2372 int net_ads(struct net_context *c, int argc, const char **argv)
2374 struct functable func[] = {
2379 "Display details on remote ADS server",
2381 " Display details on remote ADS server"
2387 "Join the local machine to ADS realm",
2389 " Join the local machine to ADS realm"
2395 "Validate machine account",
2396 "net ads testjoin\n"
2397 " Validate machine account"
2403 "Remove the local machine from ADS",
2405 " Remove the local machine from ADS"
2411 "Display machine account details",
2413 " Display machine account details"
2419 "List/modify users",
2421 " List/modify users"
2427 "List/modify groups",
2429 " List/modify groups"
2435 "Issue dynamic DNS update",
2437 " Issue dynamic DNS update"
2443 "Change user passwords",
2444 "net ads password\n"
2445 " Change user passwords"
2449 net_ads_changetrustpw,
2451 "Change trust account password",
2452 "net ads changetrustpw\n"
2453 " Change trust account password"
2459 "List/modify printer entries",
2461 " List/modify printer entries"
2467 "Issue LDAP search using filter",
2469 " Issue LDAP search using filter"
2475 "Issue LDAP search by DN",
2477 " Issue LDAP search by DN"
2483 "Issue LDAP search by SID",
2485 " Issue LDAP search by SID"
2491 "Display workgroup name",
2492 "net ads workgroup\n"
2493 " Display the workgroup name"
2499 "Perfom CLDAP query on DC",
2501 " Find the ADS DC using CLDAP lookups"
2507 "Manage local keytab file",
2509 " Manage local keytab file"
2515 "Manage group policy objects",
2517 " Manage group policy objects"
2523 "Manage kerberos keytab",
2524 "net ads kerberos\n"
2525 " Manage kerberos keytab"
2527 {NULL, NULL, 0, NULL, NULL}
2530 return net_run_function(c, argc, argv, "net ads", func);
2535 static int net_ads_noads(void)
2537 d_fprintf(stderr, "ADS support not compiled in\n");
2541 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2543 return net_ads_noads();
2546 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2548 return net_ads_noads();
2551 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2553 return net_ads_noads();
2556 int net_ads_join(struct net_context *c, int argc, const char **argv)
2558 return net_ads_noads();
2561 int net_ads_user(struct net_context *c, int argc, const char **argv)
2563 return net_ads_noads();
2566 int net_ads_group(struct net_context *c, int argc, const char **argv)
2568 return net_ads_noads();
2571 /* this one shouldn't display a message */
2572 int net_ads_check(struct net_context *c)
2577 int net_ads_check_our_domain(struct net_context *c)
2582 int net_ads(struct net_context *c, int argc, const char **argv)
2584 return net_ads_noads();
2587 #endif /* WITH_ADS */