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"
29 /* when we do not have sufficient input parameters to contact a remote domain
30 * we always fall back to our own realm - Guenther*/
32 static const char *assume_own_realm(struct net_context *c)
34 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
42 do a cldap netlogon query
44 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
46 char addr[INET6_ADDRSTRLEN];
47 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
49 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
50 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
51 d_fprintf(stderr, "CLDAP query failed!\n");
55 d_printf("Information for Domain Controller: %s\n\n",
58 d_printf("Response Type: ");
59 switch (reply.command) {
60 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
61 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
63 case LOGON_SAM_LOGON_RESPONSE_EX:
64 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
67 d_printf("0x%x\n", reply.command);
71 d_printf("GUID: %s\n", GUID_string(talloc_tos(), &reply.domain_uuid));
75 "\tIs a GC of the forest: %s\n"
76 "\tIs an LDAP server: %s\n"
78 "\tIs running a KDC: %s\n"
79 "\tIs running time services: %s\n"
80 "\tIs the closest DC: %s\n"
82 "\tHas a hardware clock: %s\n"
83 "\tIs a non-domain NC serviced by LDAP server: %s\n"
84 "\tIs NT6 DC that has some secrets: %s\n"
85 "\tIs NT6 DC that has all secrets: %s\n",
86 (reply.server_type & NBT_SERVER_PDC) ? "yes" : "no",
87 (reply.server_type & NBT_SERVER_GC) ? "yes" : "no",
88 (reply.server_type & NBT_SERVER_LDAP) ? "yes" : "no",
89 (reply.server_type & NBT_SERVER_DS) ? "yes" : "no",
90 (reply.server_type & NBT_SERVER_KDC) ? "yes" : "no",
91 (reply.server_type & NBT_SERVER_TIMESERV) ? "yes" : "no",
92 (reply.server_type & NBT_SERVER_CLOSEST) ? "yes" : "no",
93 (reply.server_type & NBT_SERVER_WRITABLE) ? "yes" : "no",
94 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? "yes" : "no",
95 (reply.server_type & NBT_SERVER_NDNC) ? "yes" : "no",
96 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? "yes" : "no",
97 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? "yes" : "no");
100 printf("Forest:\t\t\t%s\n", reply.forest);
101 printf("Domain:\t\t\t%s\n", reply.dns_domain);
102 printf("Domain Controller:\t%s\n", reply.pdc_dns_name);
104 printf("Pre-Win2k Domain:\t%s\n", reply.domain);
105 printf("Pre-Win2k Hostname:\t%s\n", reply.pdc_name);
107 if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
109 printf("Server Site Name :\t\t%s\n", reply.server_site);
110 printf("Client Site Name :\t\t%s\n", reply.client_site);
112 d_printf("NT Version: %d\n", reply.nt_version);
113 d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
114 d_printf("LM20 Token: %.2x\n", reply.lm20_token);
120 this implements the CLDAP based netlogon lookup requests
121 for finding the domain controller of a ADS domain
123 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
128 if (c->display_usage) {
131 " Find the ADS DC using CLDAP lookup.\n");
135 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
136 d_fprintf(stderr, "Didn't find the cldap server!\n");
141 if (!ads->config.realm) {
142 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
143 ads->ldap.port = 389;
146 ret = net_ads_cldap_netlogon(c, ads);
153 static int net_ads_info(struct net_context *c, int argc, const char **argv)
156 char addr[INET6_ADDRSTRLEN];
158 if (c->display_usage) {
161 " Display information about an Active Directory "
166 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
167 d_fprintf(stderr, "Didn't find the ldap server!\n");
171 if (!ads || !ads->config.realm) {
172 d_fprintf(stderr, "Didn't find the ldap server!\n");
177 /* Try to set the server's current time since we didn't do a full
178 TCP LDAP session initially */
180 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
181 d_fprintf( stderr, "Failed to get server's current time!\n");
184 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
186 d_printf("LDAP server: %s\n", addr);
187 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
188 d_printf("Realm: %s\n", ads->config.realm);
189 d_printf("Bind Path: %s\n", ads->config.bind_path);
190 d_printf("LDAP port: %d\n", ads->ldap.port);
191 d_printf("Server time: %s\n",
192 http_timestring(talloc_tos(), ads->config.current_time));
194 d_printf("KDC server: %s\n", ads->auth.kdc_server );
195 d_printf("Server time offset: %d\n", ads->auth.time_offset );
201 static void use_in_memory_ccache(void) {
202 /* Use in-memory credentials cache so we do not interfere with
203 * existing credentials */
204 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
207 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
208 uint32 auth_flags, ADS_STRUCT **ads_ret)
210 ADS_STRUCT *ads = NULL;
212 bool need_password = false;
213 bool second_time = false;
215 const char *realm = NULL;
216 bool tried_closest_dc = false;
218 /* lp_realm() should be handled by a command line param,
219 However, the join requires that realm be set in smb.conf
220 and compares our realm with the remote server's so this is
221 ok until someone needs more flexibility */
226 if (only_own_domain) {
229 realm = assume_own_realm(c);
232 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
236 set_cmdline_auth_info_getpass(c->auth_info);
239 if (get_cmdline_auth_info_got_pass(c->auth_info) ||
240 !get_cmdline_auth_info_use_kerberos(c->auth_info)) {
241 use_in_memory_ccache();
242 SAFE_FREE(ads->auth.password);
243 ads->auth.password = smb_xstrdup(
244 get_cmdline_auth_info_password(c->auth_info));
247 ads->auth.flags |= auth_flags;
248 SAFE_FREE(ads->auth.user_name);
249 ads->auth.user_name = smb_xstrdup(
250 get_cmdline_auth_info_username(c->auth_info));
253 * If the username is of the form "name@realm",
254 * extract the realm and convert to upper case.
255 * This is only used to establish the connection.
257 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
259 SAFE_FREE(ads->auth.realm);
260 ads->auth.realm = smb_xstrdup(cp);
261 strupper_m(ads->auth.realm);
264 status = ads_connect(ads);
266 if (!ADS_ERR_OK(status)) {
268 if (NT_STATUS_EQUAL(ads_ntstatus(status),
269 NT_STATUS_NO_LOGON_SERVERS)) {
270 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
275 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
276 need_password = true;
285 /* when contacting our own domain, make sure we use the closest DC.
286 * This is done by reconnecting to ADS because only the first call to
287 * ads_connect will give us our own sitename */
289 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
291 tried_closest_dc = true; /* avoid loop */
293 if (!ads_closest_dc(ads)) {
295 namecache_delete(ads->server.realm, 0x1C);
296 namecache_delete(ads->server.workgroup, 0x1C);
309 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
311 return ads_startup_int(c, only_own_domain, 0, ads);
314 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
316 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
320 Check to see if connection can be made via ads.
321 ads_startup() stores the password in opt_password if it needs to so
322 that rpc or rap can use it without re-prompting.
324 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
329 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
333 ads->auth.flags |= ADS_AUTH_NO_BIND;
335 status = ads_connect(ads);
336 if ( !ADS_ERR_OK(status) ) {
344 int net_ads_check_our_domain(struct net_context *c)
346 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
349 int net_ads_check(struct net_context *c)
351 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
355 determine the netbios workgroup name for a domain
357 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
360 char addr[INET6_ADDRSTRLEN];
361 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
363 if (c->display_usage) {
365 "net ads workgroup\n"
366 " Print the workgroup name\n");
370 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
371 d_fprintf(stderr, "Didn't find the cldap server!\n");
375 if (!ads->config.realm) {
376 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
377 ads->ldap.port = 389;
380 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
381 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
382 d_fprintf(stderr, "CLDAP query failed!\n");
387 d_printf("Workgroup: %s\n", reply.domain);
396 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
398 char **disp_fields = (char **) data_area;
400 if (!field) { /* must be end of record */
401 if (disp_fields[0]) {
402 if (!strchr_m(disp_fields[0], '$')) {
404 d_printf("%-21.21s %s\n",
405 disp_fields[0], disp_fields[1]);
407 d_printf("%s\n", disp_fields[0]);
410 SAFE_FREE(disp_fields[0]);
411 SAFE_FREE(disp_fields[1]);
414 if (!values) /* must be new field, indicate string field */
416 if (StrCaseCmp(field, "sAMAccountName") == 0) {
417 disp_fields[0] = SMB_STRDUP((char *) values[0]);
419 if (StrCaseCmp(field, "description") == 0)
420 disp_fields[1] = SMB_STRDUP((char *) values[0]);
424 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
426 return net_user_usage(c, argc, argv);
429 static int ads_user_add(struct net_context *c, int argc, const char **argv)
434 LDAPMessage *res=NULL;
438 if (argc < 1 || c->display_usage)
439 return net_ads_user_usage(c, argc, argv);
441 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
445 status = ads_find_user_acct(ads, &res, argv[0]);
447 if (!ADS_ERR_OK(status)) {
448 d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
452 if (ads_count_replies(ads, res)) {
453 d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
457 if (c->opt_container) {
458 ou_str = SMB_STRDUP(c->opt_container);
460 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
463 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
465 if (!ADS_ERR_OK(status)) {
466 d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
471 /* if no password is to be set, we're done */
473 d_printf("User %s added\n", argv[0]);
478 /* try setting the password */
479 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
482 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
483 ads->auth.time_offset);
485 if (ADS_ERR_OK(status)) {
486 d_printf("User %s added\n", argv[0]);
491 /* password didn't set, delete account */
492 d_fprintf(stderr, "Could not add user %s. Error setting password %s\n",
493 argv[0], ads_errstr(status));
494 ads_msgfree(ads, res);
495 status=ads_find_user_acct(ads, &res, argv[0]);
496 if (ADS_ERR_OK(status)) {
497 userdn = ads_get_dn(ads, talloc_tos(), res);
498 ads_del_dn(ads, userdn);
504 ads_msgfree(ads, res);
510 static int ads_user_info(struct net_context *c, int argc, const char **argv)
515 const char *attrs[] = {"memberOf", NULL};
516 char *searchstring=NULL;
520 if (argc < 1 || c->display_usage) {
521 return net_ads_user_usage(c, argc, argv);
524 escaped_user = escape_ldap_string_alloc(argv[0]);
527 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
531 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
532 SAFE_FREE(escaped_user);
536 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
537 SAFE_FREE(escaped_user);
540 rc = ads_search(ads, &res, searchstring, attrs);
541 SAFE_FREE(searchstring);
543 if (!ADS_ERR_OK(rc)) {
544 d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
546 SAFE_FREE(escaped_user);
550 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
551 (LDAPMessage *)res, "memberOf");
556 for (i=0;grouplist[i];i++) {
557 groupname = ldap_explode_dn(grouplist[i], 1);
558 d_printf("%s\n", groupname[0]);
559 ldap_value_free(groupname);
561 ldap_value_free(grouplist);
564 ads_msgfree(ads, res);
566 SAFE_FREE(escaped_user);
570 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
574 LDAPMessage *res = NULL;
578 return net_ads_user_usage(c, argc, argv);
581 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
585 rc = ads_find_user_acct(ads, &res, argv[0]);
586 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
587 d_printf("User %s does not exist.\n", argv[0]);
588 ads_msgfree(ads, res);
592 userdn = ads_get_dn(ads, talloc_tos(), res);
593 ads_msgfree(ads, res);
594 rc = ads_del_dn(ads, userdn);
596 if (ADS_ERR_OK(rc)) {
597 d_printf("User %s deleted\n", argv[0]);
601 d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
607 int net_ads_user(struct net_context *c, int argc, const char **argv)
609 struct functable func[] = {
622 "Display information about an AD user",
623 "net ads user info\n"
624 " Display information about an AD user"
631 "net ads user delete\n"
634 {NULL, NULL, 0, NULL, NULL}
638 const char *shortattrs[] = {"sAMAccountName", NULL};
639 const char *longattrs[] = {"sAMAccountName", "description", NULL};
640 char *disp_fields[2] = {NULL, NULL};
643 if (c->display_usage) {
644 d_printf("Usage:\n");
645 d_printf("net ads user\n"
647 net_display_usage_from_functable(func);
651 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
655 if (c->opt_long_list_entries)
656 d_printf("\nUser name Comment"
657 "\n-----------------------------\n");
659 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
661 "(objectCategory=user)",
662 c->opt_long_list_entries ? longattrs :
663 shortattrs, usergrp_display,
666 return ADS_ERR_OK(rc) ? 0 : -1;
669 return net_run_function(c, argc, argv, "net ads user", func);
672 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
674 return net_group_usage(c, argc, argv);
677 static int ads_group_add(struct net_context *c, int argc, const char **argv)
681 LDAPMessage *res=NULL;
685 if (argc < 1 || c->display_usage) {
686 return net_ads_group_usage(c, argc, argv);
689 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
693 status = ads_find_user_acct(ads, &res, argv[0]);
695 if (!ADS_ERR_OK(status)) {
696 d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
700 if (ads_count_replies(ads, res)) {
701 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
705 if (c->opt_container) {
706 ou_str = SMB_STRDUP(c->opt_container);
708 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
711 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
713 if (ADS_ERR_OK(status)) {
714 d_printf("Group %s added\n", argv[0]);
717 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
723 ads_msgfree(ads, res);
729 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
733 LDAPMessage *res = NULL;
736 if (argc < 1 || c->display_usage) {
737 return net_ads_group_usage(c, argc, argv);
740 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
744 rc = ads_find_user_acct(ads, &res, argv[0]);
745 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
746 d_printf("Group %s does not exist.\n", argv[0]);
747 ads_msgfree(ads, res);
751 groupdn = ads_get_dn(ads, talloc_tos(), res);
752 ads_msgfree(ads, res);
753 rc = ads_del_dn(ads, groupdn);
754 TALLOC_FREE(groupdn);
755 if (ADS_ERR_OK(rc)) {
756 d_printf("Group %s deleted\n", argv[0]);
760 d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
766 int net_ads_group(struct net_context *c, int argc, const char **argv)
768 struct functable func[] = {
774 "net ads group add\n"
781 "Delete an AD group",
782 "net ads group delete\n"
783 " Delete an AD group"
785 {NULL, NULL, 0, NULL, NULL}
789 const char *shortattrs[] = {"sAMAccountName", NULL};
790 const char *longattrs[] = {"sAMAccountName", "description", NULL};
791 char *disp_fields[2] = {NULL, NULL};
794 if (c->display_usage) {
795 d_printf("Usage:\n");
796 d_printf("net ads group\n"
797 " List AD groups\n");
798 net_display_usage_from_functable(func);
802 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
806 if (c->opt_long_list_entries)
807 d_printf("\nGroup name Comment"
808 "\n-----------------------------\n");
809 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
811 "(objectCategory=group)",
812 c->opt_long_list_entries ? longattrs :
813 shortattrs, usergrp_display,
817 return ADS_ERR_OK(rc) ? 0 : -1;
819 return net_run_function(c, argc, argv, "net ads group", func);
822 static int net_ads_status(struct net_context *c, int argc, const char **argv)
828 if (c->display_usage) {
831 " Display machine account details\n");
835 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
839 rc = ads_find_machine_acct(ads, &res, global_myname());
840 if (!ADS_ERR_OK(rc)) {
841 d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
846 if (ads_count_replies(ads, res) == 0) {
847 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
857 /*******************************************************************
858 Leave an AD domain. Windows XP disables the machine account.
859 We'll try the same. The old code would do an LDAP delete.
860 That only worked using the machine creds because added the machine
861 with full control to the computer object's ACL.
862 *******************************************************************/
864 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
867 struct libnet_UnjoinCtx *r = NULL;
869 struct user_auth_info *ai = c->auth_info;
871 if (c->display_usage) {
874 " Leave an AD domain\n");
879 d_fprintf(stderr, "No realm set, are we joined ?\n");
883 if (!(ctx = talloc_init("net_ads_leave"))) {
884 d_fprintf(stderr, "Could not initialise talloc context.\n");
888 if (!get_cmdline_auth_info_use_kerberos(ai)) {
889 use_in_memory_ccache();
892 werr = libnet_init_UnjoinCtx(ctx, &r);
893 if (!W_ERROR_IS_OK(werr)) {
894 d_fprintf(stderr, "Could not initialise unjoin context.\n");
898 set_cmdline_auth_info_getpass(ai);
901 r->in.use_kerberos = get_cmdline_auth_info_use_kerberos(ai);
902 r->in.dc_name = c->opt_host;
903 r->in.domain_name = lp_realm();
904 r->in.admin_account = get_cmdline_auth_info_username(ai);
905 r->in.admin_password = get_cmdline_auth_info_password(ai);
906 r->in.modify_config = lp_config_backend_is_registry();
908 /* Try to delete it, but if that fails, disable it. The
909 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
910 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
911 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
912 r->in.delete_machine_account = true;
914 werr = libnet_Unjoin(ctx, r);
915 if (!W_ERROR_IS_OK(werr)) {
916 d_printf("Failed to leave domain: %s\n",
917 r->out.error_string ? r->out.error_string :
918 get_friendly_werror_msg(werr));
922 if (r->out.deleted_machine_account) {
923 d_printf("Deleted account for '%s' in realm '%s'\n",
924 r->in.machine_name, r->out.dns_domain_name);
928 /* We couldn't delete it - see if the disable succeeded. */
929 if (r->out.disabled_machine_account) {
930 d_printf("Disabled account for '%s' in realm '%s'\n",
931 r->in.machine_name, r->out.dns_domain_name);
936 /* Based on what we requseted, we shouldn't get here, but if
937 we did, it means the secrets were removed, and therefore
938 we have left the domain */
939 d_fprintf(stderr, "Machine '%s' Left domain '%s'\n",
940 r->in.machine_name, r->out.dns_domain_name);
946 if (W_ERROR_IS_OK(werr)) {
953 static NTSTATUS net_ads_join_ok(struct net_context *c)
955 ADS_STRUCT *ads = NULL;
958 if (!secrets_init()) {
959 DEBUG(1,("Failed to initialise secrets database\n"));
960 return NT_STATUS_ACCESS_DENIED;
963 set_cmdline_auth_info_use_machine_account(c->auth_info);
964 set_cmdline_auth_info_machine_account_creds(c->auth_info);
966 status = ads_startup(c, true, &ads);
967 if (!ADS_ERR_OK(status)) {
968 return ads_ntstatus(status);
976 check that an existing join is OK
978 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
981 use_in_memory_ccache();
983 if (c->display_usage) {
986 " Test if the existing join is ok\n");
990 /* Display success or failure */
991 status = net_ads_join_ok(c);
992 if (!NT_STATUS_IS_OK(status)) {
993 fprintf(stderr,"Join to domain is not valid: %s\n",
994 get_friendly_nt_error_msg(status));
998 printf("Join is OK\n");
1002 /*******************************************************************
1003 Simple configu checks before beginning the join
1004 ********************************************************************/
1006 static WERROR check_ads_config( void )
1008 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1009 d_printf("Host is not configured as a member server.\n");
1010 return WERR_INVALID_DOMAIN_ROLE;
1013 if (strlen(global_myname()) > 15) {
1014 d_printf("Our netbios name can be at most 15 chars long, "
1015 "\"%s\" is %u chars long\n", global_myname(),
1016 (unsigned int)strlen(global_myname()));
1017 return WERR_INVALID_COMPUTERNAME;
1020 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1021 d_fprintf(stderr, "realm must be set in in %s for ADS "
1022 "join to succeed.\n", get_dyn_CONFIGFILE());
1023 return WERR_INVALID_PARAM;
1029 /*******************************************************************
1030 Send a DNS update request
1031 *******************************************************************/
1033 #if defined(WITH_DNS_UPDATES)
1035 DNS_ERROR DoDNSUpdate(char *pszServerName,
1036 const char *pszDomainName, const char *pszHostName,
1037 const struct sockaddr_storage *sslist,
1040 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1041 const char *machine_name,
1042 const struct sockaddr_storage *addrs,
1045 struct dns_rr_ns *nameservers = NULL;
1047 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1050 const char *dnsdomain = NULL;
1051 char *root_domain = NULL;
1053 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1054 d_printf("No DNS domain configured for %s. "
1055 "Unable to perform DNS Update.\n", machine_name);
1056 status = NT_STATUS_INVALID_PARAMETER;
1061 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1062 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1063 /* Child domains often do not have NS records. Look
1064 for the NS record for the forest root domain
1065 (rootDomainNamingContext in therootDSE) */
1067 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1068 LDAPMessage *msg = NULL;
1070 ADS_STATUS ads_status;
1072 if ( !ads->ldap.ld ) {
1073 ads_status = ads_connect( ads );
1074 if ( !ADS_ERR_OK(ads_status) ) {
1075 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1080 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1081 "(objectclass=*)", rootname_attrs, &msg);
1082 if (!ADS_ERR_OK(ads_status)) {
1086 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1088 ads_msgfree( ads, msg );
1092 root_domain = ads_build_domain( root_dn );
1095 ads_msgfree( ads, msg );
1097 /* try again for NS servers */
1099 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1101 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1102 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1103 "realm\n", ads->config.realm));
1107 dnsdomain = root_domain;
1111 /* Now perform the dns update - we'll try non-secure and if we fail,
1112 we'll follow it up with a secure update */
1114 fstrcpy( dns_server, nameservers[0].hostname );
1116 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1117 if (!ERR_DNS_IS_OK(dns_err)) {
1118 status = NT_STATUS_UNSUCCESSFUL;
1123 SAFE_FREE( root_domain );
1128 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1131 struct sockaddr_storage *iplist = NULL;
1132 fstring machine_name;
1135 name_to_fqdn( machine_name, global_myname() );
1136 strlower_m( machine_name );
1138 /* Get our ip address (not the 127.0.0.x address but a real ip
1141 num_addrs = get_my_ip_address( &iplist );
1142 if ( num_addrs <= 0 ) {
1143 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1145 return NT_STATUS_INVALID_PARAMETER;
1148 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1150 SAFE_FREE( iplist );
1156 /*******************************************************************
1157 ********************************************************************/
1159 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1161 d_printf("net ads join [options]\n");
1162 d_printf("Valid options:\n");
1163 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1164 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1165 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1166 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1167 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1168 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1169 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1170 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1171 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1172 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1173 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1174 d_printf(" the two other attributes.\n");
1179 /*******************************************************************
1180 ********************************************************************/
1182 int net_ads_join(struct net_context *c, int argc, const char **argv)
1184 TALLOC_CTX *ctx = NULL;
1185 struct libnet_JoinCtx *r = NULL;
1186 const char *domain = lp_realm();
1187 WERROR werr = WERR_SETUP_NOT_JOINED;
1188 bool createupn = false;
1189 const char *machineupn = NULL;
1190 const char *create_in_ou = NULL;
1192 const char *os_name = NULL;
1193 const char *os_version = NULL;
1194 bool modify_config = lp_config_backend_is_registry();
1195 struct user_auth_info *ai = c->auth_info;;
1197 if (c->display_usage)
1198 return net_ads_join_usage(c, argc, argv);
1200 if (!modify_config) {
1202 werr = check_ads_config();
1203 if (!W_ERROR_IS_OK(werr)) {
1204 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1209 if (!(ctx = talloc_init("net_ads_join"))) {
1210 d_fprintf(stderr, "Could not initialise talloc context.\n");
1215 if (!get_cmdline_auth_info_use_kerberos(ai)) {
1216 use_in_memory_ccache();
1219 werr = libnet_init_JoinCtx(ctx, &r);
1220 if (!W_ERROR_IS_OK(werr)) {
1224 /* process additional command line args */
1226 for ( i=0; i<argc; i++ ) {
1227 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1229 machineupn = get_string_param(argv[i]);
1231 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1232 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1233 d_fprintf(stderr, "Please supply a valid OU path.\n");
1234 werr = WERR_INVALID_PARAM;
1238 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1239 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1240 d_fprintf(stderr, "Please supply a operating system name.\n");
1241 werr = WERR_INVALID_PARAM;
1245 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1246 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1247 d_fprintf(stderr, "Please supply a valid operating system version.\n");
1248 werr = WERR_INVALID_PARAM;
1258 d_fprintf(stderr, "Please supply a valid domain name\n");
1259 werr = WERR_INVALID_PARAM;
1263 /* Do the domain join here */
1265 set_cmdline_auth_info_getpass(ai);
1267 r->in.domain_name = domain;
1268 r->in.create_upn = createupn;
1269 r->in.upn = machineupn;
1270 r->in.account_ou = create_in_ou;
1271 r->in.os_name = os_name;
1272 r->in.os_version = os_version;
1273 r->in.dc_name = c->opt_host;
1274 r->in.admin_account = get_cmdline_auth_info_username(ai);
1275 r->in.admin_password = get_cmdline_auth_info_password(ai);
1277 r->in.use_kerberos = get_cmdline_auth_info_use_kerberos(ai);
1278 r->in.modify_config = modify_config;
1279 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1280 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1281 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1283 werr = libnet_Join(ctx, r);
1284 if (!W_ERROR_IS_OK(werr)) {
1288 /* Check the short name of the domain */
1290 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1291 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1292 d_printf("domain name obtained from the server.\n");
1293 d_printf("Using the name [%s] from the server.\n", r->out.netbios_domain_name);
1294 d_printf("You should set \"workgroup = %s\" in %s.\n",
1295 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1298 d_printf("Using short domain name -- %s\n", r->out.netbios_domain_name);
1300 if (r->out.dns_domain_name) {
1301 d_printf("Joined '%s' to realm '%s'\n", r->in.machine_name,
1302 r->out.dns_domain_name);
1304 d_printf("Joined '%s' to domain '%s'\n", r->in.machine_name,
1305 r->out.netbios_domain_name);
1308 #if defined(WITH_DNS_UPDATES)
1309 if (r->out.domain_is_ad) {
1310 /* We enter this block with user creds */
1311 ADS_STRUCT *ads_dns = NULL;
1313 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1314 /* kinit with the machine password */
1316 use_in_memory_ccache();
1317 if (asprintf( &ads_dns->auth.user_name, "%s$", global_myname()) == -1) {
1320 ads_dns->auth.password = secrets_fetch_machine_password(
1321 r->out.netbios_domain_name, NULL, NULL );
1322 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1323 strupper_m(ads_dns->auth.realm );
1324 ads_kinit_password( ads_dns );
1327 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1328 d_fprintf( stderr, "DNS update failed!\n" );
1331 /* exit from this block using machine creds */
1332 ads_destroy(&ads_dns);
1341 /* issue an overall failure message at the end. */
1342 d_printf("Failed to join domain: %s\n",
1343 r && r->out.error_string ? r->out.error_string :
1344 get_friendly_werror_msg(werr));
1350 /*******************************************************************
1351 ********************************************************************/
1353 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1355 #if defined(WITH_DNS_UPDATES)
1361 talloc_enable_leak_report();
1364 if (argc > 0 || c->display_usage) {
1366 "net ads dns register\n"
1367 " Register hostname with DNS\n");
1371 if (!(ctx = talloc_init("net_ads_dns"))) {
1372 d_fprintf(stderr, "Could not initialise talloc context\n");
1376 status = ads_startup(c, true, &ads);
1377 if ( !ADS_ERR_OK(status) ) {
1378 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1383 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1384 d_fprintf( stderr, "DNS update failed!\n" );
1385 ads_destroy( &ads );
1390 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1397 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1402 #if defined(WITH_DNS_UPDATES)
1403 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1406 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1408 #if defined(WITH_DNS_UPDATES)
1412 talloc_enable_leak_report();
1415 if (argc != 2 || c->display_usage) {
1417 "net ads dns gethostbyname <server> <name>\n"
1418 " Look up hostname from the AD\n"
1419 " server\tName server to use\n"
1420 " name\tName to look up\n");
1424 err = do_gethostbyname(argv[0], argv[1]);
1426 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1431 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1433 struct functable func[] = {
1436 net_ads_dns_register,
1438 "Add host dns entry to AD",
1439 "net ads dns register\n"
1440 " Add host dns entry to AD"
1444 net_ads_dns_gethostbyname,
1447 "net ads dns gethostbyname\n"
1450 {NULL, NULL, 0, NULL, NULL}
1453 return net_run_function(c, argc, argv, "net ads dns", func);
1456 /*******************************************************************
1457 ********************************************************************/
1459 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1462 "\nnet ads printer search <printer>"
1463 "\n\tsearch for a printer in the directory\n"
1464 "\nnet ads printer info <printer> <server>"
1465 "\n\tlookup info in directory for printer on server"
1466 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1467 "\nnet ads printer publish <printername>"
1468 "\n\tpublish printer in directory"
1469 "\n\t(note: printer name is required)\n"
1470 "\nnet ads printer remove <printername>"
1471 "\n\tremove printer from directory"
1472 "\n\t(note: printer name is required)\n");
1476 /*******************************************************************
1477 ********************************************************************/
1479 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1483 LDAPMessage *res = NULL;
1485 if (c->display_usage) {
1487 "net ads printer search\n"
1488 " List printers in the AD\n");
1492 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1496 rc = ads_find_printers(ads, &res);
1498 if (!ADS_ERR_OK(rc)) {
1499 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1500 ads_msgfree(ads, res);
1505 if (ads_count_replies(ads, res) == 0) {
1506 d_fprintf(stderr, "No results found\n");
1507 ads_msgfree(ads, res);
1513 ads_msgfree(ads, res);
1518 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1522 const char *servername, *printername;
1523 LDAPMessage *res = NULL;
1525 if (c->display_usage) {
1527 "net ads printer info [printername [servername]]\n"
1528 " Display printer info from AD\n"
1529 " printername\tPrinter name or wildcard\n"
1530 " servername\tName of the print server\n");
1534 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1539 printername = argv[0];
1545 servername = argv[1];
1547 servername = global_myname();
1550 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1552 if (!ADS_ERR_OK(rc)) {
1553 d_fprintf(stderr, "Server '%s' not found: %s\n",
1554 servername, ads_errstr(rc));
1555 ads_msgfree(ads, res);
1560 if (ads_count_replies(ads, res) == 0) {
1561 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1562 ads_msgfree(ads, res);
1568 ads_msgfree(ads, res);
1574 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1578 const char *servername, *printername;
1579 struct cli_state *cli;
1580 struct rpc_pipe_client *pipe_hnd;
1581 struct sockaddr_storage server_ss;
1583 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1584 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1585 char *prt_dn, *srv_dn, **srv_cn;
1586 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1587 LDAPMessage *res = NULL;
1588 struct user_auth_info *ai = c->auth_info;
1590 if (argc < 1 || c->display_usage) {
1592 "net ads printer publish <printername> [servername]\n"
1593 " Publish printer in AD\n"
1594 " printername\tName of the printer\n"
1595 " servername\tName of the print server\n");
1596 talloc_destroy(mem_ctx);
1600 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1601 talloc_destroy(mem_ctx);
1605 printername = argv[0];
1608 servername = argv[1];
1610 servername = global_myname();
1613 /* Get printer data from SPOOLSS */
1615 resolve_name(servername, &server_ss, 0x20);
1617 nt_status = cli_full_connection(&cli, global_myname(), servername,
1620 get_cmdline_auth_info_username(ai),
1622 get_cmdline_auth_info_password(ai),
1623 CLI_FULL_CONNECTION_USE_KERBEROS,
1626 if (NT_STATUS_IS_ERR(nt_status)) {
1627 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1628 "for %s\n", servername, printername);
1630 talloc_destroy(mem_ctx);
1634 /* Publish on AD server */
1636 ads_find_machine_acct(ads, &res, servername);
1638 if (ads_count_replies(ads, res) == 0) {
1639 d_fprintf(stderr, "Could not find machine account for server %s\n",
1642 talloc_destroy(mem_ctx);
1646 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1647 srv_cn = ldap_explode_dn(srv_dn, 1);
1649 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1650 printername_escaped = escape_rdn_val_string_alloc(printername);
1651 if (!srv_cn_escaped || !printername_escaped) {
1652 SAFE_FREE(srv_cn_escaped);
1653 SAFE_FREE(printername_escaped);
1654 d_fprintf(stderr, "Internal error, out of memory!");
1656 talloc_destroy(mem_ctx);
1660 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1661 SAFE_FREE(srv_cn_escaped);
1662 SAFE_FREE(printername_escaped);
1663 d_fprintf(stderr, "Internal error, out of memory!");
1665 talloc_destroy(mem_ctx);
1669 SAFE_FREE(srv_cn_escaped);
1670 SAFE_FREE(printername_escaped);
1672 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
1673 if (!NT_STATUS_IS_OK(nt_status)) {
1674 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1678 talloc_destroy(mem_ctx);
1682 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1686 talloc_destroy(mem_ctx);
1690 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1691 if (!ADS_ERR_OK(rc)) {
1692 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1695 talloc_destroy(mem_ctx);
1699 d_printf("published printer\n");
1702 talloc_destroy(mem_ctx);
1707 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1711 const char *servername;
1713 LDAPMessage *res = NULL;
1715 if (argc < 1 || c->display_usage) {
1717 "net ads printer remove <printername> [servername]\n"
1718 " Remove a printer from the AD\n"
1719 " printername\tName of the printer\n"
1720 " servername\tName of the print server\n");
1724 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1729 servername = argv[1];
1731 servername = global_myname();
1734 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1736 if (!ADS_ERR_OK(rc)) {
1737 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1738 ads_msgfree(ads, res);
1743 if (ads_count_replies(ads, res) == 0) {
1744 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1745 ads_msgfree(ads, res);
1750 prt_dn = ads_get_dn(ads, talloc_tos(), res);
1751 ads_msgfree(ads, res);
1752 rc = ads_del_dn(ads, prt_dn);
1753 TALLOC_FREE(prt_dn);
1755 if (!ADS_ERR_OK(rc)) {
1756 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1765 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1767 struct functable func[] = {
1770 net_ads_printer_search,
1772 "Search for a printer",
1773 "net ads printer search\n"
1774 " Search for a printer"
1778 net_ads_printer_info,
1780 "Display printer information",
1781 "net ads printer info\n"
1782 " Display printer information"
1786 net_ads_printer_publish,
1788 "Publish a printer",
1789 "net ads printer publish\n"
1790 " Publish a printer"
1794 net_ads_printer_remove,
1797 "net ads printer remove\n"
1800 {NULL, NULL, 0, NULL, NULL}
1803 return net_run_function(c, argc, argv, "net ads printer", func);
1807 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1810 const char *auth_principal;
1811 const char *auth_password;
1813 char *new_password = NULL;
1818 if (c->display_usage) {
1820 "net ads password <username>\n"
1821 " Change password for user\n"
1822 " username\tName of user to change password for\n");
1826 auth_principal = get_cmdline_auth_info_username(c->auth_info);
1827 set_cmdline_auth_info_getpass(c->auth_info);
1828 auth_password = get_cmdline_auth_info_password(c->auth_info);
1831 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1836 if (!strchr_m(user, '@')) {
1837 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
1843 use_in_memory_ccache();
1844 chr = strchr_m(auth_principal, '@');
1851 /* use the realm so we can eventually change passwords for users
1852 in realms other than default */
1853 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1857 /* we don't actually need a full connect, but it's the easy way to
1858 fill in the KDC's addresss */
1861 if (!ads->config.realm) {
1862 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1868 new_password = (char *)argv[1];
1870 if (asprintf(&prompt, "Enter new password for %s:", user) == -1) {
1873 new_password = getpass(prompt);
1877 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1878 auth_password, user, new_password, ads->auth.time_offset);
1879 if (!ADS_ERR_OK(ret)) {
1880 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1885 d_printf("Password change for %s completed.\n", user);
1891 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1894 char *host_principal;
1898 if (c->display_usage) {
1900 "net ads changetrustpw\n"
1901 " Change the machine account's trust password\n");
1905 if (!secrets_init()) {
1906 DEBUG(1,("Failed to initialise secrets database\n"));
1910 set_cmdline_auth_info_use_machine_account(c->auth_info);
1912 use_in_memory_ccache();
1914 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1918 fstrcpy(my_name, global_myname());
1919 strlower_m(my_name);
1920 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
1924 d_printf("Changing password for principal: %s\n", host_principal);
1926 ret = ads_change_trust_account_password(ads, host_principal);
1928 if (!ADS_ERR_OK(ret)) {
1929 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1931 SAFE_FREE(host_principal);
1935 d_printf("Password change for principal %s succeeded.\n", host_principal);
1937 if (USE_SYSTEM_KEYTAB) {
1938 d_printf("Attempting to update system keytab with new password.\n");
1939 if (ads_keytab_create_default(ads)) {
1940 d_printf("Failed to update system keytab.\n");
1945 SAFE_FREE(host_principal);
1951 help for net ads search
1953 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
1956 "\nnet ads search <expression> <attributes...>\n"
1957 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
1958 "The expression is a standard LDAP search expression, and the\n"
1959 "attributes are a list of LDAP fields to show in the results.\n\n"
1960 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1962 net_common_flags_usage(c, argc, argv);
1968 general ADS search function. Useful in diagnosing problems in ADS
1970 static int net_ads_search(struct net_context *c, int argc, const char **argv)
1974 const char *ldap_exp;
1976 LDAPMessage *res = NULL;
1978 if (argc < 1 || c->display_usage) {
1979 return net_ads_search_usage(c, argc, argv);
1982 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1989 rc = ads_do_search_all(ads, ads->config.bind_path,
1991 ldap_exp, attrs, &res);
1992 if (!ADS_ERR_OK(rc)) {
1993 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1998 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2000 /* dump the results */
2003 ads_msgfree(ads, res);
2011 help for net ads search
2013 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2016 "\nnet ads dn <dn> <attributes...>\n"
2017 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2018 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2019 "to show in the results\n\n"
2020 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2021 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2023 net_common_flags_usage(c, argc, argv);
2029 general ADS search function. Useful in diagnosing problems in ADS
2031 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2037 LDAPMessage *res = NULL;
2039 if (argc < 1 || c->display_usage) {
2040 return net_ads_dn_usage(c, argc, argv);
2043 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2050 rc = ads_do_search_all(ads, dn,
2052 "(objectclass=*)", attrs, &res);
2053 if (!ADS_ERR_OK(rc)) {
2054 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2059 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2061 /* dump the results */
2064 ads_msgfree(ads, res);
2071 help for net ads sid search
2073 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2076 "\nnet ads sid <sid> <attributes...>\n"
2077 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2078 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2079 "to show in the results\n\n"
2080 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2082 net_common_flags_usage(c, argc, argv);
2088 general ADS search function. Useful in diagnosing problems in ADS
2090 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2094 const char *sid_string;
2096 LDAPMessage *res = NULL;
2099 if (argc < 1 || c->display_usage) {
2100 return net_ads_sid_usage(c, argc, argv);
2103 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2107 sid_string = argv[0];
2110 if (!string_to_sid(&sid, sid_string)) {
2111 d_fprintf(stderr, "could not convert sid\n");
2116 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2117 if (!ADS_ERR_OK(rc)) {
2118 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2123 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2125 /* dump the results */
2128 ads_msgfree(ads, res);
2134 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2139 if (c->display_usage) {
2141 "net ads keytab flush\n"
2142 " Delete the whole keytab\n");
2146 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2149 ret = ads_keytab_flush(ads);
2154 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2160 if (c->display_usage) {
2162 "net ads keytab add <principal> [principal ...]\n"
2163 " Add principals to local keytab\n"
2164 " principal\tKerberos principal to add to "
2169 d_printf("Processing principals to add...\n");
2170 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2173 for (i = 0; i < argc; i++) {
2174 ret |= ads_keytab_add_entry(ads, argv[i]);
2180 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2185 if (c->display_usage) {
2187 "net ads keytab create\n"
2188 " Create new default keytab\n");
2192 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2195 ret = ads_keytab_create_default(ads);
2200 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2202 const char *keytab = NULL;
2204 if (c->display_usage) {
2206 "net ads keytab list [keytab]\n"
2207 " List a local keytab\n"
2208 " keytab\tKeytab to list\n");
2216 return ads_keytab_list(keytab);
2220 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2222 struct functable func[] = {
2227 "Add a service principal",
2228 "net ads keytab add\n"
2229 " Add a service principal"
2233 net_ads_keytab_create,
2235 "Create a fresh keytab",
2236 "net ads keytab create\n"
2237 " Create a fresh keytab"
2241 net_ads_keytab_flush,
2243 "Remove all keytab entries",
2244 "net ads keytab flush\n"
2245 " Remove all keytab entries"
2249 net_ads_keytab_list,
2252 "net ads keytab list\n"
2255 {NULL, NULL, 0, NULL, NULL}
2258 if (!USE_KERBEROS_KEYTAB) {
2259 d_printf("\nWarning: \"kerberos method\" must be set to a "
2260 "keytab method to use keytab functions.\n");
2263 return net_run_function(c, argc, argv, "net ads keytab", func);
2266 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2270 if (c->display_usage) {
2272 "net ads kerberos renew\n"
2273 " Renew TGT from existing credential cache\n");
2277 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2279 d_printf("failed to renew kerberos ticket: %s\n",
2280 error_message(ret));
2285 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2287 struct PAC_DATA *pac = NULL;
2288 struct PAC_LOGON_INFO *info = NULL;
2289 TALLOC_CTX *mem_ctx = NULL;
2292 struct user_auth_info *ai = c->auth_info;
2294 if (c->display_usage) {
2296 "net ads kerberos pac\n"
2297 " Dump the Kerberos PAC\n");
2301 mem_ctx = talloc_init("net_ads_kerberos_pac");
2306 set_cmdline_auth_info_getpass(ai);
2308 status = kerberos_return_pac(mem_ctx,
2309 get_cmdline_auth_info_username(ai),
2310 get_cmdline_auth_info_password(ai),
2317 2592000, /* one month */
2319 if (!NT_STATUS_IS_OK(status)) {
2320 d_printf("failed to query kerberos PAC: %s\n",
2325 info = get_logon_info_from_pac(pac);
2328 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2329 d_printf("The Pac: %s\n", s);
2334 TALLOC_FREE(mem_ctx);
2338 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2340 TALLOC_CTX *mem_ctx = NULL;
2343 struct user_auth_info *ai = c->auth_info;
2345 if (c->display_usage) {
2347 "net ads kerberos kinit\n"
2348 " Get Ticket Granting Ticket (TGT) for the user\n");
2352 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2357 set_cmdline_auth_info_getpass(ai);
2359 ret = kerberos_kinit_password_ext(get_cmdline_auth_info_username(ai),
2360 get_cmdline_auth_info_password(ai),
2367 2592000, /* one month */
2370 d_printf("failed to kinit password: %s\n",
2377 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2379 struct functable func[] = {
2382 net_ads_kerberos_kinit,
2384 "Retrieve Ticket Granting Ticket (TGT)",
2385 "net ads kerberos kinit\n"
2386 " Receive Ticket Granting Ticket (TGT)"
2390 net_ads_kerberos_renew,
2392 "Renew Ticket Granting Ticket from credential cache"
2393 "net ads kerberos renew\n"
2394 " Renew Ticket Granting Ticket from credential cache"
2398 net_ads_kerberos_pac,
2400 "Dump Kerberos PAC",
2401 "net ads kerberos pac\n"
2402 " Dump Kerberos PAC"
2404 {NULL, NULL, 0, NULL, NULL}
2407 return net_run_function(c, argc, argv, "net ads kerberos", func);
2410 int net_ads(struct net_context *c, int argc, const char **argv)
2412 struct functable func[] = {
2417 "Display details on remote ADS server",
2419 " Display details on remote ADS server"
2425 "Join the local machine to ADS realm",
2427 " Join the local machine to ADS realm"
2433 "Validate machine account",
2434 "net ads testjoin\n"
2435 " Validate machine account"
2441 "Remove the local machine from ADS",
2443 " Remove the local machine from ADS"
2449 "Display machine account details",
2451 " Display machine account details"
2457 "List/modify users",
2459 " List/modify users"
2465 "List/modify groups",
2467 " List/modify groups"
2473 "Issue dynamic DNS update",
2475 " Issue dynamic DNS update"
2481 "Change user passwords",
2482 "net ads password\n"
2483 " Change user passwords"
2487 net_ads_changetrustpw,
2489 "Change trust account password",
2490 "net ads changetrustpw\n"
2491 " Change trust account password"
2497 "List/modify printer entries",
2499 " List/modify printer entries"
2505 "Issue LDAP search using filter",
2507 " Issue LDAP search using filter"
2513 "Issue LDAP search by DN",
2515 " Issue LDAP search by DN"
2521 "Issue LDAP search by SID",
2523 " Issue LDAP search by SID"
2529 "Display workgroup name",
2530 "net ads workgroup\n"
2531 " Display the workgroup name"
2537 "Perfom CLDAP query on DC",
2539 " Find the ADS DC using CLDAP lookups"
2545 "Manage local keytab file",
2547 " Manage local keytab file"
2553 "Manage group policy objects",
2555 " Manage group policy objects"
2561 "Manage kerberos keytab",
2562 "net ads kerberos\n"
2563 " Manage kerberos keytab"
2565 {NULL, NULL, 0, NULL, NULL}
2568 return net_run_function(c, argc, argv, "net ads", func);
2573 static int net_ads_noads(void)
2575 d_fprintf(stderr, "ADS support not compiled in\n");
2579 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2581 return net_ads_noads();
2584 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2586 return net_ads_noads();
2589 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2591 return net_ads_noads();
2594 int net_ads_join(struct net_context *c, int argc, const char **argv)
2596 return net_ads_noads();
2599 int net_ads_user(struct net_context *c, int argc, const char **argv)
2601 return net_ads_noads();
2604 int net_ads_group(struct net_context *c, int argc, const char **argv)
2606 return net_ads_noads();
2609 /* this one shouldn't display a message */
2610 int net_ads_check(struct net_context *c)
2615 int net_ads_check_our_domain(struct net_context *c)
2620 int net_ads(struct net_context *c, int argc, const char **argv)
2622 return net_ads_noads();
2625 #endif /* WITH_ADS */