2 Samba Unix/Linux SMB client library
4 Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
5 Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
6 Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
7 Copyright (C) 2006 Gerald (Jerry) Carter (jerry@samba.org)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "utils/net.h"
25 #include "librpc/gen_ndr/ndr_krb5pac.h"
26 #include "nsswitch/libwbclient/wbclient.h"
30 /* when we do not have sufficient input parameters to contact a remote domain
31 * we always fall back to our own realm - Guenther*/
33 static const char *assume_own_realm(struct net_context *c)
35 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
43 do a cldap netlogon query
45 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
47 char addr[INET6_ADDRSTRLEN];
48 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
50 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
51 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
52 d_fprintf(stderr, "CLDAP query failed!\n");
56 d_printf("Information for Domain Controller: %s\n\n",
59 d_printf("Response Type: ");
60 switch (reply.command) {
61 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
62 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
64 case LOGON_SAM_LOGON_RESPONSE_EX:
65 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
68 d_printf("0x%x\n", reply.command);
72 d_printf("GUID: %s\n", GUID_string(talloc_tos(), &reply.domain_uuid));
76 "\tIs a GC of the forest: %s\n"
77 "\tIs an LDAP server: %s\n"
79 "\tIs running a KDC: %s\n"
80 "\tIs running time services: %s\n"
81 "\tIs the closest DC: %s\n"
83 "\tHas a hardware clock: %s\n"
84 "\tIs a non-domain NC serviced by LDAP server: %s\n"
85 "\tIs NT6 DC that has some secrets: %s\n"
86 "\tIs NT6 DC that has all secrets: %s\n",
87 (reply.server_type & NBT_SERVER_PDC) ? "yes" : "no",
88 (reply.server_type & NBT_SERVER_GC) ? "yes" : "no",
89 (reply.server_type & NBT_SERVER_LDAP) ? "yes" : "no",
90 (reply.server_type & NBT_SERVER_DS) ? "yes" : "no",
91 (reply.server_type & NBT_SERVER_KDC) ? "yes" : "no",
92 (reply.server_type & NBT_SERVER_TIMESERV) ? "yes" : "no",
93 (reply.server_type & NBT_SERVER_CLOSEST) ? "yes" : "no",
94 (reply.server_type & NBT_SERVER_WRITABLE) ? "yes" : "no",
95 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? "yes" : "no",
96 (reply.server_type & NBT_SERVER_NDNC) ? "yes" : "no",
97 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? "yes" : "no",
98 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? "yes" : "no");
101 printf("Forest:\t\t\t%s\n", reply.forest);
102 printf("Domain:\t\t\t%s\n", reply.dns_domain);
103 printf("Domain Controller:\t%s\n", reply.pdc_dns_name);
105 printf("Pre-Win2k Domain:\t%s\n", reply.domain);
106 printf("Pre-Win2k Hostname:\t%s\n", reply.pdc_name);
108 if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
110 printf("Server Site Name :\t\t%s\n", reply.server_site);
111 printf("Client Site Name :\t\t%s\n", reply.client_site);
113 d_printf("NT Version: %d\n", reply.nt_version);
114 d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
115 d_printf("LM20 Token: %.2x\n", reply.lm20_token);
121 this implements the CLDAP based netlogon lookup requests
122 for finding the domain controller of a ADS domain
124 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
129 if (c->display_usage) {
132 " Find the ADS DC using CLDAP lookup.\n");
136 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
137 d_fprintf(stderr, "Didn't find the cldap server!\n");
142 if (!ads->config.realm) {
143 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
144 ads->ldap.port = 389;
147 ret = net_ads_cldap_netlogon(c, ads);
154 static int net_ads_info(struct net_context *c, int argc, const char **argv)
157 char addr[INET6_ADDRSTRLEN];
159 if (c->display_usage) {
162 " Display information about an Active Directory "
167 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
168 d_fprintf(stderr, "Didn't find the ldap server!\n");
172 if (!ads || !ads->config.realm) {
173 d_fprintf(stderr, "Didn't find the ldap server!\n");
178 /* Try to set the server's current time since we didn't do a full
179 TCP LDAP session initially */
181 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
182 d_fprintf( stderr, "Failed to get server's current time!\n");
185 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
187 d_printf("LDAP server: %s\n", addr);
188 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
189 d_printf("Realm: %s\n", ads->config.realm);
190 d_printf("Bind Path: %s\n", ads->config.bind_path);
191 d_printf("LDAP port: %d\n", ads->ldap.port);
192 d_printf("Server time: %s\n",
193 http_timestring(talloc_tos(), ads->config.current_time));
195 d_printf("KDC server: %s\n", ads->auth.kdc_server );
196 d_printf("Server time offset: %d\n", ads->auth.time_offset );
202 static void use_in_memory_ccache(void) {
203 /* Use in-memory credentials cache so we do not interfere with
204 * existing credentials */
205 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
208 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
209 uint32 auth_flags, ADS_STRUCT **ads_ret)
211 ADS_STRUCT *ads = NULL;
213 bool need_password = false;
214 bool second_time = false;
216 const char *realm = NULL;
217 bool tried_closest_dc = false;
219 /* lp_realm() should be handled by a command line param,
220 However, the join requires that realm be set in smb.conf
221 and compares our realm with the remote server's so this is
222 ok until someone needs more flexibility */
227 if (only_own_domain) {
230 realm = assume_own_realm(c);
233 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
235 if (!c->opt_user_name) {
236 c->opt_user_name = "administrator";
239 if (c->opt_user_specified) {
240 need_password = true;
244 if (!c->opt_password && need_password && !c->opt_machine_pass) {
245 c->opt_password = net_prompt_pass(c, c->opt_user_name);
246 if (!c->opt_password) {
248 return ADS_ERROR(LDAP_NO_MEMORY);
252 if (c->opt_password) {
253 use_in_memory_ccache();
254 SAFE_FREE(ads->auth.password);
255 ads->auth.password = smb_xstrdup(c->opt_password);
258 ads->auth.flags |= auth_flags;
259 SAFE_FREE(ads->auth.user_name);
260 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
263 * If the username is of the form "name@realm",
264 * extract the realm and convert to upper case.
265 * This is only used to establish the connection.
267 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
269 SAFE_FREE(ads->auth.realm);
270 ads->auth.realm = smb_xstrdup(cp);
271 strupper_m(ads->auth.realm);
274 status = ads_connect(ads);
276 if (!ADS_ERR_OK(status)) {
278 if (NT_STATUS_EQUAL(ads_ntstatus(status),
279 NT_STATUS_NO_LOGON_SERVERS)) {
280 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
285 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
286 need_password = true;
295 /* when contacting our own domain, make sure we use the closest DC.
296 * This is done by reconnecting to ADS because only the first call to
297 * ads_connect will give us our own sitename */
299 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
301 tried_closest_dc = true; /* avoid loop */
303 if (!ads_closest_dc(ads)) {
305 namecache_delete(ads->server.realm, 0x1C);
306 namecache_delete(ads->server.workgroup, 0x1C);
319 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
321 return ads_startup_int(c, only_own_domain, 0, ads);
324 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
326 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
330 Check to see if connection can be made via ads.
331 ads_startup() stores the password in opt_password if it needs to so
332 that rpc or rap can use it without re-prompting.
334 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
339 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
343 ads->auth.flags |= ADS_AUTH_NO_BIND;
345 status = ads_connect(ads);
346 if ( !ADS_ERR_OK(status) ) {
354 int net_ads_check_our_domain(struct net_context *c)
356 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
359 int net_ads_check(struct net_context *c)
361 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
365 determine the netbios workgroup name for a domain
367 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
370 char addr[INET6_ADDRSTRLEN];
371 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
373 if (c->display_usage) {
375 "net ads workgroup\n"
376 " Print the workgroup name\n");
380 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
381 d_fprintf(stderr, "Didn't find the cldap server!\n");
385 if (!ads->config.realm) {
386 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
387 ads->ldap.port = 389;
390 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
391 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
392 d_fprintf(stderr, "CLDAP query failed!\n");
397 d_printf("Workgroup: %s\n", reply.domain);
406 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
408 char **disp_fields = (char **) data_area;
410 if (!field) { /* must be end of record */
411 if (disp_fields[0]) {
412 if (!strchr_m(disp_fields[0], '$')) {
414 d_printf("%-21.21s %s\n",
415 disp_fields[0], disp_fields[1]);
417 d_printf("%s\n", disp_fields[0]);
420 SAFE_FREE(disp_fields[0]);
421 SAFE_FREE(disp_fields[1]);
424 if (!values) /* must be new field, indicate string field */
426 if (StrCaseCmp(field, "sAMAccountName") == 0) {
427 disp_fields[0] = SMB_STRDUP((char *) values[0]);
429 if (StrCaseCmp(field, "description") == 0)
430 disp_fields[1] = SMB_STRDUP((char *) values[0]);
434 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
436 return net_user_usage(c, argc, argv);
439 static int ads_user_add(struct net_context *c, int argc, const char **argv)
444 LDAPMessage *res=NULL;
448 if (argc < 1 || c->display_usage)
449 return net_ads_user_usage(c, argc, argv);
451 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
455 status = ads_find_user_acct(ads, &res, argv[0]);
457 if (!ADS_ERR_OK(status)) {
458 d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
462 if (ads_count_replies(ads, res)) {
463 d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
467 if (c->opt_container) {
468 ou_str = SMB_STRDUP(c->opt_container);
470 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
473 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
475 if (!ADS_ERR_OK(status)) {
476 d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
481 /* if no password is to be set, we're done */
483 d_printf("User %s added\n", argv[0]);
488 /* try setting the password */
489 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
492 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
493 ads->auth.time_offset);
495 if (ADS_ERR_OK(status)) {
496 d_printf("User %s added\n", argv[0]);
501 /* password didn't set, delete account */
502 d_fprintf(stderr, "Could not add user %s. Error setting password %s\n",
503 argv[0], ads_errstr(status));
504 ads_msgfree(ads, res);
505 status=ads_find_user_acct(ads, &res, argv[0]);
506 if (ADS_ERR_OK(status)) {
507 userdn = ads_get_dn(ads, talloc_tos(), res);
508 ads_del_dn(ads, userdn);
514 ads_msgfree(ads, res);
520 static int ads_user_info(struct net_context *c, int argc, const char **argv)
522 ADS_STRUCT *ads = NULL;
524 LDAPMessage *res = NULL;
528 const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
529 char *searchstring=NULL;
533 DOM_SID primary_group_sid;
535 enum SID_NAME_USE type;
537 if (argc < 1 || c->display_usage) {
538 return net_ads_user_usage(c, argc, argv);
541 frame = talloc_new(talloc_tos());
546 escaped_user = escape_ldap_string(frame, argv[0]);
548 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
552 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
557 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
561 rc = ads_search(ads, &res, searchstring, attrs);
562 SAFE_FREE(searchstring);
564 if (!ADS_ERR_OK(rc)) {
565 d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
570 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
571 d_fprintf(stderr, "ads_pull_uint32 failed\n");
576 rc = ads_domain_sid(ads, &primary_group_sid);
577 if (!ADS_ERR_OK(rc)) {
578 d_fprintf(stderr, "ads_domain_sid: %s\n", ads_errstr(rc));
583 sid_append_rid(&primary_group_sid, group_rid);
585 wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
586 NULL, /* don't look up domain */
588 (enum wbcSidType *) &type);
589 if (!WBC_ERROR_IS_OK(wbc_status)) {
590 d_fprintf(stderr, "wbcLookupSid: %s\n",
591 wbcErrorString(wbc_status));
596 d_printf("%s\n", primary_group);
598 wbcFreeMemory(primary_group);
600 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
601 (LDAPMessage *)res, "memberOf");
606 for (i=0;grouplist[i];i++) {
607 groupname = ldap_explode_dn(grouplist[i], 1);
608 d_printf("%s\n", groupname[0]);
609 ldap_value_free(groupname);
611 ldap_value_free(grouplist);
615 if (res) ads_msgfree(ads, res);
616 if (ads) ads_destroy(&ads);
621 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
625 LDAPMessage *res = NULL;
629 return net_ads_user_usage(c, argc, argv);
632 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
636 rc = ads_find_user_acct(ads, &res, argv[0]);
637 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
638 d_printf("User %s does not exist.\n", argv[0]);
639 ads_msgfree(ads, res);
643 userdn = ads_get_dn(ads, talloc_tos(), res);
644 ads_msgfree(ads, res);
645 rc = ads_del_dn(ads, userdn);
647 if (ADS_ERR_OK(rc)) {
648 d_printf("User %s deleted\n", argv[0]);
652 d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
658 int net_ads_user(struct net_context *c, int argc, const char **argv)
660 struct functable func[] = {
673 "Display information about an AD user",
674 "net ads user info\n"
675 " Display information about an AD user"
682 "net ads user delete\n"
685 {NULL, NULL, 0, NULL, NULL}
689 const char *shortattrs[] = {"sAMAccountName", NULL};
690 const char *longattrs[] = {"sAMAccountName", "description", NULL};
691 char *disp_fields[2] = {NULL, NULL};
694 if (c->display_usage) {
695 d_printf("Usage:\n");
696 d_printf("net ads user\n"
698 net_display_usage_from_functable(func);
702 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
706 if (c->opt_long_list_entries)
707 d_printf("\nUser name Comment"
708 "\n-----------------------------\n");
710 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
712 "(objectCategory=user)",
713 c->opt_long_list_entries ? longattrs :
714 shortattrs, usergrp_display,
717 return ADS_ERR_OK(rc) ? 0 : -1;
720 return net_run_function(c, argc, argv, "net ads user", func);
723 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
725 return net_group_usage(c, argc, argv);
728 static int ads_group_add(struct net_context *c, int argc, const char **argv)
732 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 status = ads_find_user_acct(ads, &res, argv[0]);
746 if (!ADS_ERR_OK(status)) {
747 d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
751 if (ads_count_replies(ads, res)) {
752 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
756 if (c->opt_container) {
757 ou_str = SMB_STRDUP(c->opt_container);
759 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
762 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
764 if (ADS_ERR_OK(status)) {
765 d_printf("Group %s added\n", argv[0]);
768 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
774 ads_msgfree(ads, res);
780 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
784 LDAPMessage *res = NULL;
787 if (argc < 1 || c->display_usage) {
788 return net_ads_group_usage(c, argc, argv);
791 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
795 rc = ads_find_user_acct(ads, &res, argv[0]);
796 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
797 d_printf("Group %s does not exist.\n", argv[0]);
798 ads_msgfree(ads, res);
802 groupdn = ads_get_dn(ads, talloc_tos(), res);
803 ads_msgfree(ads, res);
804 rc = ads_del_dn(ads, groupdn);
805 TALLOC_FREE(groupdn);
806 if (ADS_ERR_OK(rc)) {
807 d_printf("Group %s deleted\n", argv[0]);
811 d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
817 int net_ads_group(struct net_context *c, int argc, const char **argv)
819 struct functable func[] = {
825 "net ads group add\n"
832 "Delete an AD group",
833 "net ads group delete\n"
834 " Delete an AD group"
836 {NULL, NULL, 0, NULL, NULL}
840 const char *shortattrs[] = {"sAMAccountName", NULL};
841 const char *longattrs[] = {"sAMAccountName", "description", NULL};
842 char *disp_fields[2] = {NULL, NULL};
845 if (c->display_usage) {
846 d_printf("Usage:\n");
847 d_printf("net ads group\n"
848 " List AD groups\n");
849 net_display_usage_from_functable(func);
853 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
857 if (c->opt_long_list_entries)
858 d_printf("\nGroup name Comment"
859 "\n-----------------------------\n");
860 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
862 "(objectCategory=group)",
863 c->opt_long_list_entries ? longattrs :
864 shortattrs, usergrp_display,
868 return ADS_ERR_OK(rc) ? 0 : -1;
870 return net_run_function(c, argc, argv, "net ads group", func);
873 static int net_ads_status(struct net_context *c, int argc, const char **argv)
879 if (c->display_usage) {
882 " Display machine account details\n");
886 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
890 rc = ads_find_machine_acct(ads, &res, global_myname());
891 if (!ADS_ERR_OK(rc)) {
892 d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
897 if (ads_count_replies(ads, res) == 0) {
898 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
908 /*******************************************************************
909 Leave an AD domain. Windows XP disables the machine account.
910 We'll try the same. The old code would do an LDAP delete.
911 That only worked using the machine creds because added the machine
912 with full control to the computer object's ACL.
913 *******************************************************************/
915 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
918 struct libnet_UnjoinCtx *r = NULL;
921 if (c->display_usage) {
924 " Leave an AD domain\n");
929 d_fprintf(stderr, "No realm set, are we joined ?\n");
933 if (!(ctx = talloc_init("net_ads_leave"))) {
934 d_fprintf(stderr, "Could not initialise talloc context.\n");
938 if (!c->opt_kerberos) {
939 use_in_memory_ccache();
942 werr = libnet_init_UnjoinCtx(ctx, &r);
943 if (!W_ERROR_IS_OK(werr)) {
944 d_fprintf(stderr, "Could not initialise unjoin context.\n");
949 r->in.use_kerberos = c->opt_kerberos;
950 r->in.dc_name = c->opt_host;
951 r->in.domain_name = lp_realm();
952 r->in.admin_account = c->opt_user_name;
953 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
954 r->in.modify_config = lp_config_backend_is_registry();
956 /* Try to delete it, but if that fails, disable it. The
957 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
958 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
959 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
960 r->in.delete_machine_account = true;
962 werr = libnet_Unjoin(ctx, r);
963 if (!W_ERROR_IS_OK(werr)) {
964 d_printf("Failed to leave domain: %s\n",
965 r->out.error_string ? r->out.error_string :
966 get_friendly_werror_msg(werr));
970 if (r->out.deleted_machine_account) {
971 d_printf("Deleted account for '%s' in realm '%s'\n",
972 r->in.machine_name, r->out.dns_domain_name);
976 /* We couldn't delete it - see if the disable succeeded. */
977 if (r->out.disabled_machine_account) {
978 d_printf("Disabled account for '%s' in realm '%s'\n",
979 r->in.machine_name, r->out.dns_domain_name);
984 /* Based on what we requseted, we shouldn't get here, but if
985 we did, it means the secrets were removed, and therefore
986 we have left the domain */
987 d_fprintf(stderr, "Machine '%s' Left domain '%s'\n",
988 r->in.machine_name, r->out.dns_domain_name);
994 if (W_ERROR_IS_OK(werr)) {
1001 static NTSTATUS net_ads_join_ok(struct net_context *c)
1003 ADS_STRUCT *ads = NULL;
1006 if (!secrets_init()) {
1007 DEBUG(1,("Failed to initialise secrets database\n"));
1008 return NT_STATUS_ACCESS_DENIED;
1011 net_use_krb_machine_account(c);
1013 status = ads_startup(c, true, &ads);
1014 if (!ADS_ERR_OK(status)) {
1015 return ads_ntstatus(status);
1019 return NT_STATUS_OK;
1023 check that an existing join is OK
1025 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1028 use_in_memory_ccache();
1030 if (c->display_usage) {
1032 "net ads testjoin\n"
1033 " Test if the existing join is ok\n");
1037 /* Display success or failure */
1038 status = net_ads_join_ok(c);
1039 if (!NT_STATUS_IS_OK(status)) {
1040 fprintf(stderr,"Join to domain is not valid: %s\n",
1041 get_friendly_nt_error_msg(status));
1045 printf("Join is OK\n");
1049 /*******************************************************************
1050 Simple configu checks before beginning the join
1051 ********************************************************************/
1053 static WERROR check_ads_config( void )
1055 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1056 d_printf("Host is not configured as a member server.\n");
1057 return WERR_INVALID_DOMAIN_ROLE;
1060 if (strlen(global_myname()) > 15) {
1061 d_printf("Our netbios name can be at most 15 chars long, "
1062 "\"%s\" is %u chars long\n", global_myname(),
1063 (unsigned int)strlen(global_myname()));
1064 return WERR_INVALID_COMPUTERNAME;
1067 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1068 d_fprintf(stderr, "realm must be set in in %s for ADS "
1069 "join to succeed.\n", get_dyn_CONFIGFILE());
1070 return WERR_INVALID_PARAM;
1076 /*******************************************************************
1077 Send a DNS update request
1078 *******************************************************************/
1080 #if defined(WITH_DNS_UPDATES)
1082 DNS_ERROR DoDNSUpdate(char *pszServerName,
1083 const char *pszDomainName, const char *pszHostName,
1084 const struct sockaddr_storage *sslist,
1087 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1088 const char *machine_name,
1089 const struct sockaddr_storage *addrs,
1092 struct dns_rr_ns *nameservers = NULL;
1094 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1097 const char *dnsdomain = NULL;
1098 char *root_domain = NULL;
1100 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1101 d_printf("No DNS domain configured for %s. "
1102 "Unable to perform DNS Update.\n", machine_name);
1103 status = NT_STATUS_INVALID_PARAMETER;
1108 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1109 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1110 /* Child domains often do not have NS records. Look
1111 for the NS record for the forest root domain
1112 (rootDomainNamingContext in therootDSE) */
1114 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1115 LDAPMessage *msg = NULL;
1117 ADS_STATUS ads_status;
1119 if ( !ads->ldap.ld ) {
1120 ads_status = ads_connect( ads );
1121 if ( !ADS_ERR_OK(ads_status) ) {
1122 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1127 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1128 "(objectclass=*)", rootname_attrs, &msg);
1129 if (!ADS_ERR_OK(ads_status)) {
1133 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1135 ads_msgfree( ads, msg );
1139 root_domain = ads_build_domain( root_dn );
1142 ads_msgfree( ads, msg );
1144 /* try again for NS servers */
1146 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1148 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1149 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1150 "realm\n", ads->config.realm));
1154 dnsdomain = root_domain;
1158 /* Now perform the dns update - we'll try non-secure and if we fail,
1159 we'll follow it up with a secure update */
1161 fstrcpy( dns_server, nameservers[0].hostname );
1163 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1164 if (!ERR_DNS_IS_OK(dns_err)) {
1165 status = NT_STATUS_UNSUCCESSFUL;
1170 SAFE_FREE( root_domain );
1175 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1178 struct sockaddr_storage *iplist = NULL;
1179 fstring machine_name;
1182 name_to_fqdn( machine_name, global_myname() );
1183 strlower_m( machine_name );
1185 /* Get our ip address (not the 127.0.0.x address but a real ip
1188 num_addrs = get_my_ip_address( &iplist );
1189 if ( num_addrs <= 0 ) {
1190 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1192 return NT_STATUS_INVALID_PARAMETER;
1195 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1197 SAFE_FREE( iplist );
1203 /*******************************************************************
1204 ********************************************************************/
1206 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1208 d_printf("net ads join [options]\n");
1209 d_printf("Valid options:\n");
1210 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1211 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1212 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1213 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1214 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1215 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1216 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1217 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1218 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1219 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1220 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1221 d_printf(" the two other attributes.\n");
1226 /*******************************************************************
1227 ********************************************************************/
1229 int net_ads_join(struct net_context *c, int argc, const char **argv)
1231 TALLOC_CTX *ctx = NULL;
1232 struct libnet_JoinCtx *r = NULL;
1233 const char *domain = lp_realm();
1234 WERROR werr = WERR_SETUP_NOT_JOINED;
1235 bool createupn = false;
1236 const char *machineupn = NULL;
1237 const char *create_in_ou = NULL;
1239 const char *os_name = NULL;
1240 const char *os_version = NULL;
1241 bool modify_config = lp_config_backend_is_registry();
1243 if (c->display_usage)
1244 return net_ads_join_usage(c, argc, argv);
1246 if (!modify_config) {
1248 werr = check_ads_config();
1249 if (!W_ERROR_IS_OK(werr)) {
1250 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1255 if (!(ctx = talloc_init("net_ads_join"))) {
1256 d_fprintf(stderr, "Could not initialise talloc context.\n");
1261 if (!c->opt_kerberos) {
1262 use_in_memory_ccache();
1265 werr = libnet_init_JoinCtx(ctx, &r);
1266 if (!W_ERROR_IS_OK(werr)) {
1270 /* process additional command line args */
1272 for ( i=0; i<argc; i++ ) {
1273 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1275 machineupn = get_string_param(argv[i]);
1277 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1278 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1279 d_fprintf(stderr, "Please supply a valid OU path.\n");
1280 werr = WERR_INVALID_PARAM;
1284 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1285 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1286 d_fprintf(stderr, "Please supply a operating system name.\n");
1287 werr = WERR_INVALID_PARAM;
1291 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1292 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1293 d_fprintf(stderr, "Please supply a valid operating system version.\n");
1294 werr = WERR_INVALID_PARAM;
1304 d_fprintf(stderr, "Please supply a valid domain name\n");
1305 werr = WERR_INVALID_PARAM;
1309 /* Do the domain join here */
1311 r->in.domain_name = domain;
1312 r->in.create_upn = createupn;
1313 r->in.upn = machineupn;
1314 r->in.account_ou = create_in_ou;
1315 r->in.os_name = os_name;
1316 r->in.os_version = os_version;
1317 r->in.dc_name = c->opt_host;
1318 r->in.admin_account = c->opt_user_name;
1319 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1321 r->in.use_kerberos = c->opt_kerberos;
1322 r->in.modify_config = modify_config;
1323 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1324 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1325 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1327 werr = libnet_Join(ctx, r);
1328 if (!W_ERROR_IS_OK(werr)) {
1332 /* Check the short name of the domain */
1334 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1335 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1336 d_printf("domain name obtained from the server.\n");
1337 d_printf("Using the name [%s] from the server.\n", r->out.netbios_domain_name);
1338 d_printf("You should set \"workgroup = %s\" in %s.\n",
1339 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1342 d_printf("Using short domain name -- %s\n", r->out.netbios_domain_name);
1344 if (r->out.dns_domain_name) {
1345 d_printf("Joined '%s' to realm '%s'\n", r->in.machine_name,
1346 r->out.dns_domain_name);
1348 d_printf("Joined '%s' to domain '%s'\n", r->in.machine_name,
1349 r->out.netbios_domain_name);
1352 #if defined(WITH_DNS_UPDATES)
1353 if (r->out.domain_is_ad) {
1354 /* We enter this block with user creds */
1355 ADS_STRUCT *ads_dns = NULL;
1357 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1358 /* kinit with the machine password */
1360 use_in_memory_ccache();
1361 if (asprintf( &ads_dns->auth.user_name, "%s$", global_myname()) == -1) {
1364 ads_dns->auth.password = secrets_fetch_machine_password(
1365 r->out.netbios_domain_name, NULL, NULL );
1366 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1367 strupper_m(ads_dns->auth.realm );
1368 ads_kinit_password( ads_dns );
1371 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1372 d_fprintf( stderr, "DNS update failed!\n" );
1375 /* exit from this block using machine creds */
1376 ads_destroy(&ads_dns);
1385 /* issue an overall failure message at the end. */
1386 d_printf("Failed to join domain: %s\n",
1387 r && r->out.error_string ? r->out.error_string :
1388 get_friendly_werror_msg(werr));
1394 /*******************************************************************
1395 ********************************************************************/
1397 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1399 #if defined(WITH_DNS_UPDATES)
1405 talloc_enable_leak_report();
1408 if (argc > 0 || c->display_usage) {
1410 "net ads dns register\n"
1411 " Register hostname with DNS\n");
1415 if (!(ctx = talloc_init("net_ads_dns"))) {
1416 d_fprintf(stderr, "Could not initialise talloc context\n");
1420 status = ads_startup(c, true, &ads);
1421 if ( !ADS_ERR_OK(status) ) {
1422 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1427 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1428 d_fprintf( stderr, "DNS update failed!\n" );
1429 ads_destroy( &ads );
1434 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1441 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1446 #if defined(WITH_DNS_UPDATES)
1447 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1450 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1452 #if defined(WITH_DNS_UPDATES)
1456 talloc_enable_leak_report();
1459 if (argc != 2 || c->display_usage) {
1461 "net ads dns gethostbyname <server> <name>\n"
1462 " Look up hostname from the AD\n"
1463 " server\tName server to use\n"
1464 " name\tName to look up\n");
1468 err = do_gethostbyname(argv[0], argv[1]);
1470 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1475 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1477 struct functable func[] = {
1480 net_ads_dns_register,
1482 "Add host dns entry to AD",
1483 "net ads dns register\n"
1484 " Add host dns entry to AD"
1488 net_ads_dns_gethostbyname,
1491 "net ads dns gethostbyname\n"
1494 {NULL, NULL, 0, NULL, NULL}
1497 return net_run_function(c, argc, argv, "net ads dns", func);
1500 /*******************************************************************
1501 ********************************************************************/
1503 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1506 "\nnet ads printer search <printer>"
1507 "\n\tsearch for a printer in the directory\n"
1508 "\nnet ads printer info <printer> <server>"
1509 "\n\tlookup info in directory for printer on server"
1510 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1511 "\nnet ads printer publish <printername>"
1512 "\n\tpublish printer in directory"
1513 "\n\t(note: printer name is required)\n"
1514 "\nnet ads printer remove <printername>"
1515 "\n\tremove printer from directory"
1516 "\n\t(note: printer name is required)\n");
1520 /*******************************************************************
1521 ********************************************************************/
1523 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1527 LDAPMessage *res = NULL;
1529 if (c->display_usage) {
1531 "net ads printer search\n"
1532 " List printers in the AD\n");
1536 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1540 rc = ads_find_printers(ads, &res);
1542 if (!ADS_ERR_OK(rc)) {
1543 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1544 ads_msgfree(ads, res);
1549 if (ads_count_replies(ads, res) == 0) {
1550 d_fprintf(stderr, "No results found\n");
1551 ads_msgfree(ads, res);
1557 ads_msgfree(ads, res);
1562 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1566 const char *servername, *printername;
1567 LDAPMessage *res = NULL;
1569 if (c->display_usage) {
1571 "net ads printer info [printername [servername]]\n"
1572 " Display printer info from AD\n"
1573 " printername\tPrinter name or wildcard\n"
1574 " servername\tName of the print server\n");
1578 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1583 printername = argv[0];
1589 servername = argv[1];
1591 servername = global_myname();
1594 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1596 if (!ADS_ERR_OK(rc)) {
1597 d_fprintf(stderr, "Server '%s' not found: %s\n",
1598 servername, ads_errstr(rc));
1599 ads_msgfree(ads, res);
1604 if (ads_count_replies(ads, res) == 0) {
1605 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1606 ads_msgfree(ads, res);
1612 ads_msgfree(ads, res);
1618 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1622 const char *servername, *printername;
1623 struct cli_state *cli;
1624 struct rpc_pipe_client *pipe_hnd;
1625 struct sockaddr_storage server_ss;
1627 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1628 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1629 char *prt_dn, *srv_dn, **srv_cn;
1630 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1631 LDAPMessage *res = NULL;
1633 if (argc < 1 || c->display_usage) {
1635 "net ads printer publish <printername> [servername]\n"
1636 " Publish printer in AD\n"
1637 " printername\tName of the printer\n"
1638 " servername\tName of the print server\n");
1639 talloc_destroy(mem_ctx);
1643 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1644 talloc_destroy(mem_ctx);
1648 printername = argv[0];
1651 servername = argv[1];
1653 servername = global_myname();
1656 /* Get printer data from SPOOLSS */
1658 resolve_name(servername, &server_ss, 0x20, false);
1660 nt_status = cli_full_connection(&cli, global_myname(), servername,
1663 c->opt_user_name, c->opt_workgroup,
1664 c->opt_password ? c->opt_password : "",
1665 CLI_FULL_CONNECTION_USE_KERBEROS,
1668 if (NT_STATUS_IS_ERR(nt_status)) {
1669 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1670 "for %s\n", servername, printername);
1672 talloc_destroy(mem_ctx);
1676 /* Publish on AD server */
1678 ads_find_machine_acct(ads, &res, servername);
1680 if (ads_count_replies(ads, res) == 0) {
1681 d_fprintf(stderr, "Could not find machine account for server %s\n",
1684 talloc_destroy(mem_ctx);
1688 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1689 srv_cn = ldap_explode_dn(srv_dn, 1);
1691 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1692 printername_escaped = escape_rdn_val_string_alloc(printername);
1693 if (!srv_cn_escaped || !printername_escaped) {
1694 SAFE_FREE(srv_cn_escaped);
1695 SAFE_FREE(printername_escaped);
1696 d_fprintf(stderr, "Internal error, out of memory!");
1698 talloc_destroy(mem_ctx);
1702 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1703 SAFE_FREE(srv_cn_escaped);
1704 SAFE_FREE(printername_escaped);
1705 d_fprintf(stderr, "Internal error, out of memory!");
1707 talloc_destroy(mem_ctx);
1711 SAFE_FREE(srv_cn_escaped);
1712 SAFE_FREE(printername_escaped);
1714 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
1715 if (!NT_STATUS_IS_OK(nt_status)) {
1716 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1720 talloc_destroy(mem_ctx);
1724 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1728 talloc_destroy(mem_ctx);
1732 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1733 if (!ADS_ERR_OK(rc)) {
1734 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1737 talloc_destroy(mem_ctx);
1741 d_printf("published printer\n");
1744 talloc_destroy(mem_ctx);
1749 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1753 const char *servername;
1755 LDAPMessage *res = NULL;
1757 if (argc < 1 || c->display_usage) {
1759 "net ads printer remove <printername> [servername]\n"
1760 " Remove a printer from the AD\n"
1761 " printername\tName of the printer\n"
1762 " servername\tName of the print server\n");
1766 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1771 servername = argv[1];
1773 servername = global_myname();
1776 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1778 if (!ADS_ERR_OK(rc)) {
1779 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1780 ads_msgfree(ads, res);
1785 if (ads_count_replies(ads, res) == 0) {
1786 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1787 ads_msgfree(ads, res);
1792 prt_dn = ads_get_dn(ads, talloc_tos(), res);
1793 ads_msgfree(ads, res);
1794 rc = ads_del_dn(ads, prt_dn);
1795 TALLOC_FREE(prt_dn);
1797 if (!ADS_ERR_OK(rc)) {
1798 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1807 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1809 struct functable func[] = {
1812 net_ads_printer_search,
1814 "Search for a printer",
1815 "net ads printer search\n"
1816 " Search for a printer"
1820 net_ads_printer_info,
1822 "Display printer information",
1823 "net ads printer info\n"
1824 " Display printer information"
1828 net_ads_printer_publish,
1830 "Publish a printer",
1831 "net ads printer publish\n"
1832 " Publish a printer"
1836 net_ads_printer_remove,
1839 "net ads printer remove\n"
1842 {NULL, NULL, 0, NULL, NULL}
1845 return net_run_function(c, argc, argv, "net ads printer", func);
1849 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1852 const char *auth_principal = c->opt_user_name;
1853 const char *auth_password = c->opt_password;
1855 char *new_password = NULL;
1860 if (c->display_usage) {
1862 "net ads password <username>\n"
1863 " Change password for user\n"
1864 " username\tName of user to change password for\n");
1868 if (c->opt_user_name == NULL || c->opt_password == NULL) {
1869 d_fprintf(stderr, "You must supply an administrator username/password\n");
1874 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1879 if (!strchr_m(user, '@')) {
1880 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
1886 use_in_memory_ccache();
1887 chr = strchr_m(auth_principal, '@');
1894 /* use the realm so we can eventually change passwords for users
1895 in realms other than default */
1896 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1900 /* we don't actually need a full connect, but it's the easy way to
1901 fill in the KDC's addresss */
1904 if (!ads->config.realm) {
1905 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1911 new_password = (char *)argv[1];
1913 if (asprintf(&prompt, "Enter new password for %s:", user) == -1) {
1916 new_password = getpass(prompt);
1920 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1921 auth_password, user, new_password, ads->auth.time_offset);
1922 if (!ADS_ERR_OK(ret)) {
1923 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1928 d_printf("Password change for %s completed.\n", user);
1934 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1937 char *host_principal;
1941 if (c->display_usage) {
1943 "net ads changetrustpw\n"
1944 " Change the machine account's trust password\n");
1948 if (!secrets_init()) {
1949 DEBUG(1,("Failed to initialise secrets database\n"));
1953 net_use_krb_machine_account(c);
1955 use_in_memory_ccache();
1957 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1961 fstrcpy(my_name, global_myname());
1962 strlower_m(my_name);
1963 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
1967 d_printf("Changing password for principal: %s\n", host_principal);
1969 ret = ads_change_trust_account_password(ads, host_principal);
1971 if (!ADS_ERR_OK(ret)) {
1972 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1974 SAFE_FREE(host_principal);
1978 d_printf("Password change for principal %s succeeded.\n", host_principal);
1980 if (USE_SYSTEM_KEYTAB) {
1981 d_printf("Attempting to update system keytab with new password.\n");
1982 if (ads_keytab_create_default(ads)) {
1983 d_printf("Failed to update system keytab.\n");
1988 SAFE_FREE(host_principal);
1994 help for net ads search
1996 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
1999 "\nnet ads search <expression> <attributes...>\n"
2000 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2001 "The expression is a standard LDAP search expression, and the\n"
2002 "attributes are a list of LDAP fields to show in the results.\n\n"
2003 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2005 net_common_flags_usage(c, argc, argv);
2011 general ADS search function. Useful in diagnosing problems in ADS
2013 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2017 const char *ldap_exp;
2019 LDAPMessage *res = NULL;
2021 if (argc < 1 || c->display_usage) {
2022 return net_ads_search_usage(c, argc, argv);
2025 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2032 rc = ads_do_search_all(ads, ads->config.bind_path,
2034 ldap_exp, attrs, &res);
2035 if (!ADS_ERR_OK(rc)) {
2036 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2041 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2043 /* dump the results */
2046 ads_msgfree(ads, res);
2054 help for net ads search
2056 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2059 "\nnet ads dn <dn> <attributes...>\n"
2060 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2061 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2062 "to show in the results\n\n"
2063 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2064 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2066 net_common_flags_usage(c, argc, argv);
2072 general ADS search function. Useful in diagnosing problems in ADS
2074 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2080 LDAPMessage *res = NULL;
2082 if (argc < 1 || c->display_usage) {
2083 return net_ads_dn_usage(c, argc, argv);
2086 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2093 rc = ads_do_search_all(ads, dn,
2095 "(objectclass=*)", attrs, &res);
2096 if (!ADS_ERR_OK(rc)) {
2097 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2102 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2104 /* dump the results */
2107 ads_msgfree(ads, res);
2114 help for net ads sid search
2116 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2119 "\nnet ads sid <sid> <attributes...>\n"
2120 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2121 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2122 "to show in the results\n\n"
2123 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2125 net_common_flags_usage(c, argc, argv);
2131 general ADS search function. Useful in diagnosing problems in ADS
2133 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2137 const char *sid_string;
2139 LDAPMessage *res = NULL;
2142 if (argc < 1 || c->display_usage) {
2143 return net_ads_sid_usage(c, argc, argv);
2146 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2150 sid_string = argv[0];
2153 if (!string_to_sid(&sid, sid_string)) {
2154 d_fprintf(stderr, "could not convert sid\n");
2159 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2160 if (!ADS_ERR_OK(rc)) {
2161 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2166 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2168 /* dump the results */
2171 ads_msgfree(ads, res);
2177 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2182 if (c->display_usage) {
2184 "net ads keytab flush\n"
2185 " Delete the whole keytab\n");
2189 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2192 ret = ads_keytab_flush(ads);
2197 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2203 if (c->display_usage) {
2205 "net ads keytab add <principal> [principal ...]\n"
2206 " Add principals to local keytab\n"
2207 " principal\tKerberos principal to add to "
2212 d_printf("Processing principals to add...\n");
2213 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2216 for (i = 0; i < argc; i++) {
2217 ret |= ads_keytab_add_entry(ads, argv[i]);
2223 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2228 if (c->display_usage) {
2230 "net ads keytab create\n"
2231 " Create new default keytab\n");
2235 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2238 ret = ads_keytab_create_default(ads);
2243 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2245 const char *keytab = NULL;
2247 if (c->display_usage) {
2249 "net ads keytab list [keytab]\n"
2250 " List a local keytab\n"
2251 " keytab\tKeytab to list\n");
2259 return ads_keytab_list(keytab);
2263 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2265 struct functable func[] = {
2270 "Add a service principal",
2271 "net ads keytab add\n"
2272 " Add a service principal"
2276 net_ads_keytab_create,
2278 "Create a fresh keytab",
2279 "net ads keytab create\n"
2280 " Create a fresh keytab"
2284 net_ads_keytab_flush,
2286 "Remove all keytab entries",
2287 "net ads keytab flush\n"
2288 " Remove all keytab entries"
2292 net_ads_keytab_list,
2295 "net ads keytab list\n"
2298 {NULL, NULL, 0, NULL, NULL}
2301 if (!USE_KERBEROS_KEYTAB) {
2302 d_printf("\nWarning: \"kerberos method\" must be set to a "
2303 "keytab method to use keytab functions.\n");
2306 return net_run_function(c, argc, argv, "net ads keytab", func);
2309 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2313 if (c->display_usage) {
2315 "net ads kerberos renew\n"
2316 " Renew TGT from existing credential cache\n");
2320 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2322 d_printf("failed to renew kerberos ticket: %s\n",
2323 error_message(ret));
2328 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2330 struct PAC_DATA *pac = NULL;
2331 struct PAC_LOGON_INFO *info = NULL;
2332 TALLOC_CTX *mem_ctx = NULL;
2336 if (c->display_usage) {
2338 "net ads kerberos pac\n"
2339 " Dump the Kerberos PAC\n");
2343 mem_ctx = talloc_init("net_ads_kerberos_pac");
2348 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2350 status = kerberos_return_pac(mem_ctx,
2359 2592000, /* one month */
2361 if (!NT_STATUS_IS_OK(status)) {
2362 d_printf("failed to query kerberos PAC: %s\n",
2367 info = get_logon_info_from_pac(pac);
2370 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2371 d_printf("The Pac: %s\n", s);
2376 TALLOC_FREE(mem_ctx);
2380 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2382 TALLOC_CTX *mem_ctx = NULL;
2386 if (c->display_usage) {
2388 "net ads kerberos kinit\n"
2389 " Get Ticket Granting Ticket (TGT) for the user\n");
2393 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2398 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2400 ret = kerberos_kinit_password_ext(c->opt_user_name,
2408 2592000, /* one month */
2411 d_printf("failed to kinit password: %s\n",
2418 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2420 struct functable func[] = {
2423 net_ads_kerberos_kinit,
2425 "Retrieve Ticket Granting Ticket (TGT)",
2426 "net ads kerberos kinit\n"
2427 " Receive Ticket Granting Ticket (TGT)"
2431 net_ads_kerberos_renew,
2433 "Renew Ticket Granting Ticket from credential cache"
2434 "net ads kerberos renew\n"
2435 " Renew Ticket Granting Ticket from credential cache"
2439 net_ads_kerberos_pac,
2441 "Dump Kerberos PAC",
2442 "net ads kerberos pac\n"
2443 " Dump Kerberos PAC"
2445 {NULL, NULL, 0, NULL, NULL}
2448 return net_run_function(c, argc, argv, "net ads kerberos", func);
2451 int net_ads(struct net_context *c, int argc, const char **argv)
2453 struct functable func[] = {
2458 "Display details on remote ADS server",
2460 " Display details on remote ADS server"
2466 "Join the local machine to ADS realm",
2468 " Join the local machine to ADS realm"
2474 "Validate machine account",
2475 "net ads testjoin\n"
2476 " Validate machine account"
2482 "Remove the local machine from ADS",
2484 " Remove the local machine from ADS"
2490 "Display machine account details",
2492 " Display machine account details"
2498 "List/modify users",
2500 " List/modify users"
2506 "List/modify groups",
2508 " List/modify groups"
2514 "Issue dynamic DNS update",
2516 " Issue dynamic DNS update"
2522 "Change user passwords",
2523 "net ads password\n"
2524 " Change user passwords"
2528 net_ads_changetrustpw,
2530 "Change trust account password",
2531 "net ads changetrustpw\n"
2532 " Change trust account password"
2538 "List/modify printer entries",
2540 " List/modify printer entries"
2546 "Issue LDAP search using filter",
2548 " Issue LDAP search using filter"
2554 "Issue LDAP search by DN",
2556 " Issue LDAP search by DN"
2562 "Issue LDAP search by SID",
2564 " Issue LDAP search by SID"
2570 "Display workgroup name",
2571 "net ads workgroup\n"
2572 " Display the workgroup name"
2578 "Perfom CLDAP query on DC",
2580 " Find the ADS DC using CLDAP lookups"
2586 "Manage local keytab file",
2588 " Manage local keytab file"
2594 "Manage group policy objects",
2596 " Manage group policy objects"
2602 "Manage kerberos keytab",
2603 "net ads kerberos\n"
2604 " Manage kerberos keytab"
2606 {NULL, NULL, 0, NULL, NULL}
2609 return net_run_function(c, argc, argv, "net ads", func);
2614 static int net_ads_noads(void)
2616 d_fprintf(stderr, "ADS support not compiled in\n");
2620 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2622 return net_ads_noads();
2625 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2627 return net_ads_noads();
2630 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2632 return net_ads_noads();
2635 int net_ads_join(struct net_context *c, int argc, const char **argv)
2637 return net_ads_noads();
2640 int net_ads_user(struct net_context *c, int argc, const char **argv)
2642 return net_ads_noads();
2645 int net_ads_group(struct net_context *c, int argc, const char **argv)
2647 return net_ads_noads();
2650 /* this one shouldn't display a message */
2651 int net_ads_check(struct net_context *c)
2656 int net_ads_check_our_domain(struct net_context *c)
2661 int net_ads(struct net_context *c, int argc, const char **argv)
2663 return net_ads_noads();
2666 #endif /* WITH_ADS */