s3: Fix a winbind race leading to 100% CPU
[Samba.git] / source3 / utils / net_ads.c
blobd81d7805f4139dfda6a1ee5fe70edac66b644be4
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 "libads/dns.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"
41 #ifdef HAVE_ADS
43 /* when we do not have sufficient input parameters to contact a remote domain
44 * we always fall back to our own realm - Guenther*/
46 static const char *assume_own_realm(struct net_context *c)
48 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
49 return lp_realm();
52 return NULL;
56 do a cldap netlogon query
58 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
60 char addr[INET6_ADDRSTRLEN];
61 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
63 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
64 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
65 d_fprintf(stderr, _("CLDAP query failed!\n"));
66 return -1;
69 d_printf(_("Information for Domain Controller: %s\n\n"),
70 addr);
72 d_printf(_("Response Type: "));
73 switch (reply.command) {
74 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
75 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
76 break;
77 case LOGON_SAM_LOGON_RESPONSE_EX:
78 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
79 break;
80 default:
81 d_printf("0x%x\n", reply.command);
82 break;
85 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
87 d_printf(_("Flags:\n"
88 "\tIs a PDC: %s\n"
89 "\tIs a GC of the forest: %s\n"
90 "\tIs an LDAP server: %s\n"
91 "\tSupports DS: %s\n"
92 "\tIs running a KDC: %s\n"
93 "\tIs running time services: %s\n"
94 "\tIs the closest DC: %s\n"
95 "\tIs writable: %s\n"
96 "\tHas a hardware clock: %s\n"
97 "\tIs a non-domain NC serviced by LDAP server: %s\n"
98 "\tIs NT6 DC that has some secrets: %s\n"
99 "\tIs NT6 DC that has all secrets: %s\n"),
100 (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
101 (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
102 (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
103 (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
104 (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
105 (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
106 (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
107 (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
108 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
109 (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
110 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
111 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"));
114 printf(_("Forest:\t\t\t%s\n"), reply.forest);
115 printf(_("Domain:\t\t\t%s\n"), reply.dns_domain);
116 printf(_("Domain Controller:\t%s\n"), reply.pdc_dns_name);
118 printf(_("Pre-Win2k Domain:\t%s\n"), reply.domain_name);
119 printf(_("Pre-Win2k Hostname:\t%s\n"), reply.pdc_name);
121 if (*reply.user_name) printf(_("User name:\t%s\n"), reply.user_name);
123 printf(_("Server Site Name :\t\t%s\n"), reply.server_site);
124 printf(_("Client Site Name :\t\t%s\n"), reply.client_site);
126 d_printf(_("NT Version: %d\n"), reply.nt_version);
127 d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
128 d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
130 return 0;
134 this implements the CLDAP based netlogon lookup requests
135 for finding the domain controller of a ADS domain
137 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
139 ADS_STRUCT *ads;
140 int ret;
142 if (c->display_usage) {
143 d_printf("%s\n"
144 "net ads lookup\n"
145 " %s",
146 _("Usage:"),
147 _("Find the ADS DC using CLDAP lookup.\n"));
148 return 0;
151 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
152 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
153 ads_destroy(&ads);
154 return -1;
157 if (!ads->config.realm) {
158 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
159 ads->ldap.port = 389;
162 ret = net_ads_cldap_netlogon(c, ads);
163 ads_destroy(&ads);
164 return ret;
169 static int net_ads_info(struct net_context *c, int argc, const char **argv)
171 ADS_STRUCT *ads;
172 char addr[INET6_ADDRSTRLEN];
174 if (c->display_usage) {
175 d_printf("%s\n"
176 "net ads info\n"
177 " %s",
178 _("Usage:"),
179 _("Display information about an Active Directory "
180 "server.\n"));
181 return 0;
184 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
185 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
186 return -1;
189 if (!ads || !ads->config.realm) {
190 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
191 ads_destroy(&ads);
192 return -1;
195 /* Try to set the server's current time since we didn't do a full
196 TCP LDAP session initially */
198 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
199 d_fprintf( stderr, _("Failed to get server's current time!\n"));
202 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
204 d_printf(_("LDAP server: %s\n"), addr);
205 d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
206 d_printf(_("Realm: %s\n"), ads->config.realm);
207 d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
208 d_printf(_("LDAP port: %d\n"), ads->ldap.port);
209 d_printf(_("Server time: %s\n"),
210 http_timestring(talloc_tos(), ads->config.current_time));
212 d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
213 d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
215 ads_destroy(&ads);
216 return 0;
219 static void use_in_memory_ccache(void) {
220 /* Use in-memory credentials cache so we do not interfere with
221 * existing credentials */
222 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
225 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
226 uint32 auth_flags, ADS_STRUCT **ads_ret)
228 ADS_STRUCT *ads = NULL;
229 ADS_STATUS status;
230 bool need_password = false;
231 bool second_time = false;
232 char *cp;
233 const char *realm = NULL;
234 bool tried_closest_dc = false;
236 /* lp_realm() should be handled by a command line param,
237 However, the join requires that realm be set in smb.conf
238 and compares our realm with the remote server's so this is
239 ok until someone needs more flexibility */
241 *ads_ret = NULL;
243 retry_connect:
244 if (only_own_domain) {
245 realm = lp_realm();
246 } else {
247 realm = assume_own_realm(c);
250 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
252 if (!c->opt_user_name) {
253 c->opt_user_name = "administrator";
256 if (c->opt_user_specified) {
257 need_password = true;
260 retry:
261 if (!c->opt_password && need_password && !c->opt_machine_pass) {
262 c->opt_password = net_prompt_pass(c, c->opt_user_name);
263 if (!c->opt_password) {
264 ads_destroy(&ads);
265 return ADS_ERROR(LDAP_NO_MEMORY);
269 if (c->opt_password) {
270 use_in_memory_ccache();
271 SAFE_FREE(ads->auth.password);
272 ads->auth.password = smb_xstrdup(c->opt_password);
275 ads->auth.flags |= auth_flags;
276 SAFE_FREE(ads->auth.user_name);
277 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
280 * If the username is of the form "name@realm",
281 * extract the realm and convert to upper case.
282 * This is only used to establish the connection.
284 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
285 *cp++ = '\0';
286 SAFE_FREE(ads->auth.realm);
287 ads->auth.realm = smb_xstrdup(cp);
288 strupper_m(ads->auth.realm);
291 status = ads_connect(ads);
293 if (!ADS_ERR_OK(status)) {
295 if (NT_STATUS_EQUAL(ads_ntstatus(status),
296 NT_STATUS_NO_LOGON_SERVERS)) {
297 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
298 ads_destroy(&ads);
299 return status;
302 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
303 need_password = true;
304 second_time = true;
305 goto retry;
306 } else {
307 ads_destroy(&ads);
308 return status;
312 /* when contacting our own domain, make sure we use the closest DC.
313 * This is done by reconnecting to ADS because only the first call to
314 * ads_connect will give us our own sitename */
316 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
318 tried_closest_dc = true; /* avoid loop */
320 if (!ads_closest_dc(ads)) {
322 namecache_delete(ads->server.realm, 0x1C);
323 namecache_delete(ads->server.workgroup, 0x1C);
325 ads_destroy(&ads);
326 ads = NULL;
328 goto retry_connect;
332 *ads_ret = ads;
333 return status;
336 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
338 return ads_startup_int(c, only_own_domain, 0, ads);
341 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
343 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
347 Check to see if connection can be made via ads.
348 ads_startup() stores the password in opt_password if it needs to so
349 that rpc or rap can use it without re-prompting.
351 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
353 ADS_STRUCT *ads;
354 ADS_STATUS status;
356 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
357 return -1;
360 ads->auth.flags |= ADS_AUTH_NO_BIND;
362 status = ads_connect(ads);
363 if ( !ADS_ERR_OK(status) ) {
364 return -1;
367 ads_destroy(&ads);
368 return 0;
371 int net_ads_check_our_domain(struct net_context *c)
373 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
376 int net_ads_check(struct net_context *c)
378 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
382 determine the netbios workgroup name for a domain
384 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
386 ADS_STRUCT *ads;
387 char addr[INET6_ADDRSTRLEN];
388 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
390 if (c->display_usage) {
391 d_printf ("%s\n"
392 "net ads workgroup\n"
393 " %s\n",
394 _("Usage:"),
395 _("Print the workgroup name"));
396 return 0;
399 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
400 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
401 return -1;
404 if (!ads->config.realm) {
405 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
406 ads->ldap.port = 389;
409 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
410 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
411 d_fprintf(stderr, _("CLDAP query failed!\n"));
412 ads_destroy(&ads);
413 return -1;
416 d_printf(_("Workgroup: %s\n"), reply.domain_name);
418 ads_destroy(&ads);
420 return 0;
425 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
427 char **disp_fields = (char **) data_area;
429 if (!field) { /* must be end of record */
430 if (disp_fields[0]) {
431 if (!strchr_m(disp_fields[0], '$')) {
432 if (disp_fields[1])
433 d_printf("%-21.21s %s\n",
434 disp_fields[0], disp_fields[1]);
435 else
436 d_printf("%s\n", disp_fields[0]);
439 SAFE_FREE(disp_fields[0]);
440 SAFE_FREE(disp_fields[1]);
441 return true;
443 if (!values) /* must be new field, indicate string field */
444 return true;
445 if (StrCaseCmp(field, "sAMAccountName") == 0) {
446 disp_fields[0] = SMB_STRDUP((char *) values[0]);
448 if (StrCaseCmp(field, "description") == 0)
449 disp_fields[1] = SMB_STRDUP((char *) values[0]);
450 return true;
453 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
455 return net_user_usage(c, argc, argv);
458 static int ads_user_add(struct net_context *c, int argc, const char **argv)
460 ADS_STRUCT *ads;
461 ADS_STATUS status;
462 char *upn, *userdn;
463 LDAPMessage *res=NULL;
464 int rc = -1;
465 char *ou_str = NULL;
467 if (argc < 1 || c->display_usage)
468 return net_ads_user_usage(c, argc, argv);
470 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
471 return -1;
474 status = ads_find_user_acct(ads, &res, argv[0]);
476 if (!ADS_ERR_OK(status)) {
477 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
478 goto done;
481 if (ads_count_replies(ads, res)) {
482 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
483 argv[0]);
484 goto done;
487 if (c->opt_container) {
488 ou_str = SMB_STRDUP(c->opt_container);
489 } else {
490 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
493 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
495 if (!ADS_ERR_OK(status)) {
496 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
497 ads_errstr(status));
498 goto done;
501 /* if no password is to be set, we're done */
502 if (argc == 1) {
503 d_printf(_("User %s added\n"), argv[0]);
504 rc = 0;
505 goto done;
508 /* try setting the password */
509 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
510 goto done;
512 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
513 ads->auth.time_offset);
514 SAFE_FREE(upn);
515 if (ADS_ERR_OK(status)) {
516 d_printf(_("User %s added\n"), argv[0]);
517 rc = 0;
518 goto done;
521 /* password didn't set, delete account */
522 d_fprintf(stderr, _("Could not add user %s. "
523 "Error setting password %s\n"),
524 argv[0], ads_errstr(status));
525 ads_msgfree(ads, res);
526 status=ads_find_user_acct(ads, &res, argv[0]);
527 if (ADS_ERR_OK(status)) {
528 userdn = ads_get_dn(ads, talloc_tos(), res);
529 ads_del_dn(ads, userdn);
530 TALLOC_FREE(userdn);
533 done:
534 if (res)
535 ads_msgfree(ads, res);
536 ads_destroy(&ads);
537 SAFE_FREE(ou_str);
538 return rc;
541 static int ads_user_info(struct net_context *c, int argc, const char **argv)
543 ADS_STRUCT *ads = NULL;
544 ADS_STATUS rc;
545 LDAPMessage *res = NULL;
546 TALLOC_CTX *frame;
547 int ret = 0;
548 wbcErr wbc_status;
549 const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
550 char *searchstring=NULL;
551 char **grouplist;
552 char *primary_group;
553 char *escaped_user;
554 struct dom_sid primary_group_sid;
555 uint32_t group_rid;
556 enum wbcSidType type;
558 if (argc < 1 || c->display_usage) {
559 return net_ads_user_usage(c, argc, argv);
562 frame = talloc_new(talloc_tos());
563 if (frame == NULL) {
564 return -1;
567 escaped_user = escape_ldap_string(frame, argv[0]);
568 if (!escaped_user) {
569 d_fprintf(stderr,
570 _("ads_user_info: failed to escape user %s\n"),
571 argv[0]);
572 return -1;
575 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
576 ret = -1;
577 goto error;
580 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
581 ret =-1;
582 goto error;
584 rc = ads_search(ads, &res, searchstring, attrs);
585 SAFE_FREE(searchstring);
587 if (!ADS_ERR_OK(rc)) {
588 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(rc));
589 ret = -1;
590 goto error;
593 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
594 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
595 ret = -1;
596 goto error;
599 rc = ads_domain_sid(ads, &primary_group_sid);
600 if (!ADS_ERR_OK(rc)) {
601 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(rc));
602 ret = -1;
603 goto error;
606 sid_append_rid(&primary_group_sid, group_rid);
608 wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
609 NULL, /* don't look up domain */
610 &primary_group,
611 &type);
612 if (!WBC_ERROR_IS_OK(wbc_status)) {
613 d_fprintf(stderr, "wbcLookupSid: %s\n",
614 wbcErrorString(wbc_status));
615 ret = -1;
616 goto error;
619 d_printf("%s\n", primary_group);
621 wbcFreeMemory(primary_group);
623 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
624 (LDAPMessage *)res, "memberOf");
626 if (grouplist) {
627 int i;
628 char **groupname;
629 for (i=0;grouplist[i];i++) {
630 groupname = ldap_explode_dn(grouplist[i], 1);
631 d_printf("%s\n", groupname[0]);
632 ldap_value_free(groupname);
634 ldap_value_free(grouplist);
637 error:
638 if (res) ads_msgfree(ads, res);
639 if (ads) ads_destroy(&ads);
640 TALLOC_FREE(frame);
641 return ret;
644 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
646 ADS_STRUCT *ads;
647 ADS_STATUS rc;
648 LDAPMessage *res = NULL;
649 char *userdn;
651 if (argc < 1) {
652 return net_ads_user_usage(c, argc, argv);
655 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
656 return -1;
659 rc = ads_find_user_acct(ads, &res, argv[0]);
660 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
661 d_printf(_("User %s does not exist.\n"), argv[0]);
662 ads_msgfree(ads, res);
663 ads_destroy(&ads);
664 return -1;
666 userdn = ads_get_dn(ads, talloc_tos(), res);
667 ads_msgfree(ads, res);
668 rc = ads_del_dn(ads, userdn);
669 TALLOC_FREE(userdn);
670 if (ADS_ERR_OK(rc)) {
671 d_printf(_("User %s deleted\n"), argv[0]);
672 ads_destroy(&ads);
673 return 0;
675 d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
676 ads_errstr(rc));
677 ads_destroy(&ads);
678 return -1;
681 int net_ads_user(struct net_context *c, int argc, const char **argv)
683 struct functable func[] = {
685 "add",
686 ads_user_add,
687 NET_TRANSPORT_ADS,
688 N_("Add an AD user"),
689 N_("net ads user add\n"
690 " Add an AD user")
693 "info",
694 ads_user_info,
695 NET_TRANSPORT_ADS,
696 N_("Display information about an AD user"),
697 N_("net ads user info\n"
698 " Display information about an AD user")
701 "delete",
702 ads_user_delete,
703 NET_TRANSPORT_ADS,
704 N_("Delete an AD user"),
705 N_("net ads user delete\n"
706 " Delete an AD user")
708 {NULL, NULL, 0, NULL, NULL}
710 ADS_STRUCT *ads;
711 ADS_STATUS rc;
712 const char *shortattrs[] = {"sAMAccountName", NULL};
713 const char *longattrs[] = {"sAMAccountName", "description", NULL};
714 char *disp_fields[2] = {NULL, NULL};
716 if (argc == 0) {
717 if (c->display_usage) {
718 d_printf( "%s\n"
719 "net ads user\n"
720 " %s\n",
721 _("Usage:"),
722 _("List AD users"));
723 net_display_usage_from_functable(func);
724 return 0;
727 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
728 return -1;
731 if (c->opt_long_list_entries)
732 d_printf(_("\nUser name Comment"
733 "\n-----------------------------\n"));
735 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
736 LDAP_SCOPE_SUBTREE,
737 "(objectCategory=user)",
738 c->opt_long_list_entries ? longattrs :
739 shortattrs, usergrp_display,
740 disp_fields);
741 ads_destroy(&ads);
742 return ADS_ERR_OK(rc) ? 0 : -1;
745 return net_run_function(c, argc, argv, "net ads user", func);
748 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
750 return net_group_usage(c, argc, argv);
753 static int ads_group_add(struct net_context *c, int argc, const char **argv)
755 ADS_STRUCT *ads;
756 ADS_STATUS status;
757 LDAPMessage *res=NULL;
758 int rc = -1;
759 char *ou_str = NULL;
761 if (argc < 1 || c->display_usage) {
762 return net_ads_group_usage(c, argc, argv);
765 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
766 return -1;
769 status = ads_find_user_acct(ads, &res, argv[0]);
771 if (!ADS_ERR_OK(status)) {
772 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
773 goto done;
776 if (ads_count_replies(ads, res)) {
777 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
778 goto done;
781 if (c->opt_container) {
782 ou_str = SMB_STRDUP(c->opt_container);
783 } else {
784 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
787 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
789 if (ADS_ERR_OK(status)) {
790 d_printf(_("Group %s added\n"), argv[0]);
791 rc = 0;
792 } else {
793 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
794 ads_errstr(status));
797 done:
798 if (res)
799 ads_msgfree(ads, res);
800 ads_destroy(&ads);
801 SAFE_FREE(ou_str);
802 return rc;
805 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
807 ADS_STRUCT *ads;
808 ADS_STATUS rc;
809 LDAPMessage *res = NULL;
810 char *groupdn;
812 if (argc < 1 || c->display_usage) {
813 return net_ads_group_usage(c, argc, argv);
816 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
817 return -1;
820 rc = ads_find_user_acct(ads, &res, argv[0]);
821 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
822 d_printf(_("Group %s does not exist.\n"), argv[0]);
823 ads_msgfree(ads, res);
824 ads_destroy(&ads);
825 return -1;
827 groupdn = ads_get_dn(ads, talloc_tos(), res);
828 ads_msgfree(ads, res);
829 rc = ads_del_dn(ads, groupdn);
830 TALLOC_FREE(groupdn);
831 if (ADS_ERR_OK(rc)) {
832 d_printf(_("Group %s deleted\n"), argv[0]);
833 ads_destroy(&ads);
834 return 0;
836 d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
837 ads_errstr(rc));
838 ads_destroy(&ads);
839 return -1;
842 int net_ads_group(struct net_context *c, int argc, const char **argv)
844 struct functable func[] = {
846 "add",
847 ads_group_add,
848 NET_TRANSPORT_ADS,
849 N_("Add an AD group"),
850 N_("net ads group add\n"
851 " Add an AD group")
854 "delete",
855 ads_group_delete,
856 NET_TRANSPORT_ADS,
857 N_("Delete an AD group"),
858 N_("net ads group delete\n"
859 " Delete an AD group")
861 {NULL, NULL, 0, NULL, NULL}
863 ADS_STRUCT *ads;
864 ADS_STATUS rc;
865 const char *shortattrs[] = {"sAMAccountName", NULL};
866 const char *longattrs[] = {"sAMAccountName", "description", NULL};
867 char *disp_fields[2] = {NULL, NULL};
869 if (argc == 0) {
870 if (c->display_usage) {
871 d_printf( "%s\n"
872 "net ads group\n"
873 " %s\n",
874 _("Usage:"),
875 _("List AD groups"));
876 net_display_usage_from_functable(func);
877 return 0;
880 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
881 return -1;
884 if (c->opt_long_list_entries)
885 d_printf(_("\nGroup name Comment"
886 "\n-----------------------------\n"));
887 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
888 LDAP_SCOPE_SUBTREE,
889 "(objectCategory=group)",
890 c->opt_long_list_entries ? longattrs :
891 shortattrs, usergrp_display,
892 disp_fields);
894 ads_destroy(&ads);
895 return ADS_ERR_OK(rc) ? 0 : -1;
897 return net_run_function(c, argc, argv, "net ads group", func);
900 static int net_ads_status(struct net_context *c, int argc, const char **argv)
902 ADS_STRUCT *ads;
903 ADS_STATUS rc;
904 LDAPMessage *res;
906 if (c->display_usage) {
907 d_printf( "%s\n"
908 "net ads status\n"
909 " %s\n",
910 _("Usage:"),
911 _("Display machine account details"));
912 return 0;
915 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
916 return -1;
919 rc = ads_find_machine_acct(ads, &res, global_myname());
920 if (!ADS_ERR_OK(rc)) {
921 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
922 ads_destroy(&ads);
923 return -1;
926 if (ads_count_replies(ads, res) == 0) {
927 d_fprintf(stderr, _("No machine account for '%s' found\n"), global_myname());
928 ads_destroy(&ads);
929 return -1;
932 ads_dump(ads, res);
933 ads_destroy(&ads);
934 return 0;
937 /*******************************************************************
938 Leave an AD domain. Windows XP disables the machine account.
939 We'll try the same. The old code would do an LDAP delete.
940 That only worked using the machine creds because added the machine
941 with full control to the computer object's ACL.
942 *******************************************************************/
944 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
946 TALLOC_CTX *ctx;
947 struct libnet_UnjoinCtx *r = NULL;
948 WERROR werr;
950 if (c->display_usage) {
951 d_printf( "%s\n"
952 "net ads leave\n"
953 " %s\n",
954 _("Usage:"),
955 _("Leave an AD domain"));
956 return 0;
959 if (!*lp_realm()) {
960 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
961 return -1;
964 if (!(ctx = talloc_init("net_ads_leave"))) {
965 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
966 return -1;
969 if (!c->opt_kerberos) {
970 use_in_memory_ccache();
973 if (!c->msg_ctx) {
974 d_fprintf(stderr, _("Could not initialise message context. "
975 "Try running as root\n"));
976 return -1;
979 werr = libnet_init_UnjoinCtx(ctx, &r);
980 if (!W_ERROR_IS_OK(werr)) {
981 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
982 return -1;
985 r->in.debug = true;
986 r->in.use_kerberos = c->opt_kerberos;
987 r->in.dc_name = c->opt_host;
988 r->in.domain_name = lp_realm();
989 r->in.admin_account = c->opt_user_name;
990 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
991 r->in.modify_config = lp_config_backend_is_registry();
993 /* Try to delete it, but if that fails, disable it. The
994 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
995 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
996 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
997 r->in.delete_machine_account = true;
998 r->in.msg_ctx = c->msg_ctx;
1000 werr = libnet_Unjoin(ctx, r);
1001 if (!W_ERROR_IS_OK(werr)) {
1002 d_printf(_("Failed to leave domain: %s\n"),
1003 r->out.error_string ? r->out.error_string :
1004 get_friendly_werror_msg(werr));
1005 goto done;
1008 if (r->out.deleted_machine_account) {
1009 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1010 r->in.machine_name, r->out.dns_domain_name);
1011 goto done;
1014 /* We couldn't delete it - see if the disable succeeded. */
1015 if (r->out.disabled_machine_account) {
1016 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1017 r->in.machine_name, r->out.dns_domain_name);
1018 werr = WERR_OK;
1019 goto done;
1022 /* Based on what we requseted, we shouldn't get here, but if
1023 we did, it means the secrets were removed, and therefore
1024 we have left the domain */
1025 d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1026 r->in.machine_name, r->out.dns_domain_name);
1028 done:
1029 TALLOC_FREE(r);
1030 TALLOC_FREE(ctx);
1032 if (W_ERROR_IS_OK(werr)) {
1033 return 0;
1036 return -1;
1039 static NTSTATUS net_ads_join_ok(struct net_context *c)
1041 ADS_STRUCT *ads = NULL;
1042 ADS_STATUS status;
1043 fstring dc_name;
1044 struct sockaddr_storage dcip;
1046 if (!secrets_init()) {
1047 DEBUG(1,("Failed to initialise secrets database\n"));
1048 return NT_STATUS_ACCESS_DENIED;
1051 net_use_krb_machine_account(c);
1053 get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1055 status = ads_startup(c, true, &ads);
1056 if (!ADS_ERR_OK(status)) {
1057 return ads_ntstatus(status);
1060 ads_destroy(&ads);
1061 return NT_STATUS_OK;
1065 check that an existing join is OK
1067 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1069 NTSTATUS status;
1070 use_in_memory_ccache();
1072 if (c->display_usage) {
1073 d_printf( "%s\n"
1074 "net ads testjoin\n"
1075 " %s\n",
1076 _("Usage:"),
1077 _("Test if the existing join is ok"));
1078 return 0;
1081 /* Display success or failure */
1082 status = net_ads_join_ok(c);
1083 if (!NT_STATUS_IS_OK(status)) {
1084 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1085 get_friendly_nt_error_msg(status));
1086 return -1;
1089 printf(_("Join is OK\n"));
1090 return 0;
1093 /*******************************************************************
1094 Simple configu checks before beginning the join
1095 ********************************************************************/
1097 static WERROR check_ads_config( void )
1099 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1100 d_printf(_("Host is not configured as a member server.\n"));
1101 return WERR_INVALID_DOMAIN_ROLE;
1104 if (strlen(global_myname()) > 15) {
1105 d_printf(_("Our netbios name can be at most 15 chars long, "
1106 "\"%s\" is %u chars long\n"), global_myname(),
1107 (unsigned int)strlen(global_myname()));
1108 return WERR_INVALID_COMPUTERNAME;
1111 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1112 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1113 "join to succeed.\n"), get_dyn_CONFIGFILE());
1114 return WERR_INVALID_PARAM;
1117 return WERR_OK;
1120 /*******************************************************************
1121 Send a DNS update request
1122 *******************************************************************/
1124 #if defined(WITH_DNS_UPDATES)
1125 #include "../lib/addns/dns.h"
1126 DNS_ERROR DoDNSUpdate(char *pszServerName,
1127 const char *pszDomainName, const char *pszHostName,
1128 const struct sockaddr_storage *sslist,
1129 size_t num_addrs );
1131 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1132 const char *machine_name,
1133 const struct sockaddr_storage *addrs,
1134 int num_addrs)
1136 struct dns_rr_ns *nameservers = NULL;
1137 int ns_count = 0, i;
1138 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1139 DNS_ERROR dns_err;
1140 fstring dns_server;
1141 const char *dnsdomain = NULL;
1142 char *root_domain = NULL;
1144 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1145 d_printf(_("No DNS domain configured for %s. "
1146 "Unable to perform DNS Update.\n"), machine_name);
1147 status = NT_STATUS_INVALID_PARAMETER;
1148 goto done;
1150 dnsdomain++;
1152 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1153 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1154 /* Child domains often do not have NS records. Look
1155 for the NS record for the forest root domain
1156 (rootDomainNamingContext in therootDSE) */
1158 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1159 LDAPMessage *msg = NULL;
1160 char *root_dn;
1161 ADS_STATUS ads_status;
1163 if ( !ads->ldap.ld ) {
1164 ads_status = ads_connect( ads );
1165 if ( !ADS_ERR_OK(ads_status) ) {
1166 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1167 goto done;
1171 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1172 "(objectclass=*)", rootname_attrs, &msg);
1173 if (!ADS_ERR_OK(ads_status)) {
1174 goto done;
1177 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1178 if ( !root_dn ) {
1179 ads_msgfree( ads, msg );
1180 goto done;
1183 root_domain = ads_build_domain( root_dn );
1185 /* cleanup */
1186 ads_msgfree( ads, msg );
1188 /* try again for NS servers */
1190 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1192 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1193 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1194 "realm\n", ads->config.realm));
1195 goto done;
1198 dnsdomain = root_domain;
1202 for (i=0; i < ns_count; i++) {
1204 /* Now perform the dns update - we'll try non-secure and if we fail,
1205 we'll follow it up with a secure update */
1207 fstrcpy( dns_server, nameservers[i].hostname );
1209 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1210 if (ERR_DNS_IS_OK(dns_err)) {
1211 status = NT_STATUS_OK;
1212 goto done;
1215 if (ERR_DNS_EQUAL(dns_err, ERROR_DNS_INVALID_NAME_SERVER) ||
1216 ERR_DNS_EQUAL(dns_err, ERROR_DNS_CONNECTION_FAILED) ||
1217 ERR_DNS_EQUAL(dns_err, ERROR_DNS_SOCKET_ERROR)) {
1218 DEBUG(1,("retrying DNS update with next nameserver after receiving %s\n",
1219 dns_errstr(dns_err)));
1220 continue;
1223 d_printf(_("DNS Update for %s failed: %s\n"),
1224 machine_name, dns_errstr(dns_err));
1225 status = NT_STATUS_UNSUCCESSFUL;
1226 goto done;
1229 done:
1231 SAFE_FREE( root_domain );
1233 return status;
1236 static NTSTATUS net_update_dns_ext(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads,
1237 const char *hostname,
1238 struct sockaddr_storage *iplist,
1239 int num_addrs)
1241 struct sockaddr_storage *iplist_alloc = NULL;
1242 fstring machine_name;
1243 NTSTATUS status;
1245 if (hostname) {
1246 fstrcpy(machine_name, hostname);
1247 } else {
1248 name_to_fqdn( machine_name, global_myname() );
1250 strlower_m( machine_name );
1252 if (num_addrs == 0 || iplist == NULL) {
1254 * Get our ip address
1255 * (not the 127.0.0.x address but a real ip address)
1257 num_addrs = get_my_ip_address(&iplist_alloc);
1258 if ( num_addrs <= 0 ) {
1259 DEBUG(4, ("net_update_dns_ext: Failed to find my "
1260 "non-loopback IP addresses!\n"));
1261 return NT_STATUS_INVALID_PARAMETER;
1263 iplist = iplist_alloc;
1266 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1267 iplist, num_addrs);
1269 SAFE_FREE(iplist_alloc);
1270 return status;
1273 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, const char *hostname)
1275 NTSTATUS status;
1277 status = net_update_dns_ext(mem_ctx, ads, hostname, NULL, 0);
1278 return status;
1280 #endif
1283 /*******************************************************************
1284 ********************************************************************/
1286 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1288 d_printf(_("net ads join [options]\n"
1289 "Valid options:\n"));
1290 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1291 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1292 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1293 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1294 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1295 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1296 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1297 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1298 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1299 " NB: osName and osVer must be specified together for either to take effect.\n"
1300 " Also, the operatingSystemService attribute is also set when along with\n"
1301 " the two other attributes.\n"));
1303 return -1;
1306 /*******************************************************************
1307 ********************************************************************/
1309 int net_ads_join(struct net_context *c, int argc, const char **argv)
1311 TALLOC_CTX *ctx = NULL;
1312 struct libnet_JoinCtx *r = NULL;
1313 const char *domain = lp_realm();
1314 WERROR werr = WERR_SETUP_NOT_JOINED;
1315 bool createupn = false;
1316 const char *machineupn = NULL;
1317 const char *create_in_ou = NULL;
1318 int i;
1319 const char *os_name = NULL;
1320 const char *os_version = NULL;
1321 bool modify_config = lp_config_backend_is_registry();
1323 if (c->display_usage)
1324 return net_ads_join_usage(c, argc, argv);
1326 if (!modify_config) {
1328 werr = check_ads_config();
1329 if (!W_ERROR_IS_OK(werr)) {
1330 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1331 goto fail;
1335 if (!(ctx = talloc_init("net_ads_join"))) {
1336 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1337 werr = WERR_NOMEM;
1338 goto fail;
1341 if (!c->opt_kerberos) {
1342 use_in_memory_ccache();
1345 werr = libnet_init_JoinCtx(ctx, &r);
1346 if (!W_ERROR_IS_OK(werr)) {
1347 goto fail;
1350 /* process additional command line args */
1352 for ( i=0; i<argc; i++ ) {
1353 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1354 createupn = true;
1355 machineupn = get_string_param(argv[i]);
1357 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1358 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1359 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1360 werr = WERR_INVALID_PARAM;
1361 goto fail;
1364 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1365 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1366 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1367 werr = WERR_INVALID_PARAM;
1368 goto fail;
1371 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1372 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1373 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1374 werr = WERR_INVALID_PARAM;
1375 goto fail;
1378 else {
1379 domain = argv[i];
1383 if (!*domain) {
1384 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1385 werr = WERR_INVALID_PARAM;
1386 goto fail;
1389 if (!c->msg_ctx) {
1390 d_fprintf(stderr, _("Could not initialise message context. "
1391 "Try running as root\n"));
1392 werr = WERR_ACCESS_DENIED;
1393 goto fail;
1396 /* Do the domain join here */
1398 r->in.domain_name = domain;
1399 r->in.create_upn = createupn;
1400 r->in.upn = machineupn;
1401 r->in.account_ou = create_in_ou;
1402 r->in.os_name = os_name;
1403 r->in.os_version = os_version;
1404 r->in.dc_name = c->opt_host;
1405 r->in.admin_account = c->opt_user_name;
1406 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1407 r->in.debug = true;
1408 r->in.use_kerberos = c->opt_kerberos;
1409 r->in.modify_config = modify_config;
1410 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1411 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1412 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1413 r->in.msg_ctx = c->msg_ctx;
1415 werr = libnet_Join(ctx, r);
1416 if (W_ERROR_EQUAL(werr, WERR_DCNOTFOUND) &&
1417 strequal(domain, lp_realm())) {
1418 r->in.domain_name = lp_workgroup();
1419 werr = libnet_Join(ctx, r);
1421 if (!W_ERROR_IS_OK(werr)) {
1422 goto fail;
1425 /* Check the short name of the domain */
1427 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1428 d_printf(_("The workgroup in %s does not match the short\n"
1429 "domain name obtained from the server.\n"
1430 "Using the name [%s] from the server.\n"
1431 "You should set \"workgroup = %s\" in %s.\n"),
1432 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1433 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1436 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1438 if (r->out.dns_domain_name) {
1439 d_printf(_("Joined '%s' to realm '%s'\n"), r->in.machine_name,
1440 r->out.dns_domain_name);
1441 } else {
1442 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1443 r->out.netbios_domain_name);
1446 #if defined(WITH_DNS_UPDATES)
1448 * In a clustered environment, don't do dynamic dns updates:
1449 * Registering the set of ip addresses that are assigned to
1450 * the interfaces of the node that performs the join does usually
1451 * not have the desired effect, since the local interfaces do not
1452 * carry the complete set of the cluster's public IP addresses.
1453 * And it can also contain internal addresses that should not
1454 * be visible to the outside at all.
1455 * In order to do dns updates in a clustererd setup, use
1456 * net ads dns register.
1458 if (lp_clustering()) {
1459 d_fprintf(stderr, _("Not doing automatic DNS update in a"
1460 "clustered setup.\n"));
1461 goto done;
1464 if (r->out.domain_is_ad) {
1465 /* We enter this block with user creds */
1466 ADS_STRUCT *ads_dns = NULL;
1468 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1469 /* kinit with the machine password */
1471 use_in_memory_ccache();
1472 if (asprintf( &ads_dns->auth.user_name, "%s$", global_myname()) == -1) {
1473 goto fail;
1475 ads_dns->auth.password = secrets_fetch_machine_password(
1476 r->out.netbios_domain_name, NULL, NULL );
1477 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1478 strupper_m(ads_dns->auth.realm );
1479 ads_kinit_password( ads_dns );
1482 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns, NULL)) ) {
1483 d_fprintf( stderr, _("DNS update failed!\n") );
1486 /* exit from this block using machine creds */
1487 ads_destroy(&ads_dns);
1490 done:
1491 #endif
1493 TALLOC_FREE(r);
1494 TALLOC_FREE( ctx );
1496 return 0;
1498 fail:
1499 /* issue an overall failure message at the end. */
1500 d_printf(_("Failed to join domain: %s\n"),
1501 r && r->out.error_string ? r->out.error_string :
1502 get_friendly_werror_msg(werr));
1503 TALLOC_FREE( ctx );
1505 return -1;
1508 /*******************************************************************
1509 ********************************************************************/
1511 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1513 #if defined(WITH_DNS_UPDATES)
1514 ADS_STRUCT *ads;
1515 ADS_STATUS status;
1516 NTSTATUS ntstatus;
1517 TALLOC_CTX *ctx;
1518 const char *hostname = NULL;
1519 const char **addrs_list = NULL;
1520 struct sockaddr_storage *addrs = NULL;
1521 int num_addrs = 0;
1522 int count;
1524 #ifdef DEVELOPER
1525 talloc_enable_leak_report();
1526 #endif
1528 if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
1529 d_fprintf(stderr, _("Refusing DNS updates with automatic "
1530 "detection of addresses in a clustered "
1531 "setup.\n"));
1532 c->display_usage = true;
1535 if (c->display_usage) {
1536 d_printf( "%s\n"
1537 "net ads dns register [hostname [IP [IP...]]]\n"
1538 " %s\n",
1539 _("Usage:"),
1540 _("Register hostname with DNS\n"));
1541 return -1;
1544 if (!(ctx = talloc_init("net_ads_dns"))) {
1545 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1546 return -1;
1549 if (argc >= 1) {
1550 hostname = argv[0];
1553 if (argc > 1) {
1554 num_addrs = argc - 1;
1555 addrs_list = &argv[1];
1556 } else if (lp_clustering()) {
1557 addrs_list = lp_cluster_addresses();
1558 num_addrs = str_list_length(addrs_list);
1561 if (num_addrs > 0) {
1562 addrs = talloc_zero_array(ctx, struct sockaddr_storage, num_addrs);
1563 if (addrs == NULL) {
1564 d_fprintf(stderr, _("Error allocating memory!\n"));
1565 talloc_free(ctx);
1566 return -1;
1570 for (count = 0; count < num_addrs; count++) {
1571 if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
1572 d_fprintf(stderr, "%s '%s'.\n",
1573 _("Cannot interpret address"),
1574 addrs_list[count]);
1575 talloc_free(ctx);
1576 return -1;
1580 status = ads_startup(c, true, &ads);
1581 if ( !ADS_ERR_OK(status) ) {
1582 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1583 TALLOC_FREE(ctx);
1584 return -1;
1587 ntstatus = net_update_dns_ext(ctx, ads, hostname, addrs, num_addrs);
1588 if (!NT_STATUS_IS_OK(ntstatus)) {
1589 d_fprintf( stderr, _("DNS update failed!\n") );
1590 ads_destroy( &ads );
1591 TALLOC_FREE( ctx );
1592 return -1;
1595 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1597 ads_destroy(&ads);
1598 TALLOC_FREE( ctx );
1600 return 0;
1601 #else
1602 d_fprintf(stderr,
1603 _("DNS update support not enabled at compile time!\n"));
1604 return -1;
1605 #endif
1608 #if defined(WITH_DNS_UPDATES)
1609 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1610 #endif
1612 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1614 #if defined(WITH_DNS_UPDATES)
1615 DNS_ERROR err;
1617 #ifdef DEVELOPER
1618 talloc_enable_leak_report();
1619 #endif
1621 if (argc != 2 || c->display_usage) {
1622 d_printf( "%s\n"
1623 " %s\n"
1624 " %s\n",
1625 _("Usage:"),
1626 _("net ads dns gethostbyname <server> <name>\n"),
1627 _(" Look up hostname from the AD\n"
1628 " server\tName server to use\n"
1629 " name\tName to look up\n"));
1630 return -1;
1633 err = do_gethostbyname(argv[0], argv[1]);
1635 d_printf(_("do_gethostbyname returned %s (%d)\n"),
1636 dns_errstr(err), ERROR_DNS_V(err));
1637 #endif
1638 return 0;
1641 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1643 struct functable func[] = {
1645 "register",
1646 net_ads_dns_register,
1647 NET_TRANSPORT_ADS,
1648 N_("Add host dns entry to AD"),
1649 N_("net ads dns register\n"
1650 " Add host dns entry to AD")
1653 "gethostbyname",
1654 net_ads_dns_gethostbyname,
1655 NET_TRANSPORT_ADS,
1656 N_("Look up host"),
1657 N_("net ads dns gethostbyname\n"
1658 " Look up host")
1660 {NULL, NULL, 0, NULL, NULL}
1663 return net_run_function(c, argc, argv, "net ads dns", func);
1666 /*******************************************************************
1667 ********************************************************************/
1669 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1671 d_printf(_(
1672 "\nnet ads printer search <printer>"
1673 "\n\tsearch for a printer in the directory\n"
1674 "\nnet ads printer info <printer> <server>"
1675 "\n\tlookup info in directory for printer on server"
1676 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1677 "\nnet ads printer publish <printername>"
1678 "\n\tpublish printer in directory"
1679 "\n\t(note: printer name is required)\n"
1680 "\nnet ads printer remove <printername>"
1681 "\n\tremove printer from directory"
1682 "\n\t(note: printer name is required)\n"));
1683 return -1;
1686 /*******************************************************************
1687 ********************************************************************/
1689 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1691 ADS_STRUCT *ads;
1692 ADS_STATUS rc;
1693 LDAPMessage *res = NULL;
1695 if (c->display_usage) {
1696 d_printf( "%s\n"
1697 "net ads printer search\n"
1698 " %s\n",
1699 _("Usage:"),
1700 _("List printers in the AD"));
1701 return 0;
1704 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1705 return -1;
1708 rc = ads_find_printers(ads, &res);
1710 if (!ADS_ERR_OK(rc)) {
1711 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
1712 ads_msgfree(ads, res);
1713 ads_destroy(&ads);
1714 return -1;
1717 if (ads_count_replies(ads, res) == 0) {
1718 d_fprintf(stderr, _("No results found\n"));
1719 ads_msgfree(ads, res);
1720 ads_destroy(&ads);
1721 return -1;
1724 ads_dump(ads, res);
1725 ads_msgfree(ads, res);
1726 ads_destroy(&ads);
1727 return 0;
1730 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1732 ADS_STRUCT *ads;
1733 ADS_STATUS rc;
1734 const char *servername, *printername;
1735 LDAPMessage *res = NULL;
1737 if (c->display_usage) {
1738 d_printf("%s\n%s",
1739 _("Usage:"),
1740 _("net ads printer info [printername [servername]]\n"
1741 " Display printer info from AD\n"
1742 " printername\tPrinter name or wildcard\n"
1743 " servername\tName of the print server\n"));
1744 return 0;
1747 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1748 return -1;
1751 if (argc > 0) {
1752 printername = argv[0];
1753 } else {
1754 printername = "*";
1757 if (argc > 1) {
1758 servername = argv[1];
1759 } else {
1760 servername = global_myname();
1763 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1765 if (!ADS_ERR_OK(rc)) {
1766 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
1767 servername, ads_errstr(rc));
1768 ads_msgfree(ads, res);
1769 ads_destroy(&ads);
1770 return -1;
1773 if (ads_count_replies(ads, res) == 0) {
1774 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
1775 ads_msgfree(ads, res);
1776 ads_destroy(&ads);
1777 return -1;
1780 ads_dump(ads, res);
1781 ads_msgfree(ads, res);
1782 ads_destroy(&ads);
1784 return 0;
1787 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1789 ADS_STRUCT *ads;
1790 ADS_STATUS rc;
1791 const char *servername, *printername;
1792 struct cli_state *cli = NULL;
1793 struct rpc_pipe_client *pipe_hnd = NULL;
1794 struct sockaddr_storage server_ss;
1795 NTSTATUS nt_status;
1796 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1797 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1798 char *prt_dn, *srv_dn, **srv_cn;
1799 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1800 LDAPMessage *res = NULL;
1802 if (argc < 1 || c->display_usage) {
1803 d_printf("%s\n%s",
1804 _("Usage:"),
1805 _("net ads printer publish <printername> [servername]\n"
1806 " Publish printer in AD\n"
1807 " printername\tName of the printer\n"
1808 " servername\tName of the print server\n"));
1809 talloc_destroy(mem_ctx);
1810 return -1;
1813 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1814 talloc_destroy(mem_ctx);
1815 return -1;
1818 printername = argv[0];
1820 if (argc == 2) {
1821 servername = argv[1];
1822 } else {
1823 servername = global_myname();
1826 /* Get printer data from SPOOLSS */
1828 resolve_name(servername, &server_ss, 0x20, false);
1830 nt_status = cli_full_connection(&cli, global_myname(), servername,
1831 &server_ss, 0,
1832 "IPC$", "IPC",
1833 c->opt_user_name, c->opt_workgroup,
1834 c->opt_password ? c->opt_password : "",
1835 CLI_FULL_CONNECTION_USE_KERBEROS,
1836 Undefined);
1838 if (NT_STATUS_IS_ERR(nt_status)) {
1839 d_fprintf(stderr, _("Unable to open a connection to %s to "
1840 "obtain data for %s\n"),
1841 servername, printername);
1842 ads_destroy(&ads);
1843 talloc_destroy(mem_ctx);
1844 return -1;
1847 /* Publish on AD server */
1849 ads_find_machine_acct(ads, &res, servername);
1851 if (ads_count_replies(ads, res) == 0) {
1852 d_fprintf(stderr, _("Could not find machine account for server "
1853 "%s\n"),
1854 servername);
1855 ads_destroy(&ads);
1856 talloc_destroy(mem_ctx);
1857 return -1;
1860 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1861 srv_cn = ldap_explode_dn(srv_dn, 1);
1863 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1864 printername_escaped = escape_rdn_val_string_alloc(printername);
1865 if (!srv_cn_escaped || !printername_escaped) {
1866 SAFE_FREE(srv_cn_escaped);
1867 SAFE_FREE(printername_escaped);
1868 d_fprintf(stderr, _("Internal error, out of memory!"));
1869 ads_destroy(&ads);
1870 talloc_destroy(mem_ctx);
1871 return -1;
1874 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1875 SAFE_FREE(srv_cn_escaped);
1876 SAFE_FREE(printername_escaped);
1877 d_fprintf(stderr, _("Internal error, out of memory!"));
1878 ads_destroy(&ads);
1879 talloc_destroy(mem_ctx);
1880 return -1;
1883 SAFE_FREE(srv_cn_escaped);
1884 SAFE_FREE(printername_escaped);
1886 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
1887 if (!NT_STATUS_IS_OK(nt_status)) {
1888 d_fprintf(stderr, _("Unable to open a connection to the spoolss pipe on %s\n"),
1889 servername);
1890 SAFE_FREE(prt_dn);
1891 ads_destroy(&ads);
1892 talloc_destroy(mem_ctx);
1893 return -1;
1896 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1897 printername))) {
1898 SAFE_FREE(prt_dn);
1899 ads_destroy(&ads);
1900 talloc_destroy(mem_ctx);
1901 return -1;
1904 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1905 if (!ADS_ERR_OK(rc)) {
1906 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1907 SAFE_FREE(prt_dn);
1908 ads_destroy(&ads);
1909 talloc_destroy(mem_ctx);
1910 return -1;
1913 d_printf("published printer\n");
1914 SAFE_FREE(prt_dn);
1915 ads_destroy(&ads);
1916 talloc_destroy(mem_ctx);
1918 return 0;
1921 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1923 ADS_STRUCT *ads;
1924 ADS_STATUS rc;
1925 const char *servername;
1926 char *prt_dn;
1927 LDAPMessage *res = NULL;
1929 if (argc < 1 || c->display_usage) {
1930 d_printf("%s\n%s",
1931 _("Usage:"),
1932 _("net ads printer remove <printername> [servername]\n"
1933 " Remove a printer from the AD\n"
1934 " printername\tName of the printer\n"
1935 " servername\tName of the print server\n"));
1936 return -1;
1939 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1940 return -1;
1943 if (argc > 1) {
1944 servername = argv[1];
1945 } else {
1946 servername = global_myname();
1949 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1951 if (!ADS_ERR_OK(rc)) {
1952 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
1953 ads_msgfree(ads, res);
1954 ads_destroy(&ads);
1955 return -1;
1958 if (ads_count_replies(ads, res) == 0) {
1959 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
1960 ads_msgfree(ads, res);
1961 ads_destroy(&ads);
1962 return -1;
1965 prt_dn = ads_get_dn(ads, talloc_tos(), res);
1966 ads_msgfree(ads, res);
1967 rc = ads_del_dn(ads, prt_dn);
1968 TALLOC_FREE(prt_dn);
1970 if (!ADS_ERR_OK(rc)) {
1971 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
1972 ads_destroy(&ads);
1973 return -1;
1976 ads_destroy(&ads);
1977 return 0;
1980 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1982 struct functable func[] = {
1984 "search",
1985 net_ads_printer_search,
1986 NET_TRANSPORT_ADS,
1987 N_("Search for a printer"),
1988 N_("net ads printer search\n"
1989 " Search for a printer")
1992 "info",
1993 net_ads_printer_info,
1994 NET_TRANSPORT_ADS,
1995 N_("Display printer information"),
1996 N_("net ads printer info\n"
1997 " Display printer information")
2000 "publish",
2001 net_ads_printer_publish,
2002 NET_TRANSPORT_ADS,
2003 N_("Publish a printer"),
2004 N_("net ads printer publish\n"
2005 " Publish a printer")
2008 "remove",
2009 net_ads_printer_remove,
2010 NET_TRANSPORT_ADS,
2011 N_("Delete a printer"),
2012 N_("net ads printer remove\n"
2013 " Delete a printer")
2015 {NULL, NULL, 0, NULL, NULL}
2018 return net_run_function(c, argc, argv, "net ads printer", func);
2022 static int net_ads_password(struct net_context *c, int argc, const char **argv)
2024 ADS_STRUCT *ads;
2025 const char *auth_principal = c->opt_user_name;
2026 const char *auth_password = c->opt_password;
2027 char *realm = NULL;
2028 char *new_password = NULL;
2029 char *chr, *prompt;
2030 const char *user;
2031 ADS_STATUS ret;
2033 if (c->display_usage) {
2034 d_printf("%s\n%s",
2035 _("Usage:"),
2036 _("net ads password <username>\n"
2037 " Change password for user\n"
2038 " username\tName of user to change password for\n"));
2039 return 0;
2042 if (c->opt_user_name == NULL || c->opt_password == NULL) {
2043 d_fprintf(stderr, _("You must supply an administrator "
2044 "username/password\n"));
2045 return -1;
2048 if (argc < 1) {
2049 d_fprintf(stderr, _("ERROR: You must say which username to "
2050 "change password for\n"));
2051 return -1;
2054 user = argv[0];
2055 if (!strchr_m(user, '@')) {
2056 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
2057 return -1;
2059 user = chr;
2062 use_in_memory_ccache();
2063 chr = strchr_m(auth_principal, '@');
2064 if (chr) {
2065 realm = ++chr;
2066 } else {
2067 realm = lp_realm();
2070 /* use the realm so we can eventually change passwords for users
2071 in realms other than default */
2072 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
2073 return -1;
2076 /* we don't actually need a full connect, but it's the easy way to
2077 fill in the KDC's addresss */
2078 ads_connect(ads);
2080 if (!ads->config.realm) {
2081 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
2082 ads_destroy(&ads);
2083 return -1;
2086 if (argv[1]) {
2087 new_password = (char *)argv[1];
2088 } else {
2089 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
2090 return -1;
2092 new_password = getpass(prompt);
2093 free(prompt);
2096 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2097 auth_password, user, new_password, ads->auth.time_offset);
2098 if (!ADS_ERR_OK(ret)) {
2099 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2100 ads_destroy(&ads);
2101 return -1;
2104 d_printf(_("Password change for %s completed.\n"), user);
2105 ads_destroy(&ads);
2107 return 0;
2110 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2112 ADS_STRUCT *ads;
2113 char *host_principal;
2114 fstring my_name;
2115 ADS_STATUS ret;
2117 if (c->display_usage) {
2118 d_printf( "%s\n"
2119 "net ads changetrustpw\n"
2120 " %s\n",
2121 _("Usage:"),
2122 _("Change the machine account's trust password"));
2123 return 0;
2126 if (!secrets_init()) {
2127 DEBUG(1,("Failed to initialise secrets database\n"));
2128 return -1;
2131 net_use_krb_machine_account(c);
2133 use_in_memory_ccache();
2135 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2136 return -1;
2139 fstrcpy(my_name, global_myname());
2140 strlower_m(my_name);
2141 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2142 ads_destroy(&ads);
2143 return -1;
2145 d_printf(_("Changing password for principal: %s\n"), host_principal);
2147 ret = ads_change_trust_account_password(ads, host_principal);
2149 if (!ADS_ERR_OK(ret)) {
2150 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2151 ads_destroy(&ads);
2152 SAFE_FREE(host_principal);
2153 return -1;
2156 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2158 if (USE_SYSTEM_KEYTAB) {
2159 d_printf(_("Attempting to update system keytab with new password.\n"));
2160 if (ads_keytab_create_default(ads)) {
2161 d_printf(_("Failed to update system keytab.\n"));
2165 ads_destroy(&ads);
2166 SAFE_FREE(host_principal);
2168 return 0;
2172 help for net ads search
2174 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2176 d_printf(_(
2177 "\nnet ads search <expression> <attributes...>\n"
2178 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2179 "The expression is a standard LDAP search expression, and the\n"
2180 "attributes are a list of LDAP fields to show in the results.\n\n"
2181 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2183 net_common_flags_usage(c, argc, argv);
2184 return -1;
2189 general ADS search function. Useful in diagnosing problems in ADS
2191 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2193 ADS_STRUCT *ads;
2194 ADS_STATUS rc;
2195 const char *ldap_exp;
2196 const char **attrs;
2197 LDAPMessage *res = NULL;
2199 if (argc < 1 || c->display_usage) {
2200 return net_ads_search_usage(c, argc, argv);
2203 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2204 return -1;
2207 ldap_exp = argv[0];
2208 attrs = (argv + 1);
2210 rc = ads_do_search_all(ads, ads->config.bind_path,
2211 LDAP_SCOPE_SUBTREE,
2212 ldap_exp, attrs, &res);
2213 if (!ADS_ERR_OK(rc)) {
2214 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2215 ads_destroy(&ads);
2216 return -1;
2219 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2221 /* dump the results */
2222 ads_dump(ads, res);
2224 ads_msgfree(ads, res);
2225 ads_destroy(&ads);
2227 return 0;
2232 help for net ads search
2234 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2236 d_printf(_(
2237 "\nnet ads dn <dn> <attributes...>\n"
2238 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2239 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2240 "to show in the results\n\n"
2241 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2242 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2244 net_common_flags_usage(c, argc, argv);
2245 return -1;
2250 general ADS search function. Useful in diagnosing problems in ADS
2252 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2254 ADS_STRUCT *ads;
2255 ADS_STATUS rc;
2256 const char *dn;
2257 const char **attrs;
2258 LDAPMessage *res = NULL;
2260 if (argc < 1 || c->display_usage) {
2261 return net_ads_dn_usage(c, argc, argv);
2264 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2265 return -1;
2268 dn = argv[0];
2269 attrs = (argv + 1);
2271 rc = ads_do_search_all(ads, dn,
2272 LDAP_SCOPE_BASE,
2273 "(objectclass=*)", attrs, &res);
2274 if (!ADS_ERR_OK(rc)) {
2275 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2276 ads_destroy(&ads);
2277 return -1;
2280 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2282 /* dump the results */
2283 ads_dump(ads, res);
2285 ads_msgfree(ads, res);
2286 ads_destroy(&ads);
2288 return 0;
2292 help for net ads sid search
2294 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2296 d_printf(_(
2297 "\nnet ads sid <sid> <attributes...>\n"
2298 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2299 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2300 "to show in the results\n\n"
2301 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2303 net_common_flags_usage(c, argc, argv);
2304 return -1;
2309 general ADS search function. Useful in diagnosing problems in ADS
2311 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2313 ADS_STRUCT *ads;
2314 ADS_STATUS rc;
2315 const char *sid_string;
2316 const char **attrs;
2317 LDAPMessage *res = NULL;
2318 struct dom_sid sid;
2320 if (argc < 1 || c->display_usage) {
2321 return net_ads_sid_usage(c, argc, argv);
2324 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2325 return -1;
2328 sid_string = argv[0];
2329 attrs = (argv + 1);
2331 if (!string_to_sid(&sid, sid_string)) {
2332 d_fprintf(stderr, _("could not convert sid\n"));
2333 ads_destroy(&ads);
2334 return -1;
2337 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2338 if (!ADS_ERR_OK(rc)) {
2339 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2340 ads_destroy(&ads);
2341 return -1;
2344 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2346 /* dump the results */
2347 ads_dump(ads, res);
2349 ads_msgfree(ads, res);
2350 ads_destroy(&ads);
2352 return 0;
2355 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2357 int ret;
2358 ADS_STRUCT *ads;
2360 if (c->display_usage) {
2361 d_printf( "%s\n"
2362 "net ads keytab flush\n"
2363 " %s\n",
2364 _("Usage:"),
2365 _("Delete the whole keytab"));
2366 return 0;
2369 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2370 return -1;
2372 ret = ads_keytab_flush(ads);
2373 ads_destroy(&ads);
2374 return ret;
2377 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2379 int i;
2380 int ret = 0;
2381 ADS_STRUCT *ads;
2383 if (c->display_usage) {
2384 d_printf("%s\n%s",
2385 _("Usage:"),
2386 _("net ads keytab add <principal> [principal ...]\n"
2387 " Add principals to local keytab\n"
2388 " principal\tKerberos principal to add to "
2389 "keytab\n"));
2390 return 0;
2393 d_printf(_("Processing principals to add...\n"));
2394 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2395 return -1;
2397 for (i = 0; i < argc; i++) {
2398 ret |= ads_keytab_add_entry(ads, argv[i]);
2400 ads_destroy(&ads);
2401 return ret;
2404 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2406 ADS_STRUCT *ads;
2407 int ret;
2409 if (c->display_usage) {
2410 d_printf( "%s\n"
2411 "net ads keytab create\n"
2412 " %s\n",
2413 _("Usage:"),
2414 _("Create new default keytab"));
2415 return 0;
2418 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2419 return -1;
2421 ret = ads_keytab_create_default(ads);
2422 ads_destroy(&ads);
2423 return ret;
2426 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2428 const char *keytab = NULL;
2430 if (c->display_usage) {
2431 d_printf("%s\n%s",
2432 _("Usage:"),
2433 _("net ads keytab list [keytab]\n"
2434 " List a local keytab\n"
2435 " keytab\tKeytab to list\n"));
2436 return 0;
2439 if (argc >= 1) {
2440 keytab = argv[0];
2443 return ads_keytab_list(keytab);
2447 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2449 struct functable func[] = {
2451 "add",
2452 net_ads_keytab_add,
2453 NET_TRANSPORT_ADS,
2454 N_("Add a service principal"),
2455 N_("net ads keytab add\n"
2456 " Add a service principal")
2459 "create",
2460 net_ads_keytab_create,
2461 NET_TRANSPORT_ADS,
2462 N_("Create a fresh keytab"),
2463 N_("net ads keytab create\n"
2464 " Create a fresh keytab")
2467 "flush",
2468 net_ads_keytab_flush,
2469 NET_TRANSPORT_ADS,
2470 N_("Remove all keytab entries"),
2471 N_("net ads keytab flush\n"
2472 " Remove all keytab entries")
2475 "list",
2476 net_ads_keytab_list,
2477 NET_TRANSPORT_ADS,
2478 N_("List a keytab"),
2479 N_("net ads keytab list\n"
2480 " List a keytab")
2482 {NULL, NULL, 0, NULL, NULL}
2485 if (!USE_KERBEROS_KEYTAB) {
2486 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2487 "keytab method to use keytab functions.\n"));
2490 return net_run_function(c, argc, argv, "net ads keytab", func);
2493 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2495 int ret = -1;
2497 if (c->display_usage) {
2498 d_printf( "%s\n"
2499 "net ads kerberos renew\n"
2500 " %s\n",
2501 _("Usage:"),
2502 _("Renew TGT from existing credential cache"));
2503 return 0;
2506 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2507 if (ret) {
2508 d_printf(_("failed to renew kerberos ticket: %s\n"),
2509 error_message(ret));
2511 return ret;
2514 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2516 struct PAC_LOGON_INFO *info = NULL;
2517 TALLOC_CTX *mem_ctx = NULL;
2518 NTSTATUS status;
2519 int ret = -1;
2520 const char *impersonate_princ_s = NULL;
2522 if (c->display_usage) {
2523 d_printf( "%s\n"
2524 "net ads kerberos pac\n"
2525 " %s\n",
2526 _("Usage:"),
2527 _("Dump the Kerberos PAC"));
2528 return 0;
2531 mem_ctx = talloc_init("net_ads_kerberos_pac");
2532 if (!mem_ctx) {
2533 goto out;
2536 if (argc > 0) {
2537 impersonate_princ_s = argv[0];
2540 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2542 status = kerberos_return_pac(mem_ctx,
2543 c->opt_user_name,
2544 c->opt_password,
2546 NULL,
2547 NULL,
2548 NULL,
2549 true,
2550 true,
2551 2592000, /* one month */
2552 impersonate_princ_s,
2553 &info);
2554 if (!NT_STATUS_IS_OK(status)) {
2555 d_printf(_("failed to query kerberos PAC: %s\n"),
2556 nt_errstr(status));
2557 goto out;
2560 if (info) {
2561 const char *s;
2562 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2563 d_printf(_("The Pac: %s\n"), s);
2566 ret = 0;
2567 out:
2568 TALLOC_FREE(mem_ctx);
2569 return ret;
2572 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2574 TALLOC_CTX *mem_ctx = NULL;
2575 int ret = -1;
2576 NTSTATUS status;
2578 if (c->display_usage) {
2579 d_printf( "%s\n"
2580 "net ads kerberos kinit\n"
2581 " %s\n",
2582 _("Usage:"),
2583 _("Get Ticket Granting Ticket (TGT) for the user"));
2584 return 0;
2587 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2588 if (!mem_ctx) {
2589 goto out;
2592 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2594 ret = kerberos_kinit_password_ext(c->opt_user_name,
2595 c->opt_password,
2597 NULL,
2598 NULL,
2599 NULL,
2600 true,
2601 true,
2602 2592000, /* one month */
2603 &status);
2604 if (ret) {
2605 d_printf(_("failed to kinit password: %s\n"),
2606 nt_errstr(status));
2608 out:
2609 return ret;
2612 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2614 struct functable func[] = {
2616 "kinit",
2617 net_ads_kerberos_kinit,
2618 NET_TRANSPORT_ADS,
2619 N_("Retrieve Ticket Granting Ticket (TGT)"),
2620 N_("net ads kerberos kinit\n"
2621 " Receive Ticket Granting Ticket (TGT)")
2624 "renew",
2625 net_ads_kerberos_renew,
2626 NET_TRANSPORT_ADS,
2627 N_("Renew Ticket Granting Ticket from credential cache"),
2628 N_("net ads kerberos renew\n"
2629 " Renew Ticket Granting Ticket (TGT) from "
2630 "credential cache")
2633 "pac",
2634 net_ads_kerberos_pac,
2635 NET_TRANSPORT_ADS,
2636 N_("Dump Kerberos PAC"),
2637 N_("net ads kerberos pac\n"
2638 " Dump Kerberos PAC")
2640 {NULL, NULL, 0, NULL, NULL}
2643 return net_run_function(c, argc, argv, "net ads kerberos", func);
2646 int net_ads(struct net_context *c, int argc, const char **argv)
2648 struct functable func[] = {
2650 "info",
2651 net_ads_info,
2652 NET_TRANSPORT_ADS,
2653 N_("Display details on remote ADS server"),
2654 N_("net ads info\n"
2655 " Display details on remote ADS server")
2658 "join",
2659 net_ads_join,
2660 NET_TRANSPORT_ADS,
2661 N_("Join the local machine to ADS realm"),
2662 N_("net ads join\n"
2663 " Join the local machine to ADS realm")
2666 "testjoin",
2667 net_ads_testjoin,
2668 NET_TRANSPORT_ADS,
2669 N_("Validate machine account"),
2670 N_("net ads testjoin\n"
2671 " Validate machine account")
2674 "leave",
2675 net_ads_leave,
2676 NET_TRANSPORT_ADS,
2677 N_("Remove the local machine from ADS"),
2678 N_("net ads leave\n"
2679 " Remove the local machine from ADS")
2682 "status",
2683 net_ads_status,
2684 NET_TRANSPORT_ADS,
2685 N_("Display machine account details"),
2686 N_("net ads status\n"
2687 " Display machine account details")
2690 "user",
2691 net_ads_user,
2692 NET_TRANSPORT_ADS,
2693 N_("List/modify users"),
2694 N_("net ads user\n"
2695 " List/modify users")
2698 "group",
2699 net_ads_group,
2700 NET_TRANSPORT_ADS,
2701 N_("List/modify groups"),
2702 N_("net ads group\n"
2703 " List/modify groups")
2706 "dns",
2707 net_ads_dns,
2708 NET_TRANSPORT_ADS,
2709 N_("Issue dynamic DNS update"),
2710 N_("net ads dns\n"
2711 " Issue dynamic DNS update")
2714 "password",
2715 net_ads_password,
2716 NET_TRANSPORT_ADS,
2717 N_("Change user passwords"),
2718 N_("net ads password\n"
2719 " Change user passwords")
2722 "changetrustpw",
2723 net_ads_changetrustpw,
2724 NET_TRANSPORT_ADS,
2725 N_("Change trust account password"),
2726 N_("net ads changetrustpw\n"
2727 " Change trust account password")
2730 "printer",
2731 net_ads_printer,
2732 NET_TRANSPORT_ADS,
2733 N_("List/modify printer entries"),
2734 N_("net ads printer\n"
2735 " List/modify printer entries")
2738 "search",
2739 net_ads_search,
2740 NET_TRANSPORT_ADS,
2741 N_("Issue LDAP search using filter"),
2742 N_("net ads search\n"
2743 " Issue LDAP search using filter")
2746 "dn",
2747 net_ads_dn,
2748 NET_TRANSPORT_ADS,
2749 N_("Issue LDAP search by DN"),
2750 N_("net ads dn\n"
2751 " Issue LDAP search by DN")
2754 "sid",
2755 net_ads_sid,
2756 NET_TRANSPORT_ADS,
2757 N_("Issue LDAP search by SID"),
2758 N_("net ads sid\n"
2759 " Issue LDAP search by SID")
2762 "workgroup",
2763 net_ads_workgroup,
2764 NET_TRANSPORT_ADS,
2765 N_("Display workgroup name"),
2766 N_("net ads workgroup\n"
2767 " Display the workgroup name")
2770 "lookup",
2771 net_ads_lookup,
2772 NET_TRANSPORT_ADS,
2773 N_("Perfom CLDAP query on DC"),
2774 N_("net ads lookup\n"
2775 " Find the ADS DC using CLDAP lookups")
2778 "keytab",
2779 net_ads_keytab,
2780 NET_TRANSPORT_ADS,
2781 N_("Manage local keytab file"),
2782 N_("net ads keytab\n"
2783 " Manage local keytab file")
2786 "gpo",
2787 net_ads_gpo,
2788 NET_TRANSPORT_ADS,
2789 N_("Manage group policy objects"),
2790 N_("net ads gpo\n"
2791 " Manage group policy objects")
2794 "kerberos",
2795 net_ads_kerberos,
2796 NET_TRANSPORT_ADS,
2797 N_("Manage kerberos keytab"),
2798 N_("net ads kerberos\n"
2799 " Manage kerberos keytab")
2801 {NULL, NULL, 0, NULL, NULL}
2804 return net_run_function(c, argc, argv, "net ads", func);
2807 #else
2809 static int net_ads_noads(void)
2811 d_fprintf(stderr, _("ADS support not compiled in\n"));
2812 return -1;
2815 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2817 return net_ads_noads();
2820 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2822 return net_ads_noads();
2825 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2827 return net_ads_noads();
2830 int net_ads_join(struct net_context *c, int argc, const char **argv)
2832 return net_ads_noads();
2835 int net_ads_user(struct net_context *c, int argc, const char **argv)
2837 return net_ads_noads();
2840 int net_ads_group(struct net_context *c, int argc, const char **argv)
2842 return net_ads_noads();
2845 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
2847 return net_ads_noads();
2850 /* this one shouldn't display a message */
2851 int net_ads_check(struct net_context *c)
2853 return -1;
2856 int net_ads_check_our_domain(struct net_context *c)
2858 return -1;
2861 int net_ads(struct net_context *c, int argc, const char **argv)
2863 return net_ads_noads();
2866 #endif /* WITH_ADS */