net: fix the order of DC lookup methods when joining a domain
[Samba.git] / source3 / utils / net_ads.c
blob28553fcadc87f78f8bd2b81dc7c1dd3396eb526b
1 /*
2 Samba Unix/Linux SMB client library
3 net ads commands
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/>.
23 #include "includes.h"
24 #include "utils/net.h"
25 #include "rpc_client/cli_pipe.h"
26 #include "librpc/gen_ndr/ndr_krb5pac.h"
27 #include "../librpc/gen_ndr/ndr_spoolss.h"
28 #include "nsswitch/libwbclient/wbclient.h"
29 #include "ads.h"
30 #include "libads/cldap.h"
31 #include "../lib/addns/dnsquery.h"
32 #include "../libds/common/flags.h"
33 #include "librpc/gen_ndr/libnet_join.h"
34 #include "libnet/libnet_join.h"
35 #include "smb_krb5.h"
36 #include "secrets.h"
37 #include "krb5_env.h"
38 #include "../libcli/security/security.h"
39 #include "libsmb/libsmb.h"
40 #include "lib/param/loadparm.h"
41 #include "utils/net_dns.h"
43 #ifdef HAVE_ADS
45 /* when we do not have sufficient input parameters to contact a remote domain
46 * we always fall back to our own realm - Guenther*/
48 static const char *assume_own_realm(struct net_context *c)
50 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
51 return lp_realm();
54 return NULL;
58 do a cldap netlogon query
60 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
62 char addr[INET6_ADDRSTRLEN];
63 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
65 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
67 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads->ldap.ss, ads->server.realm, &reply ) ) {
68 d_fprintf(stderr, _("CLDAP query failed!\n"));
69 return -1;
72 d_printf(_("Information for Domain Controller: %s\n\n"),
73 addr);
75 d_printf(_("Response Type: "));
76 switch (reply.command) {
77 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
78 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
79 break;
80 case LOGON_SAM_LOGON_RESPONSE_EX:
81 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
82 break;
83 default:
84 d_printf("0x%x\n", reply.command);
85 break;
88 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
90 d_printf(_("Flags:\n"
91 "\tIs a PDC: %s\n"
92 "\tIs a GC of the forest: %s\n"
93 "\tIs an LDAP server: %s\n"
94 "\tSupports DS: %s\n"
95 "\tIs running a KDC: %s\n"
96 "\tIs running time services: %s\n"
97 "\tIs the closest DC: %s\n"
98 "\tIs writable: %s\n"
99 "\tHas a hardware clock: %s\n"
100 "\tIs a non-domain NC serviced by LDAP server: %s\n"
101 "\tIs NT6 DC that has some secrets: %s\n"
102 "\tIs NT6 DC that has all secrets: %s\n"
103 "\tRuns Active Directory Web Services: %s\n"
104 "\tRuns on Windows 2012 or later: %s\n"),
105 (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
106 (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
107 (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
108 (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
109 (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
110 (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
111 (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
112 (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
113 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
114 (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
115 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
116 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"),
117 (reply.server_type & NBT_SERVER_ADS_WEB_SERVICE) ? _("yes") : _("no"),
118 (reply.server_type & NBT_SERVER_DS_8) ? _("yes") : _("no"));
121 printf(_("Forest:\t\t\t%s\n"), reply.forest);
122 printf(_("Domain:\t\t\t%s\n"), reply.dns_domain);
123 printf(_("Domain Controller:\t%s\n"), reply.pdc_dns_name);
125 printf(_("Pre-Win2k Domain:\t%s\n"), reply.domain_name);
126 printf(_("Pre-Win2k Hostname:\t%s\n"), reply.pdc_name);
128 if (*reply.user_name) printf(_("User name:\t%s\n"), reply.user_name);
130 printf(_("Server Site Name :\t\t%s\n"), reply.server_site);
131 printf(_("Client Site Name :\t\t%s\n"), reply.client_site);
133 d_printf(_("NT Version: %d\n"), reply.nt_version);
134 d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
135 d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
137 return 0;
141 this implements the CLDAP based netlogon lookup requests
142 for finding the domain controller of a ADS domain
144 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
146 ADS_STRUCT *ads;
147 int ret;
149 if (c->display_usage) {
150 d_printf("%s\n"
151 "net ads lookup\n"
152 " %s",
153 _("Usage:"),
154 _("Find the ADS DC using CLDAP lookup.\n"));
155 return 0;
158 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
159 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
160 ads_destroy(&ads);
161 return -1;
164 if (!ads->config.realm) {
165 ads->config.realm = discard_const_p(char, c->opt_target_workgroup);
166 ads->ldap.port = 389;
169 ret = net_ads_cldap_netlogon(c, ads);
170 ads_destroy(&ads);
171 return ret;
176 static int net_ads_info(struct net_context *c, int argc, const char **argv)
178 ADS_STRUCT *ads;
179 char addr[INET6_ADDRSTRLEN];
181 if (c->display_usage) {
182 d_printf("%s\n"
183 "net ads info\n"
184 " %s",
185 _("Usage:"),
186 _("Display information about an Active Directory "
187 "server.\n"));
188 return 0;
191 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
192 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
193 return -1;
196 if (!ads || !ads->config.realm) {
197 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
198 ads_destroy(&ads);
199 return -1;
202 /* Try to set the server's current time since we didn't do a full
203 TCP LDAP session initially */
205 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
206 d_fprintf( stderr, _("Failed to get server's current time!\n"));
209 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
211 d_printf(_("LDAP server: %s\n"), addr);
212 d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
213 d_printf(_("Realm: %s\n"), ads->config.realm);
214 d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
215 d_printf(_("LDAP port: %d\n"), ads->ldap.port);
216 d_printf(_("Server time: %s\n"),
217 http_timestring(talloc_tos(), ads->config.current_time));
219 d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
220 d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
222 ads_destroy(&ads);
223 return 0;
226 static void use_in_memory_ccache(void) {
227 /* Use in-memory credentials cache so we do not interfere with
228 * existing credentials */
229 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
232 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
233 uint32_t auth_flags, ADS_STRUCT **ads_ret)
235 ADS_STRUCT *ads = NULL;
236 ADS_STATUS status;
237 bool need_password = false;
238 bool second_time = false;
239 char *cp;
240 const char *realm = NULL;
241 bool tried_closest_dc = false;
243 /* lp_realm() should be handled by a command line param,
244 However, the join requires that realm be set in smb.conf
245 and compares our realm with the remote server's so this is
246 ok until someone needs more flexibility */
248 *ads_ret = NULL;
250 retry_connect:
251 if (only_own_domain) {
252 realm = lp_realm();
253 } else {
254 realm = assume_own_realm(c);
257 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
259 if (!c->opt_user_name) {
260 c->opt_user_name = "administrator";
263 if (c->opt_user_specified) {
264 need_password = true;
267 retry:
268 if (!c->opt_password && need_password && !c->opt_machine_pass) {
269 c->opt_password = net_prompt_pass(c, c->opt_user_name);
270 if (!c->opt_password) {
271 ads_destroy(&ads);
272 return ADS_ERROR(LDAP_NO_MEMORY);
276 if (c->opt_password) {
277 use_in_memory_ccache();
278 SAFE_FREE(ads->auth.password);
279 ads->auth.password = smb_xstrdup(c->opt_password);
282 ads->auth.flags |= auth_flags;
283 SAFE_FREE(ads->auth.user_name);
284 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
287 * If the username is of the form "name@realm",
288 * extract the realm and convert to upper case.
289 * This is only used to establish the connection.
291 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
292 *cp++ = '\0';
293 SAFE_FREE(ads->auth.realm);
294 ads->auth.realm = smb_xstrdup(cp);
295 if (!strupper_m(ads->auth.realm)) {
296 ads_destroy(&ads);
297 return ADS_ERROR(LDAP_NO_MEMORY);
301 status = ads_connect(ads);
303 if (!ADS_ERR_OK(status)) {
305 if (NT_STATUS_EQUAL(ads_ntstatus(status),
306 NT_STATUS_NO_LOGON_SERVERS)) {
307 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
308 ads_destroy(&ads);
309 return status;
312 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
313 need_password = true;
314 second_time = true;
315 goto retry;
316 } else {
317 ads_destroy(&ads);
318 return status;
322 /* when contacting our own domain, make sure we use the closest DC.
323 * This is done by reconnecting to ADS because only the first call to
324 * ads_connect will give us our own sitename */
326 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
328 tried_closest_dc = true; /* avoid loop */
330 if (!ads_closest_dc(ads)) {
332 namecache_delete(ads->server.realm, 0x1C);
333 namecache_delete(ads->server.workgroup, 0x1C);
335 ads_destroy(&ads);
336 ads = NULL;
338 goto retry_connect;
342 *ads_ret = ads;
343 return status;
346 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
348 return ads_startup_int(c, only_own_domain, 0, ads);
351 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
353 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
357 Check to see if connection can be made via ads.
358 ads_startup() stores the password in opt_password if it needs to so
359 that rpc or rap can use it without re-prompting.
361 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
363 ADS_STRUCT *ads;
364 ADS_STATUS status;
366 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
367 return -1;
370 ads->auth.flags |= ADS_AUTH_NO_BIND;
372 status = ads_connect(ads);
373 if ( !ADS_ERR_OK(status) ) {
374 return -1;
377 ads_destroy(&ads);
378 return 0;
381 int net_ads_check_our_domain(struct net_context *c)
383 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
386 int net_ads_check(struct net_context *c)
388 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
392 determine the netbios workgroup name for a domain
394 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
396 ADS_STRUCT *ads;
397 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
399 if (c->display_usage) {
400 d_printf ("%s\n"
401 "net ads workgroup\n"
402 " %s\n",
403 _("Usage:"),
404 _("Print the workgroup name"));
405 return 0;
408 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
409 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
410 return -1;
413 if (!ads->config.realm) {
414 ads->config.realm = discard_const_p(char, c->opt_target_workgroup);
415 ads->ldap.port = 389;
418 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads->ldap.ss, ads->server.realm, &reply ) ) {
419 d_fprintf(stderr, _("CLDAP query failed!\n"));
420 ads_destroy(&ads);
421 return -1;
424 d_printf(_("Workgroup: %s\n"), reply.domain_name);
426 ads_destroy(&ads);
428 return 0;
433 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
435 char **disp_fields = (char **) data_area;
437 if (!field) { /* must be end of record */
438 if (disp_fields[0]) {
439 if (!strchr_m(disp_fields[0], '$')) {
440 if (disp_fields[1])
441 d_printf("%-21.21s %s\n",
442 disp_fields[0], disp_fields[1]);
443 else
444 d_printf("%s\n", disp_fields[0]);
447 SAFE_FREE(disp_fields[0]);
448 SAFE_FREE(disp_fields[1]);
449 return true;
451 if (!values) /* must be new field, indicate string field */
452 return true;
453 if (strcasecmp_m(field, "sAMAccountName") == 0) {
454 disp_fields[0] = SMB_STRDUP((char *) values[0]);
456 if (strcasecmp_m(field, "description") == 0)
457 disp_fields[1] = SMB_STRDUP((char *) values[0]);
458 return true;
461 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
463 return net_user_usage(c, argc, argv);
466 static int ads_user_add(struct net_context *c, int argc, const char **argv)
468 ADS_STRUCT *ads;
469 ADS_STATUS status;
470 char *upn, *userdn;
471 LDAPMessage *res=NULL;
472 int rc = -1;
473 char *ou_str = NULL;
475 if (argc < 1 || c->display_usage)
476 return net_ads_user_usage(c, argc, argv);
478 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
479 return -1;
482 status = ads_find_user_acct(ads, &res, argv[0]);
484 if (!ADS_ERR_OK(status)) {
485 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
486 goto done;
489 if (ads_count_replies(ads, res)) {
490 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
491 argv[0]);
492 goto done;
495 if (c->opt_container) {
496 ou_str = SMB_STRDUP(c->opt_container);
497 } else {
498 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
501 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
503 if (!ADS_ERR_OK(status)) {
504 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
505 ads_errstr(status));
506 goto done;
509 /* if no password is to be set, we're done */
510 if (argc == 1) {
511 d_printf(_("User %s added\n"), argv[0]);
512 rc = 0;
513 goto done;
516 /* try setting the password */
517 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
518 goto done;
520 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
521 ads->auth.time_offset);
522 SAFE_FREE(upn);
523 if (ADS_ERR_OK(status)) {
524 d_printf(_("User %s added\n"), argv[0]);
525 rc = 0;
526 goto done;
529 /* password didn't set, delete account */
530 d_fprintf(stderr, _("Could not add user %s. "
531 "Error setting password %s\n"),
532 argv[0], ads_errstr(status));
533 ads_msgfree(ads, res);
534 status=ads_find_user_acct(ads, &res, argv[0]);
535 if (ADS_ERR_OK(status)) {
536 userdn = ads_get_dn(ads, talloc_tos(), res);
537 ads_del_dn(ads, userdn);
538 TALLOC_FREE(userdn);
541 done:
542 if (res)
543 ads_msgfree(ads, res);
544 ads_destroy(&ads);
545 SAFE_FREE(ou_str);
546 return rc;
549 static int ads_user_info(struct net_context *c, int argc, const char **argv)
551 ADS_STRUCT *ads = NULL;
552 ADS_STATUS rc;
553 LDAPMessage *res = NULL;
554 TALLOC_CTX *frame;
555 int ret = 0;
556 wbcErr wbc_status;
557 const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
558 char *searchstring=NULL;
559 char **grouplist;
560 char *primary_group;
561 char *escaped_user;
562 struct dom_sid primary_group_sid;
563 uint32_t group_rid;
564 enum wbcSidType type;
566 if (argc < 1 || c->display_usage) {
567 return net_ads_user_usage(c, argc, argv);
570 frame = talloc_new(talloc_tos());
571 if (frame == NULL) {
572 return -1;
575 escaped_user = escape_ldap_string(frame, argv[0]);
576 if (!escaped_user) {
577 d_fprintf(stderr,
578 _("ads_user_info: failed to escape user %s\n"),
579 argv[0]);
580 return -1;
583 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
584 ret = -1;
585 goto error;
588 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
589 ret =-1;
590 goto error;
592 rc = ads_search(ads, &res, searchstring, attrs);
593 SAFE_FREE(searchstring);
595 if (!ADS_ERR_OK(rc)) {
596 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(rc));
597 ret = -1;
598 goto error;
601 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
602 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
603 ret = -1;
604 goto error;
607 rc = ads_domain_sid(ads, &primary_group_sid);
608 if (!ADS_ERR_OK(rc)) {
609 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(rc));
610 ret = -1;
611 goto error;
614 sid_append_rid(&primary_group_sid, group_rid);
616 wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
617 NULL, /* don't look up domain */
618 &primary_group,
619 &type);
620 if (!WBC_ERROR_IS_OK(wbc_status)) {
621 d_fprintf(stderr, "wbcLookupSid: %s\n",
622 wbcErrorString(wbc_status));
623 ret = -1;
624 goto error;
627 d_printf("%s\n", primary_group);
629 wbcFreeMemory(primary_group);
631 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
632 (LDAPMessage *)res, "memberOf");
634 if (grouplist) {
635 int i;
636 char **groupname;
637 for (i=0;grouplist[i];i++) {
638 groupname = ldap_explode_dn(grouplist[i], 1);
639 d_printf("%s\n", groupname[0]);
640 ldap_value_free(groupname);
642 ldap_value_free(grouplist);
645 error:
646 if (res) ads_msgfree(ads, res);
647 if (ads) ads_destroy(&ads);
648 TALLOC_FREE(frame);
649 return ret;
652 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
654 ADS_STRUCT *ads;
655 ADS_STATUS rc;
656 LDAPMessage *res = NULL;
657 char *userdn;
659 if (argc < 1) {
660 return net_ads_user_usage(c, argc, argv);
663 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
664 return -1;
667 rc = ads_find_user_acct(ads, &res, argv[0]);
668 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
669 d_printf(_("User %s does not exist.\n"), argv[0]);
670 ads_msgfree(ads, res);
671 ads_destroy(&ads);
672 return -1;
674 userdn = ads_get_dn(ads, talloc_tos(), res);
675 ads_msgfree(ads, res);
676 rc = ads_del_dn(ads, userdn);
677 TALLOC_FREE(userdn);
678 if (ADS_ERR_OK(rc)) {
679 d_printf(_("User %s deleted\n"), argv[0]);
680 ads_destroy(&ads);
681 return 0;
683 d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
684 ads_errstr(rc));
685 ads_destroy(&ads);
686 return -1;
689 int net_ads_user(struct net_context *c, int argc, const char **argv)
691 struct functable func[] = {
693 "add",
694 ads_user_add,
695 NET_TRANSPORT_ADS,
696 N_("Add an AD user"),
697 N_("net ads user add\n"
698 " Add an AD user")
701 "info",
702 ads_user_info,
703 NET_TRANSPORT_ADS,
704 N_("Display information about an AD user"),
705 N_("net ads user info\n"
706 " Display information about an AD user")
709 "delete",
710 ads_user_delete,
711 NET_TRANSPORT_ADS,
712 N_("Delete an AD user"),
713 N_("net ads user delete\n"
714 " Delete an AD user")
716 {NULL, NULL, 0, NULL, NULL}
718 ADS_STRUCT *ads;
719 ADS_STATUS rc;
720 const char *shortattrs[] = {"sAMAccountName", NULL};
721 const char *longattrs[] = {"sAMAccountName", "description", NULL};
722 char *disp_fields[2] = {NULL, NULL};
724 if (argc == 0) {
725 if (c->display_usage) {
726 d_printf( "%s\n"
727 "net ads user\n"
728 " %s\n",
729 _("Usage:"),
730 _("List AD users"));
731 net_display_usage_from_functable(func);
732 return 0;
735 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
736 return -1;
739 if (c->opt_long_list_entries)
740 d_printf(_("\nUser name Comment"
741 "\n-----------------------------\n"));
743 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
744 LDAP_SCOPE_SUBTREE,
745 "(objectCategory=user)",
746 c->opt_long_list_entries ? longattrs :
747 shortattrs, usergrp_display,
748 disp_fields);
749 ads_destroy(&ads);
750 return ADS_ERR_OK(rc) ? 0 : -1;
753 return net_run_function(c, argc, argv, "net ads user", func);
756 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
758 return net_group_usage(c, argc, argv);
761 static int ads_group_add(struct net_context *c, int argc, const char **argv)
763 ADS_STRUCT *ads;
764 ADS_STATUS status;
765 LDAPMessage *res=NULL;
766 int rc = -1;
767 char *ou_str = NULL;
769 if (argc < 1 || c->display_usage) {
770 return net_ads_group_usage(c, argc, argv);
773 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
774 return -1;
777 status = ads_find_user_acct(ads, &res, argv[0]);
779 if (!ADS_ERR_OK(status)) {
780 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
781 goto done;
784 if (ads_count_replies(ads, res)) {
785 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
786 goto done;
789 if (c->opt_container) {
790 ou_str = SMB_STRDUP(c->opt_container);
791 } else {
792 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
795 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
797 if (ADS_ERR_OK(status)) {
798 d_printf(_("Group %s added\n"), argv[0]);
799 rc = 0;
800 } else {
801 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
802 ads_errstr(status));
805 done:
806 if (res)
807 ads_msgfree(ads, res);
808 ads_destroy(&ads);
809 SAFE_FREE(ou_str);
810 return rc;
813 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
815 ADS_STRUCT *ads;
816 ADS_STATUS rc;
817 LDAPMessage *res = NULL;
818 char *groupdn;
820 if (argc < 1 || c->display_usage) {
821 return net_ads_group_usage(c, argc, argv);
824 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
825 return -1;
828 rc = ads_find_user_acct(ads, &res, argv[0]);
829 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
830 d_printf(_("Group %s does not exist.\n"), argv[0]);
831 ads_msgfree(ads, res);
832 ads_destroy(&ads);
833 return -1;
835 groupdn = ads_get_dn(ads, talloc_tos(), res);
836 ads_msgfree(ads, res);
837 rc = ads_del_dn(ads, groupdn);
838 TALLOC_FREE(groupdn);
839 if (ADS_ERR_OK(rc)) {
840 d_printf(_("Group %s deleted\n"), argv[0]);
841 ads_destroy(&ads);
842 return 0;
844 d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
845 ads_errstr(rc));
846 ads_destroy(&ads);
847 return -1;
850 int net_ads_group(struct net_context *c, int argc, const char **argv)
852 struct functable func[] = {
854 "add",
855 ads_group_add,
856 NET_TRANSPORT_ADS,
857 N_("Add an AD group"),
858 N_("net ads group add\n"
859 " Add an AD group")
862 "delete",
863 ads_group_delete,
864 NET_TRANSPORT_ADS,
865 N_("Delete an AD group"),
866 N_("net ads group delete\n"
867 " Delete an AD group")
869 {NULL, NULL, 0, NULL, NULL}
871 ADS_STRUCT *ads;
872 ADS_STATUS rc;
873 const char *shortattrs[] = {"sAMAccountName", NULL};
874 const char *longattrs[] = {"sAMAccountName", "description", NULL};
875 char *disp_fields[2] = {NULL, NULL};
877 if (argc == 0) {
878 if (c->display_usage) {
879 d_printf( "%s\n"
880 "net ads group\n"
881 " %s\n",
882 _("Usage:"),
883 _("List AD groups"));
884 net_display_usage_from_functable(func);
885 return 0;
888 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
889 return -1;
892 if (c->opt_long_list_entries)
893 d_printf(_("\nGroup name Comment"
894 "\n-----------------------------\n"));
895 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
896 LDAP_SCOPE_SUBTREE,
897 "(objectCategory=group)",
898 c->opt_long_list_entries ? longattrs :
899 shortattrs, usergrp_display,
900 disp_fields);
902 ads_destroy(&ads);
903 return ADS_ERR_OK(rc) ? 0 : -1;
905 return net_run_function(c, argc, argv, "net ads group", func);
908 static int net_ads_status(struct net_context *c, int argc, const char **argv)
910 ADS_STRUCT *ads;
911 ADS_STATUS rc;
912 LDAPMessage *res;
914 if (c->display_usage) {
915 d_printf( "%s\n"
916 "net ads status\n"
917 " %s\n",
918 _("Usage:"),
919 _("Display machine account details"));
920 return 0;
923 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
924 return -1;
927 rc = ads_find_machine_acct(ads, &res, lp_netbios_name());
928 if (!ADS_ERR_OK(rc)) {
929 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
930 ads_destroy(&ads);
931 return -1;
934 if (ads_count_replies(ads, res) == 0) {
935 d_fprintf(stderr, _("No machine account for '%s' found\n"), lp_netbios_name());
936 ads_destroy(&ads);
937 return -1;
940 ads_dump(ads, res);
941 ads_destroy(&ads);
942 return 0;
945 /*******************************************************************
946 Leave an AD domain. Windows XP disables the machine account.
947 We'll try the same. The old code would do an LDAP delete.
948 That only worked using the machine creds because added the machine
949 with full control to the computer object's ACL.
950 *******************************************************************/
952 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
954 TALLOC_CTX *ctx;
955 struct libnet_UnjoinCtx *r = NULL;
956 WERROR werr;
958 if (c->display_usage) {
959 d_printf( "%s\n"
960 "net ads leave\n"
961 " %s\n",
962 _("Usage:"),
963 _("Leave an AD domain"));
964 return 0;
967 if (!*lp_realm()) {
968 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
969 return -1;
972 if (!(ctx = talloc_init("net_ads_leave"))) {
973 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
974 return -1;
977 if (!c->opt_kerberos) {
978 use_in_memory_ccache();
981 if (!c->msg_ctx) {
982 d_fprintf(stderr, _("Could not initialise message context. "
983 "Try running as root\n"));
984 return -1;
987 werr = libnet_init_UnjoinCtx(ctx, &r);
988 if (!W_ERROR_IS_OK(werr)) {
989 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
990 return -1;
993 r->in.debug = true;
994 r->in.use_kerberos = c->opt_kerberos;
995 r->in.dc_name = c->opt_host;
996 r->in.domain_name = lp_realm();
997 r->in.admin_account = c->opt_user_name;
998 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
999 r->in.modify_config = lp_config_backend_is_registry();
1001 /* Try to delete it, but if that fails, disable it. The
1002 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
1003 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1004 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
1005 r->in.delete_machine_account = true;
1006 r->in.msg_ctx = c->msg_ctx;
1008 werr = libnet_Unjoin(ctx, r);
1009 if (!W_ERROR_IS_OK(werr)) {
1010 d_printf(_("Failed to leave domain: %s\n"),
1011 r->out.error_string ? r->out.error_string :
1012 get_friendly_werror_msg(werr));
1013 goto done;
1016 if (r->out.deleted_machine_account) {
1017 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1018 r->in.machine_name, r->out.dns_domain_name);
1019 goto done;
1022 /* We couldn't delete it - see if the disable succeeded. */
1023 if (r->out.disabled_machine_account) {
1024 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1025 r->in.machine_name, r->out.dns_domain_name);
1026 werr = WERR_OK;
1027 goto done;
1030 /* Based on what we requested, we shouldn't get here, but if
1031 we did, it means the secrets were removed, and therefore
1032 we have left the domain */
1033 d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1034 r->in.machine_name, r->out.dns_domain_name);
1036 done:
1037 TALLOC_FREE(r);
1038 TALLOC_FREE(ctx);
1040 if (W_ERROR_IS_OK(werr)) {
1041 return 0;
1044 return -1;
1047 static NTSTATUS net_ads_join_ok(struct net_context *c)
1049 ADS_STRUCT *ads = NULL;
1050 ADS_STATUS status;
1051 fstring dc_name;
1052 struct sockaddr_storage dcip;
1054 if (!secrets_init()) {
1055 DEBUG(1,("Failed to initialise secrets database\n"));
1056 return NT_STATUS_ACCESS_DENIED;
1059 net_use_krb_machine_account(c);
1061 get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1063 status = ads_startup(c, true, &ads);
1064 if (!ADS_ERR_OK(status)) {
1065 return ads_ntstatus(status);
1068 ads_destroy(&ads);
1069 return NT_STATUS_OK;
1073 check that an existing join is OK
1075 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1077 NTSTATUS status;
1078 use_in_memory_ccache();
1080 if (c->display_usage) {
1081 d_printf( "%s\n"
1082 "net ads testjoin\n"
1083 " %s\n",
1084 _("Usage:"),
1085 _("Test if the existing join is ok"));
1086 return 0;
1089 /* Display success or failure */
1090 status = net_ads_join_ok(c);
1091 if (!NT_STATUS_IS_OK(status)) {
1092 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1093 get_friendly_nt_error_msg(status));
1094 return -1;
1097 printf(_("Join is OK\n"));
1098 return 0;
1101 /*******************************************************************
1102 Simple configu checks before beginning the join
1103 ********************************************************************/
1105 static WERROR check_ads_config( void )
1107 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1108 d_printf(_("Host is not configured as a member server.\n"));
1109 return WERR_INVALID_DOMAIN_ROLE;
1112 if (strlen(lp_netbios_name()) > 15) {
1113 d_printf(_("Our netbios name can be at most 15 chars long, "
1114 "\"%s\" is %u chars long\n"), lp_netbios_name(),
1115 (unsigned int)strlen(lp_netbios_name()));
1116 return WERR_INVALID_COMPUTERNAME;
1119 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1120 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1121 "join to succeed.\n"), get_dyn_CONFIGFILE());
1122 return WERR_INVALID_PARAM;
1125 return WERR_OK;
1128 /*******************************************************************
1129 Send a DNS update request
1130 *******************************************************************/
1132 #if defined(WITH_DNS_UPDATES)
1133 #include "../lib/addns/dns.h"
1135 static NTSTATUS net_update_dns_internal(struct net_context *c,
1136 TALLOC_CTX *ctx, ADS_STRUCT *ads,
1137 const char *machine_name,
1138 const struct sockaddr_storage *addrs,
1139 int num_addrs)
1141 struct dns_rr_ns *nameservers = NULL;
1142 int ns_count = 0, i;
1143 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1144 DNS_ERROR dns_err;
1145 fstring dns_server;
1146 const char *dnsdomain = NULL;
1147 char *root_domain = NULL;
1149 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1150 d_printf(_("No DNS domain configured for %s. "
1151 "Unable to perform DNS Update.\n"), machine_name);
1152 status = NT_STATUS_INVALID_PARAMETER;
1153 goto done;
1155 dnsdomain++;
1157 status = ads_dns_lookup_ns(ctx,
1158 dnsdomain,
1159 &nameservers,
1160 &ns_count);
1161 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1162 /* Child domains often do not have NS records. Look
1163 for the NS record for the forest root domain
1164 (rootDomainNamingContext in therootDSE) */
1166 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1167 LDAPMessage *msg = NULL;
1168 char *root_dn;
1169 ADS_STATUS ads_status;
1171 if ( !ads->ldap.ld ) {
1172 ads_status = ads_connect( ads );
1173 if ( !ADS_ERR_OK(ads_status) ) {
1174 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1175 goto done;
1179 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1180 "(objectclass=*)", rootname_attrs, &msg);
1181 if (!ADS_ERR_OK(ads_status)) {
1182 goto done;
1185 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1186 if ( !root_dn ) {
1187 ads_msgfree( ads, msg );
1188 goto done;
1191 root_domain = ads_build_domain( root_dn );
1193 /* cleanup */
1194 ads_msgfree( ads, msg );
1196 /* try again for NS servers */
1198 status = ads_dns_lookup_ns(ctx,
1199 root_domain,
1200 &nameservers,
1201 &ns_count);
1203 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1204 DEBUG(3,("net_update_dns_internal: Failed to find name server for the %s "
1205 "realm\n", ads->config.realm));
1206 goto done;
1209 dnsdomain = root_domain;
1213 for (i=0; i < ns_count; i++) {
1215 uint32_t flags = DNS_UPDATE_SIGNED |
1216 DNS_UPDATE_UNSIGNED |
1217 DNS_UPDATE_UNSIGNED_SUFFICIENT |
1218 DNS_UPDATE_PROBE |
1219 DNS_UPDATE_PROBE_SUFFICIENT;
1221 if (c->opt_force) {
1222 flags &= ~DNS_UPDATE_PROBE_SUFFICIENT;
1223 flags &= ~DNS_UPDATE_UNSIGNED_SUFFICIENT;
1226 status = NT_STATUS_UNSUCCESSFUL;
1228 /* Now perform the dns update - we'll try non-secure and if we fail,
1229 we'll follow it up with a secure update */
1231 fstrcpy( dns_server, nameservers[i].hostname );
1233 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs, flags);
1234 if (ERR_DNS_IS_OK(dns_err)) {
1235 status = NT_STATUS_OK;
1236 goto done;
1239 if (ERR_DNS_EQUAL(dns_err, ERROR_DNS_INVALID_NAME_SERVER) ||
1240 ERR_DNS_EQUAL(dns_err, ERROR_DNS_CONNECTION_FAILED) ||
1241 ERR_DNS_EQUAL(dns_err, ERROR_DNS_SOCKET_ERROR)) {
1242 DEBUG(1,("retrying DNS update with next nameserver after receiving %s\n",
1243 dns_errstr(dns_err)));
1244 continue;
1247 d_printf(_("DNS Update for %s failed: %s\n"),
1248 machine_name, dns_errstr(dns_err));
1249 status = NT_STATUS_UNSUCCESSFUL;
1250 goto done;
1253 done:
1255 SAFE_FREE( root_domain );
1257 return status;
1260 static NTSTATUS net_update_dns_ext(struct net_context *c,
1261 TALLOC_CTX *mem_ctx, ADS_STRUCT *ads,
1262 const char *hostname,
1263 struct sockaddr_storage *iplist,
1264 int num_addrs)
1266 struct sockaddr_storage *iplist_alloc = NULL;
1267 fstring machine_name;
1268 NTSTATUS status;
1270 if (hostname) {
1271 fstrcpy(machine_name, hostname);
1272 } else {
1273 name_to_fqdn( machine_name, lp_netbios_name() );
1275 if (!strlower_m( machine_name )) {
1276 return NT_STATUS_INVALID_PARAMETER;
1279 if (num_addrs == 0 || iplist == NULL) {
1281 * Get our ip address
1282 * (not the 127.0.0.x address but a real ip address)
1284 num_addrs = get_my_ip_address(&iplist_alloc);
1285 if ( num_addrs <= 0 ) {
1286 DEBUG(4, ("net_update_dns_ext: Failed to find my "
1287 "non-loopback IP addresses!\n"));
1288 return NT_STATUS_INVALID_PARAMETER;
1290 iplist = iplist_alloc;
1293 status = net_update_dns_internal(c, mem_ctx, ads, machine_name,
1294 iplist, num_addrs);
1296 SAFE_FREE(iplist_alloc);
1297 return status;
1300 static NTSTATUS net_update_dns(struct net_context *c, TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, const char *hostname)
1302 NTSTATUS status;
1304 status = net_update_dns_ext(c, mem_ctx, ads, hostname, NULL, 0);
1305 return status;
1307 #endif
1310 /*******************************************************************
1311 ********************************************************************/
1313 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1315 d_printf(_("net ads join [options]\n"
1316 "Valid options:\n"));
1317 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1318 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1319 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1320 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1321 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1322 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1323 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1324 d_printf(_(" machinepass=PASS Set the machine password to a specific value during the join.\n"
1325 " The deault password is random.\n"));
1326 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1327 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1328 " NB: osName and osVer must be specified together for either to take effect.\n"
1329 " Also, the operatingSystemService attribute is also set when along with\n"
1330 " the two other attributes.\n"));
1332 d_printf(_(" osServicePack=string Set the operatingSystemServicePack "
1333 "attribute during the join. Note: if not specified then by "
1334 "default the samba version string is used instead.\n"));
1335 return -1;
1339 static void _net_ads_join_dns_updates(struct net_context *c, TALLOC_CTX *ctx, struct libnet_JoinCtx *r)
1341 #if defined(WITH_DNS_UPDATES)
1342 ADS_STRUCT *ads_dns = NULL;
1343 int ret;
1344 NTSTATUS status;
1347 * In a clustered environment, don't do dynamic dns updates:
1348 * Registering the set of ip addresses that are assigned to
1349 * the interfaces of the node that performs the join does usually
1350 * not have the desired effect, since the local interfaces do not
1351 * carry the complete set of the cluster's public IP addresses.
1352 * And it can also contain internal addresses that should not
1353 * be visible to the outside at all.
1354 * In order to do dns updates in a clustererd setup, use
1355 * net ads dns register.
1357 if (lp_clustering()) {
1358 d_fprintf(stderr, _("Not doing automatic DNS update in a "
1359 "clustered setup.\n"));
1360 return;
1363 if (!r->out.domain_is_ad) {
1364 return;
1368 * We enter this block with user creds.
1369 * kinit with the machine password to do dns update.
1372 ads_dns = ads_init(lp_realm(), NULL, r->in.dc_name);
1374 if (ads_dns == NULL) {
1375 d_fprintf(stderr, _("DNS update failed: out of memory!\n"));
1376 goto done;
1379 use_in_memory_ccache();
1381 ret = asprintf(&ads_dns->auth.user_name, "%s$", lp_netbios_name());
1382 if (ret == -1) {
1383 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1384 goto done;
1387 ads_dns->auth.password = secrets_fetch_machine_password(
1388 r->out.netbios_domain_name, NULL, NULL);
1389 if (ads_dns->auth.password == NULL) {
1390 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1391 goto done;
1394 ads_dns->auth.realm = SMB_STRDUP(r->out.dns_domain_name);
1395 if (ads_dns->auth.realm == NULL) {
1396 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1397 goto done;
1400 if (!strupper_m(ads_dns->auth.realm)) {
1401 d_fprintf(stderr, _("strupper_m %s failed\n"), ads_dns->auth.realm);
1402 goto done;
1405 ret = ads_kinit_password(ads_dns);
1406 if (ret != 0) {
1407 d_fprintf(stderr,
1408 _("DNS update failed: kinit failed: %s\n"),
1409 error_message(ret));
1410 goto done;
1413 status = net_update_dns(c, ctx, ads_dns, NULL);
1414 if (!NT_STATUS_IS_OK(status)) {
1415 d_fprintf( stderr, _("DNS update failed: %s\n"),
1416 nt_errstr(status));
1419 done:
1420 ads_destroy(&ads_dns);
1421 #endif
1423 return;
1427 int net_ads_join(struct net_context *c, int argc, const char **argv)
1429 TALLOC_CTX *ctx = NULL;
1430 struct libnet_JoinCtx *r = NULL;
1431 const char *domain = lp_realm();
1432 WERROR werr = WERR_SETUP_NOT_JOINED;
1433 bool createupn = false;
1434 const char *machineupn = NULL;
1435 const char *machine_password = NULL;
1436 const char *create_in_ou = NULL;
1437 int i;
1438 const char *os_name = NULL;
1439 const char *os_version = NULL;
1440 const char *os_servicepack = NULL;
1441 bool modify_config = lp_config_backend_is_registry();
1442 enum libnetjoin_JoinDomNameType domain_name_type = JoinDomNameTypeDNS;
1444 if (c->display_usage)
1445 return net_ads_join_usage(c, argc, argv);
1447 if (!modify_config) {
1449 werr = check_ads_config();
1450 if (!W_ERROR_IS_OK(werr)) {
1451 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1452 goto fail;
1456 if (!(ctx = talloc_init("net_ads_join"))) {
1457 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1458 werr = WERR_NOMEM;
1459 goto fail;
1462 if (!c->opt_kerberos) {
1463 use_in_memory_ccache();
1466 werr = libnet_init_JoinCtx(ctx, &r);
1467 if (!W_ERROR_IS_OK(werr)) {
1468 goto fail;
1471 /* process additional command line args */
1473 for ( i=0; i<argc; i++ ) {
1474 if ( !strncasecmp_m(argv[i], "createupn", strlen("createupn")) ) {
1475 createupn = true;
1476 machineupn = get_string_param(argv[i]);
1478 else if ( !strncasecmp_m(argv[i], "createcomputer", strlen("createcomputer")) ) {
1479 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1480 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1481 werr = WERR_INVALID_PARAM;
1482 goto fail;
1485 else if ( !strncasecmp_m(argv[i], "osName", strlen("osName")) ) {
1486 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1487 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1488 werr = WERR_INVALID_PARAM;
1489 goto fail;
1492 else if ( !strncasecmp_m(argv[i], "osVer", strlen("osVer")) ) {
1493 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1494 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1495 werr = WERR_INVALID_PARAM;
1496 goto fail;
1499 else if ( !strncasecmp_m(argv[i], "osServicePack", strlen("osServicePack")) ) {
1500 if ( (os_servicepack = get_string_param(argv[i])) == NULL ) {
1501 d_fprintf(stderr, _("Please supply a valid servicepack identifier.\n"));
1502 werr = WERR_INVALID_PARAM;
1503 goto fail;
1506 else if ( !strncasecmp_m(argv[i], "machinepass", strlen("machinepass")) ) {
1507 if ( (machine_password = get_string_param(argv[i])) == NULL ) {
1508 d_fprintf(stderr, _("Please supply a valid password to set as trust account password.\n"));
1509 werr = WERR_INVALID_PARAM;
1510 goto fail;
1513 else {
1514 domain = argv[i];
1515 if (strchr(domain, '.') == NULL) {
1516 domain_name_type = JoinDomNameTypeUnknown;
1517 } else {
1518 domain_name_type = JoinDomNameTypeDNS;
1523 if (!*domain) {
1524 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1525 werr = WERR_INVALID_PARAM;
1526 goto fail;
1529 if (!c->msg_ctx) {
1530 d_fprintf(stderr, _("Could not initialise message context. "
1531 "Try running as root\n"));
1532 werr = WERR_ACCESS_DENIED;
1533 goto fail;
1536 /* Do the domain join here */
1538 r->in.domain_name = domain;
1539 r->in.domain_name_type = domain_name_type;
1540 r->in.create_upn = createupn;
1541 r->in.upn = machineupn;
1542 r->in.account_ou = create_in_ou;
1543 r->in.os_name = os_name;
1544 r->in.os_version = os_version;
1545 r->in.os_servicepack = os_servicepack;
1546 r->in.dc_name = c->opt_host;
1547 r->in.admin_account = c->opt_user_name;
1548 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1549 r->in.machine_password = machine_password;
1550 r->in.debug = true;
1551 r->in.use_kerberos = c->opt_kerberos;
1552 r->in.modify_config = modify_config;
1553 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1554 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1555 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1556 r->in.msg_ctx = c->msg_ctx;
1558 werr = libnet_Join(ctx, r);
1559 if (W_ERROR_EQUAL(werr, WERR_DCNOTFOUND) &&
1560 strequal(domain, lp_realm())) {
1561 r->in.domain_name = lp_workgroup();
1562 r->in.domain_name_type = JoinDomNameTypeNBT;
1563 werr = libnet_Join(ctx, r);
1565 if (!W_ERROR_IS_OK(werr)) {
1566 goto fail;
1569 /* Check the short name of the domain */
1571 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1572 d_printf(_("The workgroup in %s does not match the short\n"
1573 "domain name obtained from the server.\n"
1574 "Using the name [%s] from the server.\n"
1575 "You should set \"workgroup = %s\" in %s.\n"),
1576 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1577 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1580 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1582 if (r->out.dns_domain_name) {
1583 d_printf(_("Joined '%s' to dns domain '%s'\n"), r->in.machine_name,
1584 r->out.dns_domain_name);
1585 } else {
1586 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1587 r->out.netbios_domain_name);
1591 * We try doing the dns update (if it was compiled in).
1592 * If the dns update fails, we still consider the join
1593 * operation as succeeded if we came this far.
1595 _net_ads_join_dns_updates(c, ctx, r);
1597 TALLOC_FREE(r);
1598 TALLOC_FREE( ctx );
1600 return 0;
1602 fail:
1603 /* issue an overall failure message at the end. */
1604 d_printf(_("Failed to join domain: %s\n"),
1605 r && r->out.error_string ? r->out.error_string :
1606 get_friendly_werror_msg(werr));
1607 TALLOC_FREE( ctx );
1609 return -1;
1612 /*******************************************************************
1613 ********************************************************************/
1615 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1617 #if defined(WITH_DNS_UPDATES)
1618 ADS_STRUCT *ads;
1619 ADS_STATUS status;
1620 NTSTATUS ntstatus;
1621 TALLOC_CTX *ctx;
1622 const char *hostname = NULL;
1623 const char **addrs_list = NULL;
1624 struct sockaddr_storage *addrs = NULL;
1625 int num_addrs = 0;
1626 int count;
1628 #ifdef DEVELOPER
1629 talloc_enable_leak_report();
1630 #endif
1632 if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
1633 d_fprintf(stderr, _("Refusing DNS updates with automatic "
1634 "detection of addresses in a clustered "
1635 "setup.\n"));
1636 c->display_usage = true;
1639 if (c->display_usage) {
1640 d_printf( "%s\n"
1641 "net ads dns register [hostname [IP [IP...]]]\n"
1642 " %s\n",
1643 _("Usage:"),
1644 _("Register hostname with DNS\n"));
1645 return -1;
1648 if (!(ctx = talloc_init("net_ads_dns"))) {
1649 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1650 return -1;
1653 if (argc >= 1) {
1654 hostname = argv[0];
1657 if (argc > 1) {
1658 num_addrs = argc - 1;
1659 addrs_list = &argv[1];
1660 } else if (lp_clustering()) {
1661 addrs_list = lp_cluster_addresses();
1662 num_addrs = str_list_length(addrs_list);
1665 if (num_addrs > 0) {
1666 addrs = talloc_zero_array(ctx, struct sockaddr_storage, num_addrs);
1667 if (addrs == NULL) {
1668 d_fprintf(stderr, _("Error allocating memory!\n"));
1669 talloc_free(ctx);
1670 return -1;
1674 for (count = 0; count < num_addrs; count++) {
1675 if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
1676 d_fprintf(stderr, "%s '%s'.\n",
1677 _("Cannot interpret address"),
1678 addrs_list[count]);
1679 talloc_free(ctx);
1680 return -1;
1684 status = ads_startup(c, true, &ads);
1685 if ( !ADS_ERR_OK(status) ) {
1686 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1687 TALLOC_FREE(ctx);
1688 return -1;
1691 ntstatus = net_update_dns_ext(c, ctx, ads, hostname, addrs, num_addrs);
1692 if (!NT_STATUS_IS_OK(ntstatus)) {
1693 d_fprintf( stderr, _("DNS update failed!\n") );
1694 ads_destroy( &ads );
1695 TALLOC_FREE( ctx );
1696 return -1;
1699 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1701 ads_destroy(&ads);
1702 TALLOC_FREE( ctx );
1704 return 0;
1705 #else
1706 d_fprintf(stderr,
1707 _("DNS update support not enabled at compile time!\n"));
1708 return -1;
1709 #endif
1712 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1714 #if defined(WITH_DNS_UPDATES)
1715 DNS_ERROR err;
1717 #ifdef DEVELOPER
1718 talloc_enable_leak_report();
1719 #endif
1721 if (argc != 2 || c->display_usage) {
1722 d_printf( "%s\n"
1723 " %s\n"
1724 " %s\n",
1725 _("Usage:"),
1726 _("net ads dns gethostbyname <server> <name>\n"),
1727 _(" Look up hostname from the AD\n"
1728 " server\tName server to use\n"
1729 " name\tName to look up\n"));
1730 return -1;
1733 err = do_gethostbyname(argv[0], argv[1]);
1735 d_printf(_("do_gethostbyname returned %s (%d)\n"),
1736 dns_errstr(err), ERROR_DNS_V(err));
1737 #endif
1738 return 0;
1741 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1743 struct functable func[] = {
1745 "register",
1746 net_ads_dns_register,
1747 NET_TRANSPORT_ADS,
1748 N_("Add host dns entry to AD"),
1749 N_("net ads dns register\n"
1750 " Add host dns entry to AD")
1753 "gethostbyname",
1754 net_ads_dns_gethostbyname,
1755 NET_TRANSPORT_ADS,
1756 N_("Look up host"),
1757 N_("net ads dns gethostbyname\n"
1758 " Look up host")
1760 {NULL, NULL, 0, NULL, NULL}
1763 return net_run_function(c, argc, argv, "net ads dns", func);
1766 /*******************************************************************
1767 ********************************************************************/
1769 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1771 d_printf(_(
1772 "\nnet ads printer search <printer>"
1773 "\n\tsearch for a printer in the directory\n"
1774 "\nnet ads printer info <printer> <server>"
1775 "\n\tlookup info in directory for printer on server"
1776 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1777 "\nnet ads printer publish <printername>"
1778 "\n\tpublish printer in directory"
1779 "\n\t(note: printer name is required)\n"
1780 "\nnet ads printer remove <printername>"
1781 "\n\tremove printer from directory"
1782 "\n\t(note: printer name is required)\n"));
1783 return -1;
1786 /*******************************************************************
1787 ********************************************************************/
1789 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1791 ADS_STRUCT *ads;
1792 ADS_STATUS rc;
1793 LDAPMessage *res = NULL;
1795 if (c->display_usage) {
1796 d_printf( "%s\n"
1797 "net ads printer search\n"
1798 " %s\n",
1799 _("Usage:"),
1800 _("List printers in the AD"));
1801 return 0;
1804 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1805 return -1;
1808 rc = ads_find_printers(ads, &res);
1810 if (!ADS_ERR_OK(rc)) {
1811 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
1812 ads_msgfree(ads, res);
1813 ads_destroy(&ads);
1814 return -1;
1817 if (ads_count_replies(ads, res) == 0) {
1818 d_fprintf(stderr, _("No results found\n"));
1819 ads_msgfree(ads, res);
1820 ads_destroy(&ads);
1821 return -1;
1824 ads_dump(ads, res);
1825 ads_msgfree(ads, res);
1826 ads_destroy(&ads);
1827 return 0;
1830 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1832 ADS_STRUCT *ads;
1833 ADS_STATUS rc;
1834 const char *servername, *printername;
1835 LDAPMessage *res = NULL;
1837 if (c->display_usage) {
1838 d_printf("%s\n%s",
1839 _("Usage:"),
1840 _("net ads printer info [printername [servername]]\n"
1841 " Display printer info from AD\n"
1842 " printername\tPrinter name or wildcard\n"
1843 " servername\tName of the print server\n"));
1844 return 0;
1847 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1848 return -1;
1851 if (argc > 0) {
1852 printername = argv[0];
1853 } else {
1854 printername = "*";
1857 if (argc > 1) {
1858 servername = argv[1];
1859 } else {
1860 servername = lp_netbios_name();
1863 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1865 if (!ADS_ERR_OK(rc)) {
1866 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
1867 servername, ads_errstr(rc));
1868 ads_msgfree(ads, res);
1869 ads_destroy(&ads);
1870 return -1;
1873 if (ads_count_replies(ads, res) == 0) {
1874 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
1875 ads_msgfree(ads, res);
1876 ads_destroy(&ads);
1877 return -1;
1880 ads_dump(ads, res);
1881 ads_msgfree(ads, res);
1882 ads_destroy(&ads);
1884 return 0;
1887 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1889 ADS_STRUCT *ads;
1890 ADS_STATUS rc;
1891 const char *servername, *printername;
1892 struct cli_state *cli = NULL;
1893 struct rpc_pipe_client *pipe_hnd = NULL;
1894 struct sockaddr_storage server_ss;
1895 NTSTATUS nt_status;
1896 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1897 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1898 char *prt_dn, *srv_dn, **srv_cn;
1899 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1900 LDAPMessage *res = NULL;
1902 if (argc < 1 || c->display_usage) {
1903 d_printf("%s\n%s",
1904 _("Usage:"),
1905 _("net ads printer publish <printername> [servername]\n"
1906 " Publish printer in AD\n"
1907 " printername\tName of the printer\n"
1908 " servername\tName of the print server\n"));
1909 talloc_destroy(mem_ctx);
1910 return -1;
1913 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1914 talloc_destroy(mem_ctx);
1915 return -1;
1918 printername = argv[0];
1920 if (argc == 2) {
1921 servername = argv[1];
1922 } else {
1923 servername = lp_netbios_name();
1926 /* Get printer data from SPOOLSS */
1928 resolve_name(servername, &server_ss, 0x20, false);
1930 nt_status = cli_full_connection(&cli, lp_netbios_name(), servername,
1931 &server_ss, 0,
1932 "IPC$", "IPC",
1933 c->opt_user_name, c->opt_workgroup,
1934 c->opt_password ? c->opt_password : "",
1935 CLI_FULL_CONNECTION_USE_KERBEROS,
1936 SMB_SIGNING_DEFAULT);
1938 if (NT_STATUS_IS_ERR(nt_status)) {
1939 d_fprintf(stderr, _("Unable to open a connection to %s to "
1940 "obtain data for %s\n"),
1941 servername, printername);
1942 ads_destroy(&ads);
1943 talloc_destroy(mem_ctx);
1944 return -1;
1947 /* Publish on AD server */
1949 ads_find_machine_acct(ads, &res, servername);
1951 if (ads_count_replies(ads, res) == 0) {
1952 d_fprintf(stderr, _("Could not find machine account for server "
1953 "%s\n"),
1954 servername);
1955 ads_destroy(&ads);
1956 talloc_destroy(mem_ctx);
1957 return -1;
1960 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1961 srv_cn = ldap_explode_dn(srv_dn, 1);
1963 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1964 printername_escaped = escape_rdn_val_string_alloc(printername);
1965 if (!srv_cn_escaped || !printername_escaped) {
1966 SAFE_FREE(srv_cn_escaped);
1967 SAFE_FREE(printername_escaped);
1968 d_fprintf(stderr, _("Internal error, out of memory!"));
1969 ads_destroy(&ads);
1970 talloc_destroy(mem_ctx);
1971 return -1;
1974 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1975 SAFE_FREE(srv_cn_escaped);
1976 SAFE_FREE(printername_escaped);
1977 d_fprintf(stderr, _("Internal error, out of memory!"));
1978 ads_destroy(&ads);
1979 talloc_destroy(mem_ctx);
1980 return -1;
1983 SAFE_FREE(srv_cn_escaped);
1984 SAFE_FREE(printername_escaped);
1986 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss, &pipe_hnd);
1987 if (!NT_STATUS_IS_OK(nt_status)) {
1988 d_fprintf(stderr, _("Unable to open a connection to the spoolss pipe on %s\n"),
1989 servername);
1990 SAFE_FREE(prt_dn);
1991 ads_destroy(&ads);
1992 talloc_destroy(mem_ctx);
1993 return -1;
1996 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1997 printername))) {
1998 SAFE_FREE(prt_dn);
1999 ads_destroy(&ads);
2000 talloc_destroy(mem_ctx);
2001 return -1;
2004 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
2005 if (!ADS_ERR_OK(rc)) {
2006 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
2007 SAFE_FREE(prt_dn);
2008 ads_destroy(&ads);
2009 talloc_destroy(mem_ctx);
2010 return -1;
2013 d_printf("published printer\n");
2014 SAFE_FREE(prt_dn);
2015 ads_destroy(&ads);
2016 talloc_destroy(mem_ctx);
2018 return 0;
2021 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
2023 ADS_STRUCT *ads;
2024 ADS_STATUS rc;
2025 const char *servername;
2026 char *prt_dn;
2027 LDAPMessage *res = NULL;
2029 if (argc < 1 || c->display_usage) {
2030 d_printf("%s\n%s",
2031 _("Usage:"),
2032 _("net ads printer remove <printername> [servername]\n"
2033 " Remove a printer from the AD\n"
2034 " printername\tName of the printer\n"
2035 " servername\tName of the print server\n"));
2036 return -1;
2039 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2040 return -1;
2043 if (argc > 1) {
2044 servername = argv[1];
2045 } else {
2046 servername = lp_netbios_name();
2049 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
2051 if (!ADS_ERR_OK(rc)) {
2052 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
2053 ads_msgfree(ads, res);
2054 ads_destroy(&ads);
2055 return -1;
2058 if (ads_count_replies(ads, res) == 0) {
2059 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
2060 ads_msgfree(ads, res);
2061 ads_destroy(&ads);
2062 return -1;
2065 prt_dn = ads_get_dn(ads, talloc_tos(), res);
2066 ads_msgfree(ads, res);
2067 rc = ads_del_dn(ads, prt_dn);
2068 TALLOC_FREE(prt_dn);
2070 if (!ADS_ERR_OK(rc)) {
2071 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
2072 ads_destroy(&ads);
2073 return -1;
2076 ads_destroy(&ads);
2077 return 0;
2080 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
2082 struct functable func[] = {
2084 "search",
2085 net_ads_printer_search,
2086 NET_TRANSPORT_ADS,
2087 N_("Search for a printer"),
2088 N_("net ads printer search\n"
2089 " Search for a printer")
2092 "info",
2093 net_ads_printer_info,
2094 NET_TRANSPORT_ADS,
2095 N_("Display printer information"),
2096 N_("net ads printer info\n"
2097 " Display printer information")
2100 "publish",
2101 net_ads_printer_publish,
2102 NET_TRANSPORT_ADS,
2103 N_("Publish a printer"),
2104 N_("net ads printer publish\n"
2105 " Publish a printer")
2108 "remove",
2109 net_ads_printer_remove,
2110 NET_TRANSPORT_ADS,
2111 N_("Delete a printer"),
2112 N_("net ads printer remove\n"
2113 " Delete a printer")
2115 {NULL, NULL, 0, NULL, NULL}
2118 return net_run_function(c, argc, argv, "net ads printer", func);
2122 static int net_ads_password(struct net_context *c, int argc, const char **argv)
2124 ADS_STRUCT *ads;
2125 const char *auth_principal = c->opt_user_name;
2126 const char *auth_password = c->opt_password;
2127 const char *realm = NULL;
2128 const char *new_password = NULL;
2129 char *chr, *prompt;
2130 const char *user;
2131 char pwd[256] = {0};
2132 ADS_STATUS ret;
2134 if (c->display_usage) {
2135 d_printf("%s\n%s",
2136 _("Usage:"),
2137 _("net ads password <username>\n"
2138 " Change password for user\n"
2139 " username\tName of user to change password for\n"));
2140 return 0;
2143 if (c->opt_user_name == NULL || c->opt_password == NULL) {
2144 d_fprintf(stderr, _("You must supply an administrator "
2145 "username/password\n"));
2146 return -1;
2149 if (argc < 1) {
2150 d_fprintf(stderr, _("ERROR: You must say which username to "
2151 "change password for\n"));
2152 return -1;
2155 user = argv[0];
2156 if (!strchr_m(user, '@')) {
2157 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
2158 return -1;
2160 user = chr;
2163 use_in_memory_ccache();
2164 chr = strchr_m(auth_principal, '@');
2165 if (chr) {
2166 realm = ++chr;
2167 } else {
2168 realm = lp_realm();
2171 /* use the realm so we can eventually change passwords for users
2172 in realms other than default */
2173 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
2174 return -1;
2177 /* we don't actually need a full connect, but it's the easy way to
2178 fill in the KDC's addresss */
2179 ads_connect(ads);
2181 if (!ads->config.realm) {
2182 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
2183 ads_destroy(&ads);
2184 return -1;
2187 if (argv[1]) {
2188 new_password = (const char *)argv[1];
2189 } else {
2190 int rc;
2192 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
2193 return -1;
2195 rc = samba_getpass(prompt, pwd, sizeof(pwd), false, true);
2196 if (rc < 0) {
2197 return -1;
2199 new_password = pwd;
2200 free(prompt);
2203 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2204 auth_password, user, new_password, ads->auth.time_offset);
2205 memset(pwd, '\0', sizeof(pwd));
2206 if (!ADS_ERR_OK(ret)) {
2207 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2208 ads_destroy(&ads);
2209 return -1;
2212 d_printf(_("Password change for %s completed.\n"), user);
2213 ads_destroy(&ads);
2215 return 0;
2218 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2220 ADS_STRUCT *ads;
2221 char *host_principal;
2222 fstring my_name;
2223 ADS_STATUS ret;
2225 if (c->display_usage) {
2226 d_printf( "%s\n"
2227 "net ads changetrustpw\n"
2228 " %s\n",
2229 _("Usage:"),
2230 _("Change the machine account's trust password"));
2231 return 0;
2234 if (!secrets_init()) {
2235 DEBUG(1,("Failed to initialise secrets database\n"));
2236 return -1;
2239 net_use_krb_machine_account(c);
2241 use_in_memory_ccache();
2243 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2244 return -1;
2247 fstrcpy(my_name, lp_netbios_name());
2248 if (!strlower_m(my_name)) {
2249 ads_destroy(&ads);
2250 return -1;
2253 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2254 ads_destroy(&ads);
2255 return -1;
2257 d_printf(_("Changing password for principal: %s\n"), host_principal);
2259 ret = ads_change_trust_account_password(ads, host_principal);
2261 if (!ADS_ERR_OK(ret)) {
2262 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2263 ads_destroy(&ads);
2264 SAFE_FREE(host_principal);
2265 return -1;
2268 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2270 if (USE_SYSTEM_KEYTAB) {
2271 d_printf(_("Attempting to update system keytab with new password.\n"));
2272 if (ads_keytab_create_default(ads)) {
2273 d_printf(_("Failed to update system keytab.\n"));
2277 ads_destroy(&ads);
2278 SAFE_FREE(host_principal);
2280 return 0;
2284 help for net ads search
2286 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2288 d_printf(_(
2289 "\nnet ads search <expression> <attributes...>\n"
2290 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2291 "The expression is a standard LDAP search expression, and the\n"
2292 "attributes are a list of LDAP fields to show in the results.\n\n"
2293 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2295 net_common_flags_usage(c, argc, argv);
2296 return -1;
2301 general ADS search function. Useful in diagnosing problems in ADS
2303 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2305 ADS_STRUCT *ads;
2306 ADS_STATUS rc;
2307 const char *ldap_exp;
2308 const char **attrs;
2309 LDAPMessage *res = NULL;
2311 if (argc < 1 || c->display_usage) {
2312 return net_ads_search_usage(c, argc, argv);
2315 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2316 return -1;
2319 ldap_exp = argv[0];
2320 attrs = (argv + 1);
2322 rc = ads_do_search_retry(ads, ads->config.bind_path,
2323 LDAP_SCOPE_SUBTREE,
2324 ldap_exp, attrs, &res);
2325 if (!ADS_ERR_OK(rc)) {
2326 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2327 ads_destroy(&ads);
2328 return -1;
2331 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2333 /* dump the results */
2334 ads_dump(ads, res);
2336 ads_msgfree(ads, res);
2337 ads_destroy(&ads);
2339 return 0;
2344 help for net ads search
2346 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2348 d_printf(_(
2349 "\nnet ads dn <dn> <attributes...>\n"
2350 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2351 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2352 "to show in the results\n\n"
2353 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2354 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2356 net_common_flags_usage(c, argc, argv);
2357 return -1;
2362 general ADS search function. Useful in diagnosing problems in ADS
2364 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2366 ADS_STRUCT *ads;
2367 ADS_STATUS rc;
2368 const char *dn;
2369 const char **attrs;
2370 LDAPMessage *res = NULL;
2372 if (argc < 1 || c->display_usage) {
2373 return net_ads_dn_usage(c, argc, argv);
2376 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2377 return -1;
2380 dn = argv[0];
2381 attrs = (argv + 1);
2383 rc = ads_do_search_all(ads, dn,
2384 LDAP_SCOPE_BASE,
2385 "(objectclass=*)", attrs, &res);
2386 if (!ADS_ERR_OK(rc)) {
2387 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2388 ads_destroy(&ads);
2389 return -1;
2392 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2394 /* dump the results */
2395 ads_dump(ads, res);
2397 ads_msgfree(ads, res);
2398 ads_destroy(&ads);
2400 return 0;
2404 help for net ads sid search
2406 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2408 d_printf(_(
2409 "\nnet ads sid <sid> <attributes...>\n"
2410 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2411 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2412 "to show in the results\n\n"
2413 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2415 net_common_flags_usage(c, argc, argv);
2416 return -1;
2421 general ADS search function. Useful in diagnosing problems in ADS
2423 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2425 ADS_STRUCT *ads;
2426 ADS_STATUS rc;
2427 const char *sid_string;
2428 const char **attrs;
2429 LDAPMessage *res = NULL;
2430 struct dom_sid sid;
2432 if (argc < 1 || c->display_usage) {
2433 return net_ads_sid_usage(c, argc, argv);
2436 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2437 return -1;
2440 sid_string = argv[0];
2441 attrs = (argv + 1);
2443 if (!string_to_sid(&sid, sid_string)) {
2444 d_fprintf(stderr, _("could not convert sid\n"));
2445 ads_destroy(&ads);
2446 return -1;
2449 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2450 if (!ADS_ERR_OK(rc)) {
2451 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2452 ads_destroy(&ads);
2453 return -1;
2456 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2458 /* dump the results */
2459 ads_dump(ads, res);
2461 ads_msgfree(ads, res);
2462 ads_destroy(&ads);
2464 return 0;
2467 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2469 int ret;
2470 ADS_STRUCT *ads;
2472 if (c->display_usage) {
2473 d_printf( "%s\n"
2474 "net ads keytab flush\n"
2475 " %s\n",
2476 _("Usage:"),
2477 _("Delete the whole keytab"));
2478 return 0;
2481 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2482 return -1;
2484 ret = ads_keytab_flush(ads);
2485 ads_destroy(&ads);
2486 return ret;
2489 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2491 int i;
2492 int ret = 0;
2493 ADS_STRUCT *ads;
2495 if (c->display_usage) {
2496 d_printf("%s\n%s",
2497 _("Usage:"),
2498 _("net ads keytab add <principal> [principal ...]\n"
2499 " Add principals to local keytab\n"
2500 " principal\tKerberos principal to add to "
2501 "keytab\n"));
2502 return 0;
2505 d_printf(_("Processing principals to add...\n"));
2506 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2507 return -1;
2509 for (i = 0; i < argc; i++) {
2510 ret |= ads_keytab_add_entry(ads, argv[i]);
2512 ads_destroy(&ads);
2513 return ret;
2516 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2518 ADS_STRUCT *ads;
2519 int ret;
2521 if (c->display_usage) {
2522 d_printf( "%s\n"
2523 "net ads keytab create\n"
2524 " %s\n",
2525 _("Usage:"),
2526 _("Create new default keytab"));
2527 return 0;
2530 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2531 return -1;
2533 ret = ads_keytab_create_default(ads);
2534 ads_destroy(&ads);
2535 return ret;
2538 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2540 const char *keytab = NULL;
2542 if (c->display_usage) {
2543 d_printf("%s\n%s",
2544 _("Usage:"),
2545 _("net ads keytab list [keytab]\n"
2546 " List a local keytab\n"
2547 " keytab\tKeytab to list\n"));
2548 return 0;
2551 if (argc >= 1) {
2552 keytab = argv[0];
2555 return ads_keytab_list(keytab);
2559 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2561 struct functable func[] = {
2563 "add",
2564 net_ads_keytab_add,
2565 NET_TRANSPORT_ADS,
2566 N_("Add a service principal"),
2567 N_("net ads keytab add\n"
2568 " Add a service principal")
2571 "create",
2572 net_ads_keytab_create,
2573 NET_TRANSPORT_ADS,
2574 N_("Create a fresh keytab"),
2575 N_("net ads keytab create\n"
2576 " Create a fresh keytab")
2579 "flush",
2580 net_ads_keytab_flush,
2581 NET_TRANSPORT_ADS,
2582 N_("Remove all keytab entries"),
2583 N_("net ads keytab flush\n"
2584 " Remove all keytab entries")
2587 "list",
2588 net_ads_keytab_list,
2589 NET_TRANSPORT_ADS,
2590 N_("List a keytab"),
2591 N_("net ads keytab list\n"
2592 " List a keytab")
2594 {NULL, NULL, 0, NULL, NULL}
2597 if (!USE_KERBEROS_KEYTAB) {
2598 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2599 "keytab method to use keytab functions.\n"));
2602 return net_run_function(c, argc, argv, "net ads keytab", func);
2605 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2607 int ret = -1;
2609 if (c->display_usage) {
2610 d_printf( "%s\n"
2611 "net ads kerberos renew\n"
2612 " %s\n",
2613 _("Usage:"),
2614 _("Renew TGT from existing credential cache"));
2615 return 0;
2618 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2619 if (ret) {
2620 d_printf(_("failed to renew kerberos ticket: %s\n"),
2621 error_message(ret));
2623 return ret;
2626 static int net_ads_kerberos_pac_common(struct net_context *c, int argc, const char **argv,
2627 struct PAC_DATA_CTR **pac_data_ctr)
2629 NTSTATUS status;
2630 int ret = -1;
2631 const char *impersonate_princ_s = NULL;
2632 const char *local_service = NULL;
2633 int i;
2635 for (i=0; i<argc; i++) {
2636 if (strnequal(argv[i], "impersonate", strlen("impersonate"))) {
2637 impersonate_princ_s = get_string_param(argv[i]);
2638 if (impersonate_princ_s == NULL) {
2639 return -1;
2642 if (strnequal(argv[i], "local_service", strlen("local_service"))) {
2643 local_service = get_string_param(argv[i]);
2644 if (local_service == NULL) {
2645 return -1;
2650 if (local_service == NULL) {
2651 local_service = talloc_asprintf(c, "%s$@%s",
2652 lp_netbios_name(), lp_realm());
2653 if (local_service == NULL) {
2654 goto out;
2658 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2660 status = kerberos_return_pac(c,
2661 c->opt_user_name,
2662 c->opt_password,
2664 NULL,
2665 NULL,
2666 NULL,
2667 true,
2668 true,
2669 2592000, /* one month */
2670 impersonate_princ_s,
2671 local_service,
2672 pac_data_ctr);
2673 if (!NT_STATUS_IS_OK(status)) {
2674 d_printf(_("failed to query kerberos PAC: %s\n"),
2675 nt_errstr(status));
2676 goto out;
2679 ret = 0;
2680 out:
2681 return ret;
2684 static int net_ads_kerberos_pac_dump(struct net_context *c, int argc, const char **argv)
2686 struct PAC_DATA_CTR *pac_data_ctr = NULL;
2687 int i;
2688 int ret = -1;
2689 enum PAC_TYPE type = 0;
2691 if (c->display_usage) {
2692 d_printf( "%s\n"
2693 "net ads kerberos pac dump [impersonate=string] [local_service=string] [pac_buffer_type=int]\n"
2694 " %s\n",
2695 _("Usage:"),
2696 _("Dump the Kerberos PAC"));
2697 return -1;
2700 for (i=0; i<argc; i++) {
2701 if (strnequal(argv[i], "pac_buffer_type", strlen("pac_buffer_type"))) {
2702 type = get_int_param(argv[i]);
2706 ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
2707 if (ret) {
2708 return ret;
2711 if (type == 0) {
2713 char *s = NULL;
2715 s = NDR_PRINT_STRUCT_STRING(c, PAC_DATA,
2716 pac_data_ctr->pac_data);
2717 if (s != NULL) {
2718 d_printf(_("The Pac: %s\n"), s);
2719 talloc_free(s);
2722 return 0;
2725 for (i=0; i < pac_data_ctr->pac_data->num_buffers; i++) {
2727 char *s = NULL;
2729 if (pac_data_ctr->pac_data->buffers[i].type != type) {
2730 continue;
2733 s = NDR_PRINT_UNION_STRING(c, PAC_INFO, type,
2734 pac_data_ctr->pac_data->buffers[i].info);
2735 if (s != NULL) {
2736 d_printf(_("The Pac: %s\n"), s);
2737 talloc_free(s);
2739 break;
2742 return 0;
2745 static int net_ads_kerberos_pac_save(struct net_context *c, int argc, const char **argv)
2747 struct PAC_DATA_CTR *pac_data_ctr = NULL;
2748 char *filename = NULL;
2749 int ret = -1;
2750 int i;
2752 if (c->display_usage) {
2753 d_printf( "%s\n"
2754 "net ads kerberos pac save [impersonate=string] [local_service=string] [filename=string]\n"
2755 " %s\n",
2756 _("Usage:"),
2757 _("Save the Kerberos PAC"));
2758 return -1;
2761 for (i=0; i<argc; i++) {
2762 if (strnequal(argv[i], "filename", strlen("filename"))) {
2763 filename = get_string_param(argv[i]);
2764 if (filename == NULL) {
2765 return -1;
2770 ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
2771 if (ret) {
2772 return ret;
2775 if (filename == NULL) {
2776 d_printf(_("please define \"filename=<filename>\" to save the PAC\n"));
2777 return -1;
2780 /* save the raw format */
2781 if (!file_save(filename, pac_data_ctr->pac_blob.data, pac_data_ctr->pac_blob.length)) {
2782 d_printf(_("failed to save PAC in %s\n"), filename);
2783 return -1;
2786 return 0;
2789 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2791 struct functable func[] = {
2793 "dump",
2794 net_ads_kerberos_pac_dump,
2795 NET_TRANSPORT_ADS,
2796 N_("Dump Kerberos PAC"),
2797 N_("net ads kerberos pac dump\n"
2798 " Dump a Kerberos PAC to stdout")
2801 "save",
2802 net_ads_kerberos_pac_save,
2803 NET_TRANSPORT_ADS,
2804 N_("Save Kerberos PAC"),
2805 N_("net ads kerberos pac save\n"
2806 " Save a Kerberos PAC in a file")
2809 {NULL, NULL, 0, NULL, NULL}
2812 return net_run_function(c, argc, argv, "net ads kerberos pac", func);
2815 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2817 TALLOC_CTX *mem_ctx = NULL;
2818 int ret = -1;
2819 NTSTATUS status;
2821 if (c->display_usage) {
2822 d_printf( "%s\n"
2823 "net ads kerberos kinit\n"
2824 " %s\n",
2825 _("Usage:"),
2826 _("Get Ticket Granting Ticket (TGT) for the user"));
2827 return 0;
2830 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2831 if (!mem_ctx) {
2832 goto out;
2835 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2837 ret = kerberos_kinit_password_ext(c->opt_user_name,
2838 c->opt_password,
2840 NULL,
2841 NULL,
2842 NULL,
2843 true,
2844 true,
2845 2592000, /* one month */
2846 &status);
2847 if (ret) {
2848 d_printf(_("failed to kinit password: %s\n"),
2849 nt_errstr(status));
2851 out:
2852 return ret;
2855 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2857 struct functable func[] = {
2859 "kinit",
2860 net_ads_kerberos_kinit,
2861 NET_TRANSPORT_ADS,
2862 N_("Retrieve Ticket Granting Ticket (TGT)"),
2863 N_("net ads kerberos kinit\n"
2864 " Receive Ticket Granting Ticket (TGT)")
2867 "renew",
2868 net_ads_kerberos_renew,
2869 NET_TRANSPORT_ADS,
2870 N_("Renew Ticket Granting Ticket from credential cache"),
2871 N_("net ads kerberos renew\n"
2872 " Renew Ticket Granting Ticket (TGT) from "
2873 "credential cache")
2876 "pac",
2877 net_ads_kerberos_pac,
2878 NET_TRANSPORT_ADS,
2879 N_("Dump Kerberos PAC"),
2880 N_("net ads kerberos pac\n"
2881 " Dump Kerberos PAC")
2883 {NULL, NULL, 0, NULL, NULL}
2886 return net_run_function(c, argc, argv, "net ads kerberos", func);
2889 static int net_ads_enctype_lookup_account(struct net_context *c,
2890 ADS_STRUCT *ads,
2891 const char *account,
2892 LDAPMessage **res,
2893 const char **enctype_str)
2895 const char *filter;
2896 const char *attrs[] = {
2897 "msDS-SupportedEncryptionTypes",
2898 NULL
2900 int count;
2901 int ret = -1;
2902 ADS_STATUS status;
2904 filter = talloc_asprintf(c, "(&(objectclass=user)(sAMAccountName=%s))",
2905 account);
2906 if (filter == NULL) {
2907 goto done;
2910 status = ads_search(ads, res, filter, attrs);
2911 if (!ADS_ERR_OK(status)) {
2912 d_printf(_("no account found with filter: %s\n"), filter);
2913 goto done;
2916 count = ads_count_replies(ads, *res);
2917 switch (count) {
2918 case 1:
2919 break;
2920 case 0:
2921 d_printf(_("no account found with filter: %s\n"), filter);
2922 goto done;
2923 default:
2924 d_printf(_("multiple accounts found with filter: %s\n"), filter);
2925 goto done;
2928 if (enctype_str) {
2929 *enctype_str = ads_pull_string(ads, c, *res,
2930 "msDS-SupportedEncryptionTypes");
2931 if (*enctype_str == NULL) {
2932 d_printf(_("no msDS-SupportedEncryptionTypes attribute found\n"));
2933 goto done;
2937 ret = 0;
2938 done:
2939 return ret;
2942 static void net_ads_enctype_dump_enctypes(const char *username,
2943 const char *enctype_str)
2945 int enctypes = atoi(enctype_str);
2947 d_printf(_("'%s' uses \"msDS-SupportedEncryptionTypes\": %d (0x%08x)\n"),
2948 username, enctypes, enctypes);
2950 printf("[%s] 0x%08x DES-CBC-CRC\n",
2951 enctypes & ENC_CRC32 ? "X" : " ",
2952 ENC_CRC32);
2953 printf("[%s] 0x%08x DES-CBC-MD5\n",
2954 enctypes & ENC_RSA_MD5 ? "X" : " ",
2955 ENC_RSA_MD5);
2956 printf("[%s] 0x%08x RC4-HMAC\n",
2957 enctypes & ENC_RC4_HMAC_MD5 ? "X" : " ",
2958 ENC_RC4_HMAC_MD5);
2959 printf("[%s] 0x%08x AES128-CTS-HMAC-SHA1-96\n",
2960 enctypes & ENC_HMAC_SHA1_96_AES128 ? "X" : " ",
2961 ENC_HMAC_SHA1_96_AES128);
2962 printf("[%s] 0x%08x AES256-CTS-HMAC-SHA1-96\n",
2963 enctypes & ENC_HMAC_SHA1_96_AES256 ? "X" : " ",
2964 ENC_HMAC_SHA1_96_AES256);
2967 static int net_ads_enctypes_list(struct net_context *c, int argc, const char **argv)
2969 int ret = -1;
2970 ADS_STATUS status;
2971 ADS_STRUCT *ads = NULL;
2972 LDAPMessage *res = NULL;
2973 const char *str = NULL;
2975 if (c->display_usage || (argc < 1)) {
2976 d_printf( "%s\n"
2977 "net ads enctypes list\n"
2978 " %s\n",
2979 _("Usage:"),
2980 _("List supported enctypes"));
2981 return 0;
2984 status = ads_startup(c, false, &ads);
2985 if (!ADS_ERR_OK(status)) {
2986 printf("startup failed\n");
2987 return ret;
2990 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
2991 if (ret) {
2992 goto done;
2995 net_ads_enctype_dump_enctypes(argv[0], str);
2997 ret = 0;
2998 done:
2999 ads_msgfree(ads, res);
3000 ads_destroy(&ads);
3002 return ret;
3005 static int net_ads_enctypes_set(struct net_context *c, int argc, const char **argv)
3007 int ret = -1;
3008 ADS_STATUS status;
3009 ADS_STRUCT *ads;
3010 LDAPMessage *res = NULL;
3011 const char *etype_list_str;
3012 const char *dn;
3013 ADS_MODLIST mods;
3014 uint32_t etype_list;
3015 const char *str;
3017 if (c->display_usage || argc < 1) {
3018 d_printf( "%s\n"
3019 "net ads enctypes set <sAMAccountName> [enctypes]\n"
3020 " %s\n",
3021 _("Usage:"),
3022 _("Set supported enctypes"));
3023 return 0;
3026 status = ads_startup(c, false, &ads);
3027 if (!ADS_ERR_OK(status)) {
3028 printf("startup failed\n");
3029 return ret;
3032 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3033 if (ret) {
3034 goto done;
3037 dn = ads_get_dn(ads, c, res);
3038 if (dn == NULL) {
3039 goto done;
3042 etype_list = ENC_CRC32 | ENC_RSA_MD5 | ENC_RC4_HMAC_MD5;
3043 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
3044 etype_list |= ENC_HMAC_SHA1_96_AES128;
3045 #endif
3046 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
3047 etype_list |= ENC_HMAC_SHA1_96_AES256;
3048 #endif
3050 if (argv[1] != NULL) {
3051 sscanf(argv[1], "%i", &etype_list);
3054 etype_list_str = talloc_asprintf(c, "%d", etype_list);
3055 if (!etype_list_str) {
3056 goto done;
3059 mods = ads_init_mods(c);
3060 if (!mods) {
3061 goto done;
3064 status = ads_mod_str(c, &mods, "msDS-SupportedEncryptionTypes",
3065 etype_list_str);
3066 if (!ADS_ERR_OK(status)) {
3067 goto done;
3070 status = ads_gen_mod(ads, dn, mods);
3071 if (!ADS_ERR_OK(status)) {
3072 d_printf(_("failed to add msDS-SupportedEncryptionTypes: %s\n"),
3073 ads_errstr(status));
3074 goto done;
3077 ads_msgfree(ads, res);
3079 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3080 if (ret) {
3081 goto done;
3084 net_ads_enctype_dump_enctypes(argv[0], str);
3086 ret = 0;
3087 done:
3088 ads_msgfree(ads, res);
3089 ads_destroy(&ads);
3091 return ret;
3094 static int net_ads_enctypes_delete(struct net_context *c, int argc, const char **argv)
3096 int ret = -1;
3097 ADS_STATUS status;
3098 ADS_STRUCT *ads;
3099 LDAPMessage *res = NULL;
3100 const char *dn;
3101 ADS_MODLIST mods;
3103 if (c->display_usage || argc < 1) {
3104 d_printf( "%s\n"
3105 "net ads enctypes delete <sAMAccountName>\n"
3106 " %s\n",
3107 _("Usage:"),
3108 _("Delete supported enctypes"));
3109 return 0;
3112 status = ads_startup(c, false, &ads);
3113 if (!ADS_ERR_OK(status)) {
3114 printf("startup failed\n");
3115 return ret;
3118 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3119 if (ret) {
3120 goto done;
3123 dn = ads_get_dn(ads, c, res);
3124 if (dn == NULL) {
3125 goto done;
3128 mods = ads_init_mods(c);
3129 if (!mods) {
3130 goto done;
3133 status = ads_mod_str(c, &mods, "msDS-SupportedEncryptionTypes", NULL);
3134 if (!ADS_ERR_OK(status)) {
3135 goto done;
3138 status = ads_gen_mod(ads, dn, mods);
3139 if (!ADS_ERR_OK(status)) {
3140 d_printf(_("failed to remove msDS-SupportedEncryptionTypes: %s\n"),
3141 ads_errstr(status));
3142 goto done;
3145 ret = 0;
3147 done:
3148 ads_msgfree(ads, res);
3149 ads_destroy(&ads);
3150 return ret;
3153 static int net_ads_enctypes(struct net_context *c, int argc, const char **argv)
3155 struct functable func[] = {
3157 "list",
3158 net_ads_enctypes_list,
3159 NET_TRANSPORT_ADS,
3160 N_("List the supported encryption types"),
3161 N_("net ads enctypes list\n"
3162 " List the supported encryption types")
3165 "set",
3166 net_ads_enctypes_set,
3167 NET_TRANSPORT_ADS,
3168 N_("Set the supported encryption types"),
3169 N_("net ads enctypes set\n"
3170 " Set the supported encryption types")
3173 "delete",
3174 net_ads_enctypes_delete,
3175 NET_TRANSPORT_ADS,
3176 N_("Delete the supported encryption types"),
3177 N_("net ads enctypes delete\n"
3178 " Delete the supported encryption types")
3181 {NULL, NULL, 0, NULL, NULL}
3184 return net_run_function(c, argc, argv, "net ads enctypes", func);
3188 int net_ads(struct net_context *c, int argc, const char **argv)
3190 struct functable func[] = {
3192 "info",
3193 net_ads_info,
3194 NET_TRANSPORT_ADS,
3195 N_("Display details on remote ADS server"),
3196 N_("net ads info\n"
3197 " Display details on remote ADS server")
3200 "join",
3201 net_ads_join,
3202 NET_TRANSPORT_ADS,
3203 N_("Join the local machine to ADS realm"),
3204 N_("net ads join\n"
3205 " Join the local machine to ADS realm")
3208 "testjoin",
3209 net_ads_testjoin,
3210 NET_TRANSPORT_ADS,
3211 N_("Validate machine account"),
3212 N_("net ads testjoin\n"
3213 " Validate machine account")
3216 "leave",
3217 net_ads_leave,
3218 NET_TRANSPORT_ADS,
3219 N_("Remove the local machine from ADS"),
3220 N_("net ads leave\n"
3221 " Remove the local machine from ADS")
3224 "status",
3225 net_ads_status,
3226 NET_TRANSPORT_ADS,
3227 N_("Display machine account details"),
3228 N_("net ads status\n"
3229 " Display machine account details")
3232 "user",
3233 net_ads_user,
3234 NET_TRANSPORT_ADS,
3235 N_("List/modify users"),
3236 N_("net ads user\n"
3237 " List/modify users")
3240 "group",
3241 net_ads_group,
3242 NET_TRANSPORT_ADS,
3243 N_("List/modify groups"),
3244 N_("net ads group\n"
3245 " List/modify groups")
3248 "dns",
3249 net_ads_dns,
3250 NET_TRANSPORT_ADS,
3251 N_("Issue dynamic DNS update"),
3252 N_("net ads dns\n"
3253 " Issue dynamic DNS update")
3256 "password",
3257 net_ads_password,
3258 NET_TRANSPORT_ADS,
3259 N_("Change user passwords"),
3260 N_("net ads password\n"
3261 " Change user passwords")
3264 "changetrustpw",
3265 net_ads_changetrustpw,
3266 NET_TRANSPORT_ADS,
3267 N_("Change trust account password"),
3268 N_("net ads changetrustpw\n"
3269 " Change trust account password")
3272 "printer",
3273 net_ads_printer,
3274 NET_TRANSPORT_ADS,
3275 N_("List/modify printer entries"),
3276 N_("net ads printer\n"
3277 " List/modify printer entries")
3280 "search",
3281 net_ads_search,
3282 NET_TRANSPORT_ADS,
3283 N_("Issue LDAP search using filter"),
3284 N_("net ads search\n"
3285 " Issue LDAP search using filter")
3288 "dn",
3289 net_ads_dn,
3290 NET_TRANSPORT_ADS,
3291 N_("Issue LDAP search by DN"),
3292 N_("net ads dn\n"
3293 " Issue LDAP search by DN")
3296 "sid",
3297 net_ads_sid,
3298 NET_TRANSPORT_ADS,
3299 N_("Issue LDAP search by SID"),
3300 N_("net ads sid\n"
3301 " Issue LDAP search by SID")
3304 "workgroup",
3305 net_ads_workgroup,
3306 NET_TRANSPORT_ADS,
3307 N_("Display workgroup name"),
3308 N_("net ads workgroup\n"
3309 " Display the workgroup name")
3312 "lookup",
3313 net_ads_lookup,
3314 NET_TRANSPORT_ADS,
3315 N_("Perfom CLDAP query on DC"),
3316 N_("net ads lookup\n"
3317 " Find the ADS DC using CLDAP lookups")
3320 "keytab",
3321 net_ads_keytab,
3322 NET_TRANSPORT_ADS,
3323 N_("Manage local keytab file"),
3324 N_("net ads keytab\n"
3325 " Manage local keytab file")
3328 "gpo",
3329 net_ads_gpo,
3330 NET_TRANSPORT_ADS,
3331 N_("Manage group policy objects"),
3332 N_("net ads gpo\n"
3333 " Manage group policy objects")
3336 "kerberos",
3337 net_ads_kerberos,
3338 NET_TRANSPORT_ADS,
3339 N_("Manage kerberos keytab"),
3340 N_("net ads kerberos\n"
3341 " Manage kerberos keytab")
3344 "enctypes",
3345 net_ads_enctypes,
3346 NET_TRANSPORT_ADS,
3347 N_("List/modify supported encryption types"),
3348 N_("net ads enctypes\n"
3349 " List/modify enctypes")
3351 {NULL, NULL, 0, NULL, NULL}
3354 return net_run_function(c, argc, argv, "net ads", func);
3357 #else
3359 static int net_ads_noads(void)
3361 d_fprintf(stderr, _("ADS support not compiled in\n"));
3362 return -1;
3365 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
3367 return net_ads_noads();
3370 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3372 return net_ads_noads();
3375 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
3377 return net_ads_noads();
3380 int net_ads_join(struct net_context *c, int argc, const char **argv)
3382 return net_ads_noads();
3385 int net_ads_user(struct net_context *c, int argc, const char **argv)
3387 return net_ads_noads();
3390 int net_ads_group(struct net_context *c, int argc, const char **argv)
3392 return net_ads_noads();
3395 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
3397 return net_ads_noads();
3400 /* this one shouldn't display a message */
3401 int net_ads_check(struct net_context *c)
3403 return -1;
3406 int net_ads_check_our_domain(struct net_context *c)
3408 return -1;
3411 int net_ads(struct net_context *c, int argc, const char **argv)
3413 return net_ads_noads();
3416 #endif /* HAVE_ADS */