s4:libcli/smb2: remove unused variable
[Samba/gebeck_regimport.git] / source3 / utils / net_ads.c
bloba4f1588e515800550b39c3177fdf82cdeaa10c41
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"
42 #ifdef HAVE_ADS
44 /* when we do not have sufficient input parameters to contact a remote domain
45 * we always fall back to our own realm - Guenther*/
47 static const char *assume_own_realm(struct net_context *c)
49 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
50 return lp_realm();
53 return NULL;
57 do a cldap netlogon query
59 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
61 char addr[INET6_ADDRSTRLEN];
62 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
64 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
66 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads->ldap.ss, ads->server.realm, &reply ) ) {
67 d_fprintf(stderr, _("CLDAP query failed!\n"));
68 return -1;
71 d_printf(_("Information for Domain Controller: %s\n\n"),
72 addr);
74 d_printf(_("Response Type: "));
75 switch (reply.command) {
76 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
77 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
78 break;
79 case LOGON_SAM_LOGON_RESPONSE_EX:
80 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
81 break;
82 default:
83 d_printf("0x%x\n", reply.command);
84 break;
87 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
89 d_printf(_("Flags:\n"
90 "\tIs a PDC: %s\n"
91 "\tIs a GC of the forest: %s\n"
92 "\tIs an LDAP server: %s\n"
93 "\tSupports DS: %s\n"
94 "\tIs running a KDC: %s\n"
95 "\tIs running time services: %s\n"
96 "\tIs the closest DC: %s\n"
97 "\tIs writable: %s\n"
98 "\tHas a hardware clock: %s\n"
99 "\tIs a non-domain NC serviced by LDAP server: %s\n"
100 "\tIs NT6 DC that has some secrets: %s\n"
101 "\tIs NT6 DC that has all secrets: %s\n"),
102 (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
103 (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
104 (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
105 (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
106 (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
107 (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
108 (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
109 (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
110 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
111 (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
112 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
113 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"));
116 printf(_("Forest:\t\t\t%s\n"), reply.forest);
117 printf(_("Domain:\t\t\t%s\n"), reply.dns_domain);
118 printf(_("Domain Controller:\t%s\n"), reply.pdc_dns_name);
120 printf(_("Pre-Win2k Domain:\t%s\n"), reply.domain_name);
121 printf(_("Pre-Win2k Hostname:\t%s\n"), reply.pdc_name);
123 if (*reply.user_name) printf(_("User name:\t%s\n"), reply.user_name);
125 printf(_("Server Site Name :\t\t%s\n"), reply.server_site);
126 printf(_("Client Site Name :\t\t%s\n"), reply.client_site);
128 d_printf(_("NT Version: %d\n"), reply.nt_version);
129 d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
130 d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
132 return 0;
136 this implements the CLDAP based netlogon lookup requests
137 for finding the domain controller of a ADS domain
139 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
141 ADS_STRUCT *ads;
142 int ret;
144 if (c->display_usage) {
145 d_printf("%s\n"
146 "net ads lookup\n"
147 " %s",
148 _("Usage:"),
149 _("Find the ADS DC using CLDAP lookup.\n"));
150 return 0;
153 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
154 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
155 ads_destroy(&ads);
156 return -1;
159 if (!ads->config.realm) {
160 ads->config.realm = discard_const_p(char, c->opt_target_workgroup);
161 ads->ldap.port = 389;
164 ret = net_ads_cldap_netlogon(c, ads);
165 ads_destroy(&ads);
166 return ret;
171 static int net_ads_info(struct net_context *c, int argc, const char **argv)
173 ADS_STRUCT *ads;
174 char addr[INET6_ADDRSTRLEN];
176 if (c->display_usage) {
177 d_printf("%s\n"
178 "net ads info\n"
179 " %s",
180 _("Usage:"),
181 _("Display information about an Active Directory "
182 "server.\n"));
183 return 0;
186 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
187 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
188 return -1;
191 if (!ads || !ads->config.realm) {
192 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
193 ads_destroy(&ads);
194 return -1;
197 /* Try to set the server's current time since we didn't do a full
198 TCP LDAP session initially */
200 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
201 d_fprintf( stderr, _("Failed to get server's current time!\n"));
204 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
206 d_printf(_("LDAP server: %s\n"), addr);
207 d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
208 d_printf(_("Realm: %s\n"), ads->config.realm);
209 d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
210 d_printf(_("LDAP port: %d\n"), ads->ldap.port);
211 d_printf(_("Server time: %s\n"),
212 http_timestring(talloc_tos(), ads->config.current_time));
214 d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
215 d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
217 ads_destroy(&ads);
218 return 0;
221 static void use_in_memory_ccache(void) {
222 /* Use in-memory credentials cache so we do not interfere with
223 * existing credentials */
224 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
227 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
228 uint32 auth_flags, ADS_STRUCT **ads_ret)
230 ADS_STRUCT *ads = NULL;
231 ADS_STATUS status;
232 bool need_password = false;
233 bool second_time = false;
234 char *cp;
235 const char *realm = NULL;
236 bool tried_closest_dc = false;
238 /* lp_realm() should be handled by a command line param,
239 However, the join requires that realm be set in smb.conf
240 and compares our realm with the remote server's so this is
241 ok until someone needs more flexibility */
243 *ads_ret = NULL;
245 retry_connect:
246 if (only_own_domain) {
247 realm = lp_realm();
248 } else {
249 realm = assume_own_realm(c);
252 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
254 if (!c->opt_user_name) {
255 c->opt_user_name = "administrator";
258 if (c->opt_user_specified) {
259 need_password = true;
262 retry:
263 if (!c->opt_password && need_password && !c->opt_machine_pass) {
264 c->opt_password = net_prompt_pass(c, c->opt_user_name);
265 if (!c->opt_password) {
266 ads_destroy(&ads);
267 return ADS_ERROR(LDAP_NO_MEMORY);
271 if (c->opt_password) {
272 use_in_memory_ccache();
273 SAFE_FREE(ads->auth.password);
274 ads->auth.password = smb_xstrdup(c->opt_password);
277 ads->auth.flags |= auth_flags;
278 SAFE_FREE(ads->auth.user_name);
279 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
282 * If the username is of the form "name@realm",
283 * extract the realm and convert to upper case.
284 * This is only used to establish the connection.
286 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
287 *cp++ = '\0';
288 SAFE_FREE(ads->auth.realm);
289 ads->auth.realm = smb_xstrdup(cp);
290 strupper_m(ads->auth.realm);
293 status = ads_connect(ads);
295 if (!ADS_ERR_OK(status)) {
297 if (NT_STATUS_EQUAL(ads_ntstatus(status),
298 NT_STATUS_NO_LOGON_SERVERS)) {
299 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
300 ads_destroy(&ads);
301 return status;
304 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
305 need_password = true;
306 second_time = true;
307 goto retry;
308 } else {
309 ads_destroy(&ads);
310 return status;
314 /* when contacting our own domain, make sure we use the closest DC.
315 * This is done by reconnecting to ADS because only the first call to
316 * ads_connect will give us our own sitename */
318 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
320 tried_closest_dc = true; /* avoid loop */
322 if (!ads_closest_dc(ads)) {
324 namecache_delete(ads->server.realm, 0x1C);
325 namecache_delete(ads->server.workgroup, 0x1C);
327 ads_destroy(&ads);
328 ads = NULL;
330 goto retry_connect;
334 *ads_ret = ads;
335 return status;
338 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
340 return ads_startup_int(c, only_own_domain, 0, ads);
343 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
345 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
349 Check to see if connection can be made via ads.
350 ads_startup() stores the password in opt_password if it needs to so
351 that rpc or rap can use it without re-prompting.
353 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
355 ADS_STRUCT *ads;
356 ADS_STATUS status;
358 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
359 return -1;
362 ads->auth.flags |= ADS_AUTH_NO_BIND;
364 status = ads_connect(ads);
365 if ( !ADS_ERR_OK(status) ) {
366 return -1;
369 ads_destroy(&ads);
370 return 0;
373 int net_ads_check_our_domain(struct net_context *c)
375 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
378 int net_ads_check(struct net_context *c)
380 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
384 determine the netbios workgroup name for a domain
386 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
388 ADS_STRUCT *ads;
389 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
391 if (c->display_usage) {
392 d_printf ("%s\n"
393 "net ads workgroup\n"
394 " %s\n",
395 _("Usage:"),
396 _("Print the workgroup name"));
397 return 0;
400 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
401 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
402 return -1;
405 if (!ads->config.realm) {
406 ads->config.realm = discard_const_p(char, c->opt_target_workgroup);
407 ads->ldap.port = 389;
410 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads->ldap.ss, 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_m(field, "sAMAccountName") == 0) {
446 disp_fields[0] = SMB_STRDUP((char *) values[0]);
448 if (strcasecmp_m(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, lp_netbios_name());
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"), lp_netbios_name());
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 requested, 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(lp_netbios_name()) > 15) {
1105 d_printf(_("Our netbios name can be at most 15 chars long, "
1106 "\"%s\" is %u chars long\n"), lp_netbios_name(),
1107 (unsigned int)strlen(lp_netbios_name()));
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 *dns_hosts_file;
1142 const char *dnsdomain = NULL;
1143 char *root_domain = NULL;
1145 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1146 d_printf(_("No DNS domain configured for %s. "
1147 "Unable to perform DNS Update.\n"), machine_name);
1148 status = NT_STATUS_INVALID_PARAMETER;
1149 goto done;
1151 dnsdomain++;
1153 dns_hosts_file = lp_parm_const_string(-1, "resolv", "host file", NULL);
1154 status = ads_dns_lookup_ns(ctx, dns_hosts_file,
1155 dnsdomain, &nameservers, &ns_count);
1156 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1157 /* Child domains often do not have NS records. Look
1158 for the NS record for the forest root domain
1159 (rootDomainNamingContext in therootDSE) */
1161 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1162 LDAPMessage *msg = NULL;
1163 char *root_dn;
1164 ADS_STATUS ads_status;
1166 if ( !ads->ldap.ld ) {
1167 ads_status = ads_connect( ads );
1168 if ( !ADS_ERR_OK(ads_status) ) {
1169 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1170 goto done;
1174 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1175 "(objectclass=*)", rootname_attrs, &msg);
1176 if (!ADS_ERR_OK(ads_status)) {
1177 goto done;
1180 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1181 if ( !root_dn ) {
1182 ads_msgfree( ads, msg );
1183 goto done;
1186 root_domain = ads_build_domain( root_dn );
1188 /* cleanup */
1189 ads_msgfree( ads, msg );
1191 /* try again for NS servers */
1193 status = ads_dns_lookup_ns(ctx, dns_hosts_file, root_domain,
1194 &nameservers, &ns_count);
1196 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1197 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1198 "realm\n", ads->config.realm));
1199 goto done;
1202 dnsdomain = root_domain;
1206 for (i=0; i < ns_count; i++) {
1208 status = NT_STATUS_UNSUCCESSFUL;
1210 /* Now perform the dns update - we'll try non-secure and if we fail,
1211 we'll follow it up with a secure update */
1213 fstrcpy( dns_server, nameservers[i].hostname );
1215 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1216 if (ERR_DNS_IS_OK(dns_err)) {
1217 status = NT_STATUS_OK;
1218 goto done;
1221 if (ERR_DNS_EQUAL(dns_err, ERROR_DNS_INVALID_NAME_SERVER) ||
1222 ERR_DNS_EQUAL(dns_err, ERROR_DNS_CONNECTION_FAILED) ||
1223 ERR_DNS_EQUAL(dns_err, ERROR_DNS_SOCKET_ERROR)) {
1224 DEBUG(1,("retrying DNS update with next nameserver after receiving %s\n",
1225 dns_errstr(dns_err)));
1226 continue;
1229 d_printf(_("DNS Update for %s failed: %s\n"),
1230 machine_name, dns_errstr(dns_err));
1231 status = NT_STATUS_UNSUCCESSFUL;
1232 goto done;
1235 done:
1237 SAFE_FREE( root_domain );
1239 return status;
1242 static NTSTATUS net_update_dns_ext(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads,
1243 const char *hostname,
1244 struct sockaddr_storage *iplist,
1245 int num_addrs)
1247 struct sockaddr_storage *iplist_alloc = NULL;
1248 fstring machine_name;
1249 NTSTATUS status;
1251 if (hostname) {
1252 fstrcpy(machine_name, hostname);
1253 } else {
1254 name_to_fqdn( machine_name, lp_netbios_name() );
1256 strlower_m( machine_name );
1258 if (num_addrs == 0 || iplist == NULL) {
1260 * Get our ip address
1261 * (not the 127.0.0.x address but a real ip address)
1263 num_addrs = get_my_ip_address(&iplist_alloc);
1264 if ( num_addrs <= 0 ) {
1265 DEBUG(4, ("net_update_dns_ext: Failed to find my "
1266 "non-loopback IP addresses!\n"));
1267 return NT_STATUS_INVALID_PARAMETER;
1269 iplist = iplist_alloc;
1272 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1273 iplist, num_addrs);
1275 SAFE_FREE(iplist_alloc);
1276 return status;
1279 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, const char *hostname)
1281 NTSTATUS status;
1283 status = net_update_dns_ext(mem_ctx, ads, hostname, NULL, 0);
1284 return status;
1286 #endif
1289 /*******************************************************************
1290 ********************************************************************/
1292 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1294 d_printf(_("net ads join [options]\n"
1295 "Valid options:\n"));
1296 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1297 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1298 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1299 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1300 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1301 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1302 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1303 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1304 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1305 " NB: osName and osVer must be specified together for either to take effect.\n"
1306 " Also, the operatingSystemService attribute is also set when along with\n"
1307 " the two other attributes.\n"));
1309 return -1;
1313 static void _net_ads_join_dns_updates(TALLOC_CTX *ctx, struct libnet_JoinCtx *r)
1315 #if defined(WITH_DNS_UPDATES)
1316 ADS_STRUCT *ads_dns = NULL;
1317 int ret;
1318 NTSTATUS status;
1321 * In a clustered environment, don't do dynamic dns updates:
1322 * Registering the set of ip addresses that are assigned to
1323 * the interfaces of the node that performs the join does usually
1324 * not have the desired effect, since the local interfaces do not
1325 * carry the complete set of the cluster's public IP addresses.
1326 * And it can also contain internal addresses that should not
1327 * be visible to the outside at all.
1328 * In order to do dns updates in a clustererd setup, use
1329 * net ads dns register.
1331 if (lp_clustering()) {
1332 d_fprintf(stderr, _("Not doing automatic DNS update in a "
1333 "clustered setup.\n"));
1334 return;
1337 if (!r->out.domain_is_ad) {
1338 return;
1342 * We enter this block with user creds.
1343 * kinit with the machine password to do dns update.
1346 ads_dns = ads_init(lp_realm(), NULL, r->in.dc_name);
1348 if (ads_dns == NULL) {
1349 d_fprintf(stderr, _("DNS update failed: out of memory!\n"));
1350 goto done;
1353 use_in_memory_ccache();
1355 ret = asprintf(&ads_dns->auth.user_name, "%s$", lp_netbios_name());
1356 if (ret == -1) {
1357 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1358 goto done;
1361 ads_dns->auth.password = secrets_fetch_machine_password(
1362 r->out.netbios_domain_name, NULL, NULL);
1363 if (ads_dns->auth.password == NULL) {
1364 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1365 goto done;
1368 ads_dns->auth.realm = SMB_STRDUP(r->out.dns_domain_name);
1369 if (ads_dns->auth.realm == NULL) {
1370 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1371 goto done;
1374 strupper_m(ads_dns->auth.realm);
1376 ret = ads_kinit_password(ads_dns);
1377 if (ret != 0) {
1378 d_fprintf(stderr,
1379 _("DNS update failed: kinit failed: %s\n"),
1380 error_message(ret));
1381 goto done;
1384 status = net_update_dns(ctx, ads_dns, NULL);
1385 if (!NT_STATUS_IS_OK(status)) {
1386 d_fprintf( stderr, _("DNS update failed: %s\n"),
1387 nt_errstr(status));
1390 done:
1391 ads_destroy(&ads_dns);
1392 #endif
1394 return;
1398 int net_ads_join(struct net_context *c, int argc, const char **argv)
1400 TALLOC_CTX *ctx = NULL;
1401 struct libnet_JoinCtx *r = NULL;
1402 const char *domain = lp_realm();
1403 WERROR werr = WERR_SETUP_NOT_JOINED;
1404 bool createupn = false;
1405 const char *machineupn = NULL;
1406 const char *create_in_ou = NULL;
1407 int i;
1408 const char *os_name = NULL;
1409 const char *os_version = NULL;
1410 bool modify_config = lp_config_backend_is_registry();
1412 if (c->display_usage)
1413 return net_ads_join_usage(c, argc, argv);
1415 if (!modify_config) {
1417 werr = check_ads_config();
1418 if (!W_ERROR_IS_OK(werr)) {
1419 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1420 goto fail;
1424 if (!(ctx = talloc_init("net_ads_join"))) {
1425 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1426 werr = WERR_NOMEM;
1427 goto fail;
1430 if (!c->opt_kerberos) {
1431 use_in_memory_ccache();
1434 werr = libnet_init_JoinCtx(ctx, &r);
1435 if (!W_ERROR_IS_OK(werr)) {
1436 goto fail;
1439 /* process additional command line args */
1441 for ( i=0; i<argc; i++ ) {
1442 if ( !strncasecmp_m(argv[i], "createupn", strlen("createupn")) ) {
1443 createupn = true;
1444 machineupn = get_string_param(argv[i]);
1446 else if ( !strncasecmp_m(argv[i], "createcomputer", strlen("createcomputer")) ) {
1447 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1448 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1449 werr = WERR_INVALID_PARAM;
1450 goto fail;
1453 else if ( !strncasecmp_m(argv[i], "osName", strlen("osName")) ) {
1454 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1455 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1456 werr = WERR_INVALID_PARAM;
1457 goto fail;
1460 else if ( !strncasecmp_m(argv[i], "osVer", strlen("osVer")) ) {
1461 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1462 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1463 werr = WERR_INVALID_PARAM;
1464 goto fail;
1467 else {
1468 domain = argv[i];
1472 if (!*domain) {
1473 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1474 werr = WERR_INVALID_PARAM;
1475 goto fail;
1478 if (!c->msg_ctx) {
1479 d_fprintf(stderr, _("Could not initialise message context. "
1480 "Try running as root\n"));
1481 werr = WERR_ACCESS_DENIED;
1482 goto fail;
1485 /* Do the domain join here */
1487 r->in.domain_name = domain;
1488 r->in.create_upn = createupn;
1489 r->in.upn = machineupn;
1490 r->in.account_ou = create_in_ou;
1491 r->in.os_name = os_name;
1492 r->in.os_version = os_version;
1493 r->in.dc_name = c->opt_host;
1494 r->in.admin_account = c->opt_user_name;
1495 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1496 r->in.debug = true;
1497 r->in.use_kerberos = c->opt_kerberos;
1498 r->in.modify_config = modify_config;
1499 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1500 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1501 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1502 r->in.msg_ctx = c->msg_ctx;
1504 werr = libnet_Join(ctx, r);
1505 if (W_ERROR_EQUAL(werr, WERR_DCNOTFOUND) &&
1506 strequal(domain, lp_realm())) {
1507 r->in.domain_name = lp_workgroup();
1508 werr = libnet_Join(ctx, r);
1510 if (!W_ERROR_IS_OK(werr)) {
1511 goto fail;
1514 /* Check the short name of the domain */
1516 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1517 d_printf(_("The workgroup in %s does not match the short\n"
1518 "domain name obtained from the server.\n"
1519 "Using the name [%s] from the server.\n"
1520 "You should set \"workgroup = %s\" in %s.\n"),
1521 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1522 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1525 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1527 if (r->out.dns_domain_name) {
1528 d_printf(_("Joined '%s' to realm '%s'\n"), r->in.machine_name,
1529 r->out.dns_domain_name);
1530 } else {
1531 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1532 r->out.netbios_domain_name);
1536 * We try doing the dns update (if it was compiled in).
1537 * If the dns update fails, we still consider the join
1538 * operation as succeeded if we came this far.
1540 _net_ads_join_dns_updates(ctx, r);
1542 TALLOC_FREE(r);
1543 TALLOC_FREE( ctx );
1545 return 0;
1547 fail:
1548 /* issue an overall failure message at the end. */
1549 d_printf(_("Failed to join domain: %s\n"),
1550 r && r->out.error_string ? r->out.error_string :
1551 get_friendly_werror_msg(werr));
1552 TALLOC_FREE( ctx );
1554 return -1;
1557 /*******************************************************************
1558 ********************************************************************/
1560 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1562 #if defined(WITH_DNS_UPDATES)
1563 ADS_STRUCT *ads;
1564 ADS_STATUS status;
1565 NTSTATUS ntstatus;
1566 TALLOC_CTX *ctx;
1567 const char *hostname = NULL;
1568 const char **addrs_list = NULL;
1569 struct sockaddr_storage *addrs = NULL;
1570 int num_addrs = 0;
1571 int count;
1573 #ifdef DEVELOPER
1574 talloc_enable_leak_report();
1575 #endif
1577 if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
1578 d_fprintf(stderr, _("Refusing DNS updates with automatic "
1579 "detection of addresses in a clustered "
1580 "setup.\n"));
1581 c->display_usage = true;
1584 if (c->display_usage) {
1585 d_printf( "%s\n"
1586 "net ads dns register [hostname [IP [IP...]]]\n"
1587 " %s\n",
1588 _("Usage:"),
1589 _("Register hostname with DNS\n"));
1590 return -1;
1593 if (!(ctx = talloc_init("net_ads_dns"))) {
1594 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1595 return -1;
1598 if (argc >= 1) {
1599 hostname = argv[0];
1602 if (argc > 1) {
1603 num_addrs = argc - 1;
1604 addrs_list = &argv[1];
1605 } else if (lp_clustering()) {
1606 addrs_list = lp_cluster_addresses();
1607 num_addrs = str_list_length(addrs_list);
1610 if (num_addrs > 0) {
1611 addrs = talloc_zero_array(ctx, struct sockaddr_storage, num_addrs);
1612 if (addrs == NULL) {
1613 d_fprintf(stderr, _("Error allocating memory!\n"));
1614 talloc_free(ctx);
1615 return -1;
1619 for (count = 0; count < num_addrs; count++) {
1620 if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
1621 d_fprintf(stderr, "%s '%s'.\n",
1622 _("Cannot interpret address"),
1623 addrs_list[count]);
1624 talloc_free(ctx);
1625 return -1;
1629 status = ads_startup(c, true, &ads);
1630 if ( !ADS_ERR_OK(status) ) {
1631 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1632 TALLOC_FREE(ctx);
1633 return -1;
1636 ntstatus = net_update_dns_ext(ctx, ads, hostname, addrs, num_addrs);
1637 if (!NT_STATUS_IS_OK(ntstatus)) {
1638 d_fprintf( stderr, _("DNS update failed!\n") );
1639 ads_destroy( &ads );
1640 TALLOC_FREE( ctx );
1641 return -1;
1644 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1646 ads_destroy(&ads);
1647 TALLOC_FREE( ctx );
1649 return 0;
1650 #else
1651 d_fprintf(stderr,
1652 _("DNS update support not enabled at compile time!\n"));
1653 return -1;
1654 #endif
1657 #if defined(WITH_DNS_UPDATES)
1658 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1659 #endif
1661 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1663 #if defined(WITH_DNS_UPDATES)
1664 DNS_ERROR err;
1666 #ifdef DEVELOPER
1667 talloc_enable_leak_report();
1668 #endif
1670 if (argc != 2 || c->display_usage) {
1671 d_printf( "%s\n"
1672 " %s\n"
1673 " %s\n",
1674 _("Usage:"),
1675 _("net ads dns gethostbyname <server> <name>\n"),
1676 _(" Look up hostname from the AD\n"
1677 " server\tName server to use\n"
1678 " name\tName to look up\n"));
1679 return -1;
1682 err = do_gethostbyname(argv[0], argv[1]);
1684 d_printf(_("do_gethostbyname returned %s (%d)\n"),
1685 dns_errstr(err), ERROR_DNS_V(err));
1686 #endif
1687 return 0;
1690 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1692 struct functable func[] = {
1694 "register",
1695 net_ads_dns_register,
1696 NET_TRANSPORT_ADS,
1697 N_("Add host dns entry to AD"),
1698 N_("net ads dns register\n"
1699 " Add host dns entry to AD")
1702 "gethostbyname",
1703 net_ads_dns_gethostbyname,
1704 NET_TRANSPORT_ADS,
1705 N_("Look up host"),
1706 N_("net ads dns gethostbyname\n"
1707 " Look up host")
1709 {NULL, NULL, 0, NULL, NULL}
1712 return net_run_function(c, argc, argv, "net ads dns", func);
1715 /*******************************************************************
1716 ********************************************************************/
1718 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1720 d_printf(_(
1721 "\nnet ads printer search <printer>"
1722 "\n\tsearch for a printer in the directory\n"
1723 "\nnet ads printer info <printer> <server>"
1724 "\n\tlookup info in directory for printer on server"
1725 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1726 "\nnet ads printer publish <printername>"
1727 "\n\tpublish printer in directory"
1728 "\n\t(note: printer name is required)\n"
1729 "\nnet ads printer remove <printername>"
1730 "\n\tremove printer from directory"
1731 "\n\t(note: printer name is required)\n"));
1732 return -1;
1735 /*******************************************************************
1736 ********************************************************************/
1738 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1740 ADS_STRUCT *ads;
1741 ADS_STATUS rc;
1742 LDAPMessage *res = NULL;
1744 if (c->display_usage) {
1745 d_printf( "%s\n"
1746 "net ads printer search\n"
1747 " %s\n",
1748 _("Usage:"),
1749 _("List printers in the AD"));
1750 return 0;
1753 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1754 return -1;
1757 rc = ads_find_printers(ads, &res);
1759 if (!ADS_ERR_OK(rc)) {
1760 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
1761 ads_msgfree(ads, res);
1762 ads_destroy(&ads);
1763 return -1;
1766 if (ads_count_replies(ads, res) == 0) {
1767 d_fprintf(stderr, _("No results found\n"));
1768 ads_msgfree(ads, res);
1769 ads_destroy(&ads);
1770 return -1;
1773 ads_dump(ads, res);
1774 ads_msgfree(ads, res);
1775 ads_destroy(&ads);
1776 return 0;
1779 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1781 ADS_STRUCT *ads;
1782 ADS_STATUS rc;
1783 const char *servername, *printername;
1784 LDAPMessage *res = NULL;
1786 if (c->display_usage) {
1787 d_printf("%s\n%s",
1788 _("Usage:"),
1789 _("net ads printer info [printername [servername]]\n"
1790 " Display printer info from AD\n"
1791 " printername\tPrinter name or wildcard\n"
1792 " servername\tName of the print server\n"));
1793 return 0;
1796 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1797 return -1;
1800 if (argc > 0) {
1801 printername = argv[0];
1802 } else {
1803 printername = "*";
1806 if (argc > 1) {
1807 servername = argv[1];
1808 } else {
1809 servername = lp_netbios_name();
1812 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1814 if (!ADS_ERR_OK(rc)) {
1815 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
1816 servername, ads_errstr(rc));
1817 ads_msgfree(ads, res);
1818 ads_destroy(&ads);
1819 return -1;
1822 if (ads_count_replies(ads, res) == 0) {
1823 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
1824 ads_msgfree(ads, res);
1825 ads_destroy(&ads);
1826 return -1;
1829 ads_dump(ads, res);
1830 ads_msgfree(ads, res);
1831 ads_destroy(&ads);
1833 return 0;
1836 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1838 ADS_STRUCT *ads;
1839 ADS_STATUS rc;
1840 const char *servername, *printername;
1841 struct cli_state *cli = NULL;
1842 struct rpc_pipe_client *pipe_hnd = NULL;
1843 struct sockaddr_storage server_ss;
1844 NTSTATUS nt_status;
1845 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1846 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1847 char *prt_dn, *srv_dn, **srv_cn;
1848 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1849 LDAPMessage *res = NULL;
1851 if (argc < 1 || c->display_usage) {
1852 d_printf("%s\n%s",
1853 _("Usage:"),
1854 _("net ads printer publish <printername> [servername]\n"
1855 " Publish printer in AD\n"
1856 " printername\tName of the printer\n"
1857 " servername\tName of the print server\n"));
1858 talloc_destroy(mem_ctx);
1859 return -1;
1862 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1863 talloc_destroy(mem_ctx);
1864 return -1;
1867 printername = argv[0];
1869 if (argc == 2) {
1870 servername = argv[1];
1871 } else {
1872 servername = lp_netbios_name();
1875 /* Get printer data from SPOOLSS */
1877 resolve_name(servername, &server_ss, 0x20, false);
1879 nt_status = cli_full_connection(&cli, lp_netbios_name(), servername,
1880 &server_ss, 0,
1881 "IPC$", "IPC",
1882 c->opt_user_name, c->opt_workgroup,
1883 c->opt_password ? c->opt_password : "",
1884 CLI_FULL_CONNECTION_USE_KERBEROS,
1885 SMB_SIGNING_DEFAULT);
1887 if (NT_STATUS_IS_ERR(nt_status)) {
1888 d_fprintf(stderr, _("Unable to open a connection to %s to "
1889 "obtain data for %s\n"),
1890 servername, printername);
1891 ads_destroy(&ads);
1892 talloc_destroy(mem_ctx);
1893 return -1;
1896 /* Publish on AD server */
1898 ads_find_machine_acct(ads, &res, servername);
1900 if (ads_count_replies(ads, res) == 0) {
1901 d_fprintf(stderr, _("Could not find machine account for server "
1902 "%s\n"),
1903 servername);
1904 ads_destroy(&ads);
1905 talloc_destroy(mem_ctx);
1906 return -1;
1909 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1910 srv_cn = ldap_explode_dn(srv_dn, 1);
1912 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1913 printername_escaped = escape_rdn_val_string_alloc(printername);
1914 if (!srv_cn_escaped || !printername_escaped) {
1915 SAFE_FREE(srv_cn_escaped);
1916 SAFE_FREE(printername_escaped);
1917 d_fprintf(stderr, _("Internal error, out of memory!"));
1918 ads_destroy(&ads);
1919 talloc_destroy(mem_ctx);
1920 return -1;
1923 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1924 SAFE_FREE(srv_cn_escaped);
1925 SAFE_FREE(printername_escaped);
1926 d_fprintf(stderr, _("Internal error, out of memory!"));
1927 ads_destroy(&ads);
1928 talloc_destroy(mem_ctx);
1929 return -1;
1932 SAFE_FREE(srv_cn_escaped);
1933 SAFE_FREE(printername_escaped);
1935 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
1936 if (!NT_STATUS_IS_OK(nt_status)) {
1937 d_fprintf(stderr, _("Unable to open a connection to the spoolss pipe on %s\n"),
1938 servername);
1939 SAFE_FREE(prt_dn);
1940 ads_destroy(&ads);
1941 talloc_destroy(mem_ctx);
1942 return -1;
1945 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1946 printername))) {
1947 SAFE_FREE(prt_dn);
1948 ads_destroy(&ads);
1949 talloc_destroy(mem_ctx);
1950 return -1;
1953 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1954 if (!ADS_ERR_OK(rc)) {
1955 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1956 SAFE_FREE(prt_dn);
1957 ads_destroy(&ads);
1958 talloc_destroy(mem_ctx);
1959 return -1;
1962 d_printf("published printer\n");
1963 SAFE_FREE(prt_dn);
1964 ads_destroy(&ads);
1965 talloc_destroy(mem_ctx);
1967 return 0;
1970 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1972 ADS_STRUCT *ads;
1973 ADS_STATUS rc;
1974 const char *servername;
1975 char *prt_dn;
1976 LDAPMessage *res = NULL;
1978 if (argc < 1 || c->display_usage) {
1979 d_printf("%s\n%s",
1980 _("Usage:"),
1981 _("net ads printer remove <printername> [servername]\n"
1982 " Remove a printer from the AD\n"
1983 " printername\tName of the printer\n"
1984 " servername\tName of the print server\n"));
1985 return -1;
1988 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1989 return -1;
1992 if (argc > 1) {
1993 servername = argv[1];
1994 } else {
1995 servername = lp_netbios_name();
1998 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
2000 if (!ADS_ERR_OK(rc)) {
2001 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
2002 ads_msgfree(ads, res);
2003 ads_destroy(&ads);
2004 return -1;
2007 if (ads_count_replies(ads, res) == 0) {
2008 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
2009 ads_msgfree(ads, res);
2010 ads_destroy(&ads);
2011 return -1;
2014 prt_dn = ads_get_dn(ads, talloc_tos(), res);
2015 ads_msgfree(ads, res);
2016 rc = ads_del_dn(ads, prt_dn);
2017 TALLOC_FREE(prt_dn);
2019 if (!ADS_ERR_OK(rc)) {
2020 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
2021 ads_destroy(&ads);
2022 return -1;
2025 ads_destroy(&ads);
2026 return 0;
2029 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
2031 struct functable func[] = {
2033 "search",
2034 net_ads_printer_search,
2035 NET_TRANSPORT_ADS,
2036 N_("Search for a printer"),
2037 N_("net ads printer search\n"
2038 " Search for a printer")
2041 "info",
2042 net_ads_printer_info,
2043 NET_TRANSPORT_ADS,
2044 N_("Display printer information"),
2045 N_("net ads printer info\n"
2046 " Display printer information")
2049 "publish",
2050 net_ads_printer_publish,
2051 NET_TRANSPORT_ADS,
2052 N_("Publish a printer"),
2053 N_("net ads printer publish\n"
2054 " Publish a printer")
2057 "remove",
2058 net_ads_printer_remove,
2059 NET_TRANSPORT_ADS,
2060 N_("Delete a printer"),
2061 N_("net ads printer remove\n"
2062 " Delete a printer")
2064 {NULL, NULL, 0, NULL, NULL}
2067 return net_run_function(c, argc, argv, "net ads printer", func);
2071 static int net_ads_password(struct net_context *c, int argc, const char **argv)
2073 ADS_STRUCT *ads;
2074 const char *auth_principal = c->opt_user_name;
2075 const char *auth_password = c->opt_password;
2076 const char *realm = NULL;
2077 const char *new_password = NULL;
2078 char *chr, *prompt;
2079 const char *user;
2080 ADS_STATUS ret;
2082 if (c->display_usage) {
2083 d_printf("%s\n%s",
2084 _("Usage:"),
2085 _("net ads password <username>\n"
2086 " Change password for user\n"
2087 " username\tName of user to change password for\n"));
2088 return 0;
2091 if (c->opt_user_name == NULL || c->opt_password == NULL) {
2092 d_fprintf(stderr, _("You must supply an administrator "
2093 "username/password\n"));
2094 return -1;
2097 if (argc < 1) {
2098 d_fprintf(stderr, _("ERROR: You must say which username to "
2099 "change password for\n"));
2100 return -1;
2103 user = argv[0];
2104 if (!strchr_m(user, '@')) {
2105 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
2106 return -1;
2108 user = chr;
2111 use_in_memory_ccache();
2112 chr = strchr_m(auth_principal, '@');
2113 if (chr) {
2114 realm = ++chr;
2115 } else {
2116 realm = lp_realm();
2119 /* use the realm so we can eventually change passwords for users
2120 in realms other than default */
2121 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
2122 return -1;
2125 /* we don't actually need a full connect, but it's the easy way to
2126 fill in the KDC's addresss */
2127 ads_connect(ads);
2129 if (!ads->config.realm) {
2130 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
2131 ads_destroy(&ads);
2132 return -1;
2135 if (argv[1]) {
2136 new_password = (const char *)argv[1];
2137 } else {
2138 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
2139 return -1;
2141 new_password = getpass(prompt);
2142 free(prompt);
2145 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2146 auth_password, user, new_password, ads->auth.time_offset);
2147 if (!ADS_ERR_OK(ret)) {
2148 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2149 ads_destroy(&ads);
2150 return -1;
2153 d_printf(_("Password change for %s completed.\n"), user);
2154 ads_destroy(&ads);
2156 return 0;
2159 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2161 ADS_STRUCT *ads;
2162 char *host_principal;
2163 fstring my_name;
2164 ADS_STATUS ret;
2166 if (c->display_usage) {
2167 d_printf( "%s\n"
2168 "net ads changetrustpw\n"
2169 " %s\n",
2170 _("Usage:"),
2171 _("Change the machine account's trust password"));
2172 return 0;
2175 if (!secrets_init()) {
2176 DEBUG(1,("Failed to initialise secrets database\n"));
2177 return -1;
2180 net_use_krb_machine_account(c);
2182 use_in_memory_ccache();
2184 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2185 return -1;
2188 fstrcpy(my_name, lp_netbios_name());
2189 strlower_m(my_name);
2190 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2191 ads_destroy(&ads);
2192 return -1;
2194 d_printf(_("Changing password for principal: %s\n"), host_principal);
2196 ret = ads_change_trust_account_password(ads, host_principal);
2198 if (!ADS_ERR_OK(ret)) {
2199 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2200 ads_destroy(&ads);
2201 SAFE_FREE(host_principal);
2202 return -1;
2205 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2207 if (USE_SYSTEM_KEYTAB) {
2208 d_printf(_("Attempting to update system keytab with new password.\n"));
2209 if (ads_keytab_create_default(ads)) {
2210 d_printf(_("Failed to update system keytab.\n"));
2214 ads_destroy(&ads);
2215 SAFE_FREE(host_principal);
2217 return 0;
2221 help for net ads search
2223 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2225 d_printf(_(
2226 "\nnet ads search <expression> <attributes...>\n"
2227 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2228 "The expression is a standard LDAP search expression, and the\n"
2229 "attributes are a list of LDAP fields to show in the results.\n\n"
2230 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2232 net_common_flags_usage(c, argc, argv);
2233 return -1;
2238 general ADS search function. Useful in diagnosing problems in ADS
2240 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2242 ADS_STRUCT *ads;
2243 ADS_STATUS rc;
2244 const char *ldap_exp;
2245 const char **attrs;
2246 LDAPMessage *res = NULL;
2248 if (argc < 1 || c->display_usage) {
2249 return net_ads_search_usage(c, argc, argv);
2252 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2253 return -1;
2256 ldap_exp = argv[0];
2257 attrs = (argv + 1);
2259 rc = ads_do_search_retry(ads, ads->config.bind_path,
2260 LDAP_SCOPE_SUBTREE,
2261 ldap_exp, attrs, &res);
2262 if (!ADS_ERR_OK(rc)) {
2263 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2264 ads_destroy(&ads);
2265 return -1;
2268 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2270 /* dump the results */
2271 ads_dump(ads, res);
2273 ads_msgfree(ads, res);
2274 ads_destroy(&ads);
2276 return 0;
2281 help for net ads search
2283 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2285 d_printf(_(
2286 "\nnet ads dn <dn> <attributes...>\n"
2287 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2288 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2289 "to show in the results\n\n"
2290 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2291 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2293 net_common_flags_usage(c, argc, argv);
2294 return -1;
2299 general ADS search function. Useful in diagnosing problems in ADS
2301 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2303 ADS_STRUCT *ads;
2304 ADS_STATUS rc;
2305 const char *dn;
2306 const char **attrs;
2307 LDAPMessage *res = NULL;
2309 if (argc < 1 || c->display_usage) {
2310 return net_ads_dn_usage(c, argc, argv);
2313 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2314 return -1;
2317 dn = argv[0];
2318 attrs = (argv + 1);
2320 rc = ads_do_search_all(ads, dn,
2321 LDAP_SCOPE_BASE,
2322 "(objectclass=*)", attrs, &res);
2323 if (!ADS_ERR_OK(rc)) {
2324 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2325 ads_destroy(&ads);
2326 return -1;
2329 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2331 /* dump the results */
2332 ads_dump(ads, res);
2334 ads_msgfree(ads, res);
2335 ads_destroy(&ads);
2337 return 0;
2341 help for net ads sid search
2343 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2345 d_printf(_(
2346 "\nnet ads sid <sid> <attributes...>\n"
2347 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2348 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2349 "to show in the results\n\n"
2350 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2352 net_common_flags_usage(c, argc, argv);
2353 return -1;
2358 general ADS search function. Useful in diagnosing problems in ADS
2360 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2362 ADS_STRUCT *ads;
2363 ADS_STATUS rc;
2364 const char *sid_string;
2365 const char **attrs;
2366 LDAPMessage *res = NULL;
2367 struct dom_sid sid;
2369 if (argc < 1 || c->display_usage) {
2370 return net_ads_sid_usage(c, argc, argv);
2373 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2374 return -1;
2377 sid_string = argv[0];
2378 attrs = (argv + 1);
2380 if (!string_to_sid(&sid, sid_string)) {
2381 d_fprintf(stderr, _("could not convert sid\n"));
2382 ads_destroy(&ads);
2383 return -1;
2386 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2387 if (!ADS_ERR_OK(rc)) {
2388 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2389 ads_destroy(&ads);
2390 return -1;
2393 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2395 /* dump the results */
2396 ads_dump(ads, res);
2398 ads_msgfree(ads, res);
2399 ads_destroy(&ads);
2401 return 0;
2404 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2406 int ret;
2407 ADS_STRUCT *ads;
2409 if (c->display_usage) {
2410 d_printf( "%s\n"
2411 "net ads keytab flush\n"
2412 " %s\n",
2413 _("Usage:"),
2414 _("Delete the whole keytab"));
2415 return 0;
2418 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2419 return -1;
2421 ret = ads_keytab_flush(ads);
2422 ads_destroy(&ads);
2423 return ret;
2426 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2428 int i;
2429 int ret = 0;
2430 ADS_STRUCT *ads;
2432 if (c->display_usage) {
2433 d_printf("%s\n%s",
2434 _("Usage:"),
2435 _("net ads keytab add <principal> [principal ...]\n"
2436 " Add principals to local keytab\n"
2437 " principal\tKerberos principal to add to "
2438 "keytab\n"));
2439 return 0;
2442 d_printf(_("Processing principals to add...\n"));
2443 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2444 return -1;
2446 for (i = 0; i < argc; i++) {
2447 ret |= ads_keytab_add_entry(ads, argv[i]);
2449 ads_destroy(&ads);
2450 return ret;
2453 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2455 ADS_STRUCT *ads;
2456 int ret;
2458 if (c->display_usage) {
2459 d_printf( "%s\n"
2460 "net ads keytab create\n"
2461 " %s\n",
2462 _("Usage:"),
2463 _("Create new default keytab"));
2464 return 0;
2467 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2468 return -1;
2470 ret = ads_keytab_create_default(ads);
2471 ads_destroy(&ads);
2472 return ret;
2475 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2477 const char *keytab = NULL;
2479 if (c->display_usage) {
2480 d_printf("%s\n%s",
2481 _("Usage:"),
2482 _("net ads keytab list [keytab]\n"
2483 " List a local keytab\n"
2484 " keytab\tKeytab to list\n"));
2485 return 0;
2488 if (argc >= 1) {
2489 keytab = argv[0];
2492 return ads_keytab_list(keytab);
2496 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2498 struct functable func[] = {
2500 "add",
2501 net_ads_keytab_add,
2502 NET_TRANSPORT_ADS,
2503 N_("Add a service principal"),
2504 N_("net ads keytab add\n"
2505 " Add a service principal")
2508 "create",
2509 net_ads_keytab_create,
2510 NET_TRANSPORT_ADS,
2511 N_("Create a fresh keytab"),
2512 N_("net ads keytab create\n"
2513 " Create a fresh keytab")
2516 "flush",
2517 net_ads_keytab_flush,
2518 NET_TRANSPORT_ADS,
2519 N_("Remove all keytab entries"),
2520 N_("net ads keytab flush\n"
2521 " Remove all keytab entries")
2524 "list",
2525 net_ads_keytab_list,
2526 NET_TRANSPORT_ADS,
2527 N_("List a keytab"),
2528 N_("net ads keytab list\n"
2529 " List a keytab")
2531 {NULL, NULL, 0, NULL, NULL}
2534 if (!USE_KERBEROS_KEYTAB) {
2535 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2536 "keytab method to use keytab functions.\n"));
2539 return net_run_function(c, argc, argv, "net ads keytab", func);
2542 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2544 int ret = -1;
2546 if (c->display_usage) {
2547 d_printf( "%s\n"
2548 "net ads kerberos renew\n"
2549 " %s\n",
2550 _("Usage:"),
2551 _("Renew TGT from existing credential cache"));
2552 return 0;
2555 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2556 if (ret) {
2557 d_printf(_("failed to renew kerberos ticket: %s\n"),
2558 error_message(ret));
2560 return ret;
2563 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2565 struct PAC_LOGON_INFO *info = NULL;
2566 TALLOC_CTX *mem_ctx = NULL;
2567 NTSTATUS status;
2568 int ret = -1;
2569 const char *impersonate_princ_s = NULL;
2571 if (c->display_usage) {
2572 d_printf( "%s\n"
2573 "net ads kerberos pac\n"
2574 " %s\n",
2575 _("Usage:"),
2576 _("Dump the Kerberos PAC"));
2577 return 0;
2580 mem_ctx = talloc_init("net_ads_kerberos_pac");
2581 if (!mem_ctx) {
2582 goto out;
2585 if (argc > 0) {
2586 impersonate_princ_s = argv[0];
2589 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2591 status = kerberos_return_pac(mem_ctx,
2592 c->opt_user_name,
2593 c->opt_password,
2595 NULL,
2596 NULL,
2597 NULL,
2598 true,
2599 true,
2600 2592000, /* one month */
2601 impersonate_princ_s,
2602 &info);
2603 if (!NT_STATUS_IS_OK(status)) {
2604 d_printf(_("failed to query kerberos PAC: %s\n"),
2605 nt_errstr(status));
2606 goto out;
2609 if (info) {
2610 const char *s;
2611 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2612 d_printf(_("The Pac: %s\n"), s);
2615 ret = 0;
2616 out:
2617 TALLOC_FREE(mem_ctx);
2618 return ret;
2621 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2623 TALLOC_CTX *mem_ctx = NULL;
2624 int ret = -1;
2625 NTSTATUS status;
2627 if (c->display_usage) {
2628 d_printf( "%s\n"
2629 "net ads kerberos kinit\n"
2630 " %s\n",
2631 _("Usage:"),
2632 _("Get Ticket Granting Ticket (TGT) for the user"));
2633 return 0;
2636 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2637 if (!mem_ctx) {
2638 goto out;
2641 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2643 ret = kerberos_kinit_password_ext(c->opt_user_name,
2644 c->opt_password,
2646 NULL,
2647 NULL,
2648 NULL,
2649 true,
2650 true,
2651 2592000, /* one month */
2652 &status);
2653 if (ret) {
2654 d_printf(_("failed to kinit password: %s\n"),
2655 nt_errstr(status));
2657 out:
2658 return ret;
2661 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2663 struct functable func[] = {
2665 "kinit",
2666 net_ads_kerberos_kinit,
2667 NET_TRANSPORT_ADS,
2668 N_("Retrieve Ticket Granting Ticket (TGT)"),
2669 N_("net ads kerberos kinit\n"
2670 " Receive Ticket Granting Ticket (TGT)")
2673 "renew",
2674 net_ads_kerberos_renew,
2675 NET_TRANSPORT_ADS,
2676 N_("Renew Ticket Granting Ticket from credential cache"),
2677 N_("net ads kerberos renew\n"
2678 " Renew Ticket Granting Ticket (TGT) from "
2679 "credential cache")
2682 "pac",
2683 net_ads_kerberos_pac,
2684 NET_TRANSPORT_ADS,
2685 N_("Dump Kerberos PAC"),
2686 N_("net ads kerberos pac\n"
2687 " Dump Kerberos PAC")
2689 {NULL, NULL, 0, NULL, NULL}
2692 return net_run_function(c, argc, argv, "net ads kerberos", func);
2695 int net_ads(struct net_context *c, int argc, const char **argv)
2697 struct functable func[] = {
2699 "info",
2700 net_ads_info,
2701 NET_TRANSPORT_ADS,
2702 N_("Display details on remote ADS server"),
2703 N_("net ads info\n"
2704 " Display details on remote ADS server")
2707 "join",
2708 net_ads_join,
2709 NET_TRANSPORT_ADS,
2710 N_("Join the local machine to ADS realm"),
2711 N_("net ads join\n"
2712 " Join the local machine to ADS realm")
2715 "testjoin",
2716 net_ads_testjoin,
2717 NET_TRANSPORT_ADS,
2718 N_("Validate machine account"),
2719 N_("net ads testjoin\n"
2720 " Validate machine account")
2723 "leave",
2724 net_ads_leave,
2725 NET_TRANSPORT_ADS,
2726 N_("Remove the local machine from ADS"),
2727 N_("net ads leave\n"
2728 " Remove the local machine from ADS")
2731 "status",
2732 net_ads_status,
2733 NET_TRANSPORT_ADS,
2734 N_("Display machine account details"),
2735 N_("net ads status\n"
2736 " Display machine account details")
2739 "user",
2740 net_ads_user,
2741 NET_TRANSPORT_ADS,
2742 N_("List/modify users"),
2743 N_("net ads user\n"
2744 " List/modify users")
2747 "group",
2748 net_ads_group,
2749 NET_TRANSPORT_ADS,
2750 N_("List/modify groups"),
2751 N_("net ads group\n"
2752 " List/modify groups")
2755 "dns",
2756 net_ads_dns,
2757 NET_TRANSPORT_ADS,
2758 N_("Issue dynamic DNS update"),
2759 N_("net ads dns\n"
2760 " Issue dynamic DNS update")
2763 "password",
2764 net_ads_password,
2765 NET_TRANSPORT_ADS,
2766 N_("Change user passwords"),
2767 N_("net ads password\n"
2768 " Change user passwords")
2771 "changetrustpw",
2772 net_ads_changetrustpw,
2773 NET_TRANSPORT_ADS,
2774 N_("Change trust account password"),
2775 N_("net ads changetrustpw\n"
2776 " Change trust account password")
2779 "printer",
2780 net_ads_printer,
2781 NET_TRANSPORT_ADS,
2782 N_("List/modify printer entries"),
2783 N_("net ads printer\n"
2784 " List/modify printer entries")
2787 "search",
2788 net_ads_search,
2789 NET_TRANSPORT_ADS,
2790 N_("Issue LDAP search using filter"),
2791 N_("net ads search\n"
2792 " Issue LDAP search using filter")
2795 "dn",
2796 net_ads_dn,
2797 NET_TRANSPORT_ADS,
2798 N_("Issue LDAP search by DN"),
2799 N_("net ads dn\n"
2800 " Issue LDAP search by DN")
2803 "sid",
2804 net_ads_sid,
2805 NET_TRANSPORT_ADS,
2806 N_("Issue LDAP search by SID"),
2807 N_("net ads sid\n"
2808 " Issue LDAP search by SID")
2811 "workgroup",
2812 net_ads_workgroup,
2813 NET_TRANSPORT_ADS,
2814 N_("Display workgroup name"),
2815 N_("net ads workgroup\n"
2816 " Display the workgroup name")
2819 "lookup",
2820 net_ads_lookup,
2821 NET_TRANSPORT_ADS,
2822 N_("Perfom CLDAP query on DC"),
2823 N_("net ads lookup\n"
2824 " Find the ADS DC using CLDAP lookups")
2827 "keytab",
2828 net_ads_keytab,
2829 NET_TRANSPORT_ADS,
2830 N_("Manage local keytab file"),
2831 N_("net ads keytab\n"
2832 " Manage local keytab file")
2835 "gpo",
2836 net_ads_gpo,
2837 NET_TRANSPORT_ADS,
2838 N_("Manage group policy objects"),
2839 N_("net ads gpo\n"
2840 " Manage group policy objects")
2843 "kerberos",
2844 net_ads_kerberos,
2845 NET_TRANSPORT_ADS,
2846 N_("Manage kerberos keytab"),
2847 N_("net ads kerberos\n"
2848 " Manage kerberos keytab")
2850 {NULL, NULL, 0, NULL, NULL}
2853 return net_run_function(c, argc, argv, "net ads", func);
2856 #else
2858 static int net_ads_noads(void)
2860 d_fprintf(stderr, _("ADS support not compiled in\n"));
2861 return -1;
2864 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2866 return net_ads_noads();
2869 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2871 return net_ads_noads();
2874 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2876 return net_ads_noads();
2879 int net_ads_join(struct net_context *c, int argc, const char **argv)
2881 return net_ads_noads();
2884 int net_ads_user(struct net_context *c, int argc, const char **argv)
2886 return net_ads_noads();
2889 int net_ads_group(struct net_context *c, int argc, const char **argv)
2891 return net_ads_noads();
2894 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
2896 return net_ads_noads();
2899 /* this one shouldn't display a message */
2900 int net_ads_check(struct net_context *c)
2902 return -1;
2905 int net_ads_check_our_domain(struct net_context *c)
2907 return -1;
2910 int net_ads(struct net_context *c, int argc, const char **argv)
2912 return net_ads_noads();
2915 #endif /* HAVE_ADS */