check_parent_exists() can change errno. Ensure we preserve it across calls.
[Samba.git] / source3 / utils / net_ads.c
blob8f8b7b4cae0d9be65fef11199990a784999d14a9
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"
40 #include "utils/net_dns.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);
65 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
66 d_fprintf(stderr, _("CLDAP query failed!\n"));
67 return -1;
70 d_printf(_("Information for Domain Controller: %s\n\n"),
71 addr);
73 d_printf(_("Response Type: "));
74 switch (reply.command) {
75 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
76 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
77 break;
78 case LOGON_SAM_LOGON_RESPONSE_EX:
79 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
80 break;
81 default:
82 d_printf("0x%x\n", reply.command);
83 break;
86 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
88 d_printf(_("Flags:\n"
89 "\tIs a PDC: %s\n"
90 "\tIs a GC of the forest: %s\n"
91 "\tIs an LDAP server: %s\n"
92 "\tSupports DS: %s\n"
93 "\tIs running a KDC: %s\n"
94 "\tIs running time services: %s\n"
95 "\tIs the closest DC: %s\n"
96 "\tIs writable: %s\n"
97 "\tHas a hardware clock: %s\n"
98 "\tIs a non-domain NC serviced by LDAP server: %s\n"
99 "\tIs NT6 DC that has some secrets: %s\n"
100 "\tIs NT6 DC that has all secrets: %s\n"),
101 (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
102 (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
103 (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
104 (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
105 (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
106 (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
107 (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
108 (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
109 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
110 (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
111 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
112 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"));
115 printf(_("Forest:\t\t\t%s\n"), reply.forest);
116 printf(_("Domain:\t\t\t%s\n"), reply.dns_domain);
117 printf(_("Domain Controller:\t%s\n"), reply.pdc_dns_name);
119 printf(_("Pre-Win2k Domain:\t%s\n"), reply.domain_name);
120 printf(_("Pre-Win2k Hostname:\t%s\n"), reply.pdc_name);
122 if (*reply.user_name) printf(_("User name:\t%s\n"), reply.user_name);
124 printf(_("Server Site Name :\t\t%s\n"), reply.server_site);
125 printf(_("Client Site Name :\t\t%s\n"), reply.client_site);
127 d_printf(_("NT Version: %d\n"), reply.nt_version);
128 d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
129 d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
131 return 0;
135 this implements the CLDAP based netlogon lookup requests
136 for finding the domain controller of a ADS domain
138 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
140 ADS_STRUCT *ads;
141 int ret;
143 if (c->display_usage) {
144 d_printf("%s\n"
145 "net ads lookup\n"
146 " %s",
147 _("Usage:"),
148 _("Find the ADS DC using CLDAP lookup.\n"));
149 return 0;
152 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
153 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
154 ads_destroy(&ads);
155 return -1;
158 if (!ads->config.realm) {
159 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
160 ads->ldap.port = 389;
163 ret = net_ads_cldap_netlogon(c, ads);
164 ads_destroy(&ads);
165 return ret;
170 static int net_ads_info(struct net_context *c, int argc, const char **argv)
172 ADS_STRUCT *ads;
173 char addr[INET6_ADDRSTRLEN];
175 if (c->display_usage) {
176 d_printf("%s\n"
177 "net ads info\n"
178 " %s",
179 _("Usage:"),
180 _("Display information about an Active Directory "
181 "server.\n"));
182 return 0;
185 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
186 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
187 return -1;
190 if (!ads || !ads->config.realm) {
191 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
192 ads_destroy(&ads);
193 return -1;
196 /* Try to set the server's current time since we didn't do a full
197 TCP LDAP session initially */
199 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
200 d_fprintf( stderr, _("Failed to get server's current time!\n"));
203 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
205 d_printf(_("LDAP server: %s\n"), addr);
206 d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
207 d_printf(_("Realm: %s\n"), ads->config.realm);
208 d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
209 d_printf(_("LDAP port: %d\n"), ads->ldap.port);
210 d_printf(_("Server time: %s\n"),
211 http_timestring(talloc_tos(), ads->config.current_time));
213 d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
214 d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
216 ads_destroy(&ads);
217 return 0;
220 static void use_in_memory_ccache(void) {
221 /* Use in-memory credentials cache so we do not interfere with
222 * existing credentials */
223 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
226 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
227 uint32 auth_flags, ADS_STRUCT **ads_ret)
229 ADS_STRUCT *ads = NULL;
230 ADS_STATUS status;
231 bool need_password = false;
232 bool second_time = false;
233 char *cp;
234 const char *realm = NULL;
235 bool tried_closest_dc = false;
237 /* lp_realm() should be handled by a command line param,
238 However, the join requires that realm be set in smb.conf
239 and compares our realm with the remote server's so this is
240 ok until someone needs more flexibility */
242 *ads_ret = NULL;
244 retry_connect:
245 if (only_own_domain) {
246 realm = lp_realm();
247 } else {
248 realm = assume_own_realm(c);
251 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
253 if (!c->opt_user_name) {
254 c->opt_user_name = "administrator";
257 if (c->opt_user_specified) {
258 need_password = true;
261 retry:
262 if (!c->opt_password && need_password && !c->opt_machine_pass) {
263 c->opt_password = net_prompt_pass(c, c->opt_user_name);
264 if (!c->opt_password) {
265 ads_destroy(&ads);
266 return ADS_ERROR(LDAP_NO_MEMORY);
270 if (c->opt_password) {
271 use_in_memory_ccache();
272 SAFE_FREE(ads->auth.password);
273 ads->auth.password = smb_xstrdup(c->opt_password);
276 ads->auth.flags |= auth_flags;
277 SAFE_FREE(ads->auth.user_name);
278 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
281 * If the username is of the form "name@realm",
282 * extract the realm and convert to upper case.
283 * This is only used to establish the connection.
285 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
286 *cp++ = '\0';
287 SAFE_FREE(ads->auth.realm);
288 ads->auth.realm = smb_xstrdup(cp);
289 strupper_m(ads->auth.realm);
292 status = ads_connect(ads);
294 if (!ADS_ERR_OK(status)) {
296 if (NT_STATUS_EQUAL(ads_ntstatus(status),
297 NT_STATUS_NO_LOGON_SERVERS)) {
298 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
299 ads_destroy(&ads);
300 return status;
303 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
304 need_password = true;
305 second_time = true;
306 goto retry;
307 } else {
308 ads_destroy(&ads);
309 return status;
313 /* when contacting our own domain, make sure we use the closest DC.
314 * This is done by reconnecting to ADS because only the first call to
315 * ads_connect will give us our own sitename */
317 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
319 tried_closest_dc = true; /* avoid loop */
321 if (!ads_closest_dc(ads)) {
323 namecache_delete(ads->server.realm, 0x1C);
324 namecache_delete(ads->server.workgroup, 0x1C);
326 ads_destroy(&ads);
327 ads = NULL;
329 goto retry_connect;
333 *ads_ret = ads;
334 return status;
337 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
339 return ads_startup_int(c, only_own_domain, 0, ads);
342 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
344 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
348 Check to see if connection can be made via ads.
349 ads_startup() stores the password in opt_password if it needs to so
350 that rpc or rap can use it without re-prompting.
352 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
354 ADS_STRUCT *ads;
355 ADS_STATUS status;
357 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
358 return -1;
361 ads->auth.flags |= ADS_AUTH_NO_BIND;
363 status = ads_connect(ads);
364 if ( !ADS_ERR_OK(status) ) {
365 return -1;
368 ads_destroy(&ads);
369 return 0;
372 int net_ads_check_our_domain(struct net_context *c)
374 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
377 int net_ads_check(struct net_context *c)
379 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
383 determine the netbios workgroup name for a domain
385 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
387 ADS_STRUCT *ads;
388 char addr[INET6_ADDRSTRLEN];
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 = CONST_DISCARD(char *, c->opt_target_workgroup);
407 ads->ldap.port = 389;
410 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
411 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
412 d_fprintf(stderr, _("CLDAP query failed!\n"));
413 ads_destroy(&ads);
414 return -1;
417 d_printf(_("Workgroup: %s\n"), reply.domain_name);
419 ads_destroy(&ads);
421 return 0;
426 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
428 char **disp_fields = (char **) data_area;
430 if (!field) { /* must be end of record */
431 if (disp_fields[0]) {
432 if (!strchr_m(disp_fields[0], '$')) {
433 if (disp_fields[1])
434 d_printf("%-21.21s %s\n",
435 disp_fields[0], disp_fields[1]);
436 else
437 d_printf("%s\n", disp_fields[0]);
440 SAFE_FREE(disp_fields[0]);
441 SAFE_FREE(disp_fields[1]);
442 return true;
444 if (!values) /* must be new field, indicate string field */
445 return true;
446 if (StrCaseCmp(field, "sAMAccountName") == 0) {
447 disp_fields[0] = SMB_STRDUP((char *) values[0]);
449 if (StrCaseCmp(field, "description") == 0)
450 disp_fields[1] = SMB_STRDUP((char *) values[0]);
451 return true;
454 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
456 return net_user_usage(c, argc, argv);
459 static int ads_user_add(struct net_context *c, int argc, const char **argv)
461 ADS_STRUCT *ads;
462 ADS_STATUS status;
463 char *upn, *userdn;
464 LDAPMessage *res=NULL;
465 int rc = -1;
466 char *ou_str = NULL;
468 if (argc < 1 || c->display_usage)
469 return net_ads_user_usage(c, argc, argv);
471 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
472 return -1;
475 status = ads_find_user_acct(ads, &res, argv[0]);
477 if (!ADS_ERR_OK(status)) {
478 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
479 goto done;
482 if (ads_count_replies(ads, res)) {
483 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
484 argv[0]);
485 goto done;
488 if (c->opt_container) {
489 ou_str = SMB_STRDUP(c->opt_container);
490 } else {
491 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
494 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
496 if (!ADS_ERR_OK(status)) {
497 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
498 ads_errstr(status));
499 goto done;
502 /* if no password is to be set, we're done */
503 if (argc == 1) {
504 d_printf(_("User %s added\n"), argv[0]);
505 rc = 0;
506 goto done;
509 /* try setting the password */
510 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
511 goto done;
513 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
514 ads->auth.time_offset);
515 SAFE_FREE(upn);
516 if (ADS_ERR_OK(status)) {
517 d_printf(_("User %s added\n"), argv[0]);
518 rc = 0;
519 goto done;
522 /* password didn't set, delete account */
523 d_fprintf(stderr, _("Could not add user %s. "
524 "Error setting password %s\n"),
525 argv[0], ads_errstr(status));
526 ads_msgfree(ads, res);
527 status=ads_find_user_acct(ads, &res, argv[0]);
528 if (ADS_ERR_OK(status)) {
529 userdn = ads_get_dn(ads, talloc_tos(), res);
530 ads_del_dn(ads, userdn);
531 TALLOC_FREE(userdn);
534 done:
535 if (res)
536 ads_msgfree(ads, res);
537 ads_destroy(&ads);
538 SAFE_FREE(ou_str);
539 return rc;
542 static int ads_user_info(struct net_context *c, int argc, const char **argv)
544 ADS_STRUCT *ads = NULL;
545 ADS_STATUS rc;
546 LDAPMessage *res = NULL;
547 TALLOC_CTX *frame;
548 int ret = 0;
549 wbcErr wbc_status;
550 const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
551 char *searchstring=NULL;
552 char **grouplist;
553 char *primary_group;
554 char *escaped_user;
555 struct dom_sid primary_group_sid;
556 uint32_t group_rid;
557 enum wbcSidType type;
559 if (argc < 1 || c->display_usage) {
560 return net_ads_user_usage(c, argc, argv);
563 frame = talloc_new(talloc_tos());
564 if (frame == NULL) {
565 return -1;
568 escaped_user = escape_ldap_string(frame, argv[0]);
569 if (!escaped_user) {
570 d_fprintf(stderr,
571 _("ads_user_info: failed to escape user %s\n"),
572 argv[0]);
573 return -1;
576 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
577 ret = -1;
578 goto error;
581 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
582 ret =-1;
583 goto error;
585 rc = ads_search(ads, &res, searchstring, attrs);
586 SAFE_FREE(searchstring);
588 if (!ADS_ERR_OK(rc)) {
589 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(rc));
590 ret = -1;
591 goto error;
594 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
595 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
596 ret = -1;
597 goto error;
600 rc = ads_domain_sid(ads, &primary_group_sid);
601 if (!ADS_ERR_OK(rc)) {
602 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(rc));
603 ret = -1;
604 goto error;
607 sid_append_rid(&primary_group_sid, group_rid);
609 wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
610 NULL, /* don't look up domain */
611 &primary_group,
612 &type);
613 if (!WBC_ERROR_IS_OK(wbc_status)) {
614 d_fprintf(stderr, "wbcLookupSid: %s\n",
615 wbcErrorString(wbc_status));
616 ret = -1;
617 goto error;
620 d_printf("%s\n", primary_group);
622 wbcFreeMemory(primary_group);
624 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
625 (LDAPMessage *)res, "memberOf");
627 if (grouplist) {
628 int i;
629 char **groupname;
630 for (i=0;grouplist[i];i++) {
631 groupname = ldap_explode_dn(grouplist[i], 1);
632 d_printf("%s\n", groupname[0]);
633 ldap_value_free(groupname);
635 ldap_value_free(grouplist);
638 error:
639 if (res) ads_msgfree(ads, res);
640 if (ads) ads_destroy(&ads);
641 TALLOC_FREE(frame);
642 return ret;
645 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
647 ADS_STRUCT *ads;
648 ADS_STATUS rc;
649 LDAPMessage *res = NULL;
650 char *userdn;
652 if (argc < 1) {
653 return net_ads_user_usage(c, argc, argv);
656 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
657 return -1;
660 rc = ads_find_user_acct(ads, &res, argv[0]);
661 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
662 d_printf(_("User %s does not exist.\n"), argv[0]);
663 ads_msgfree(ads, res);
664 ads_destroy(&ads);
665 return -1;
667 userdn = ads_get_dn(ads, talloc_tos(), res);
668 ads_msgfree(ads, res);
669 rc = ads_del_dn(ads, userdn);
670 TALLOC_FREE(userdn);
671 if (ADS_ERR_OK(rc)) {
672 d_printf(_("User %s deleted\n"), argv[0]);
673 ads_destroy(&ads);
674 return 0;
676 d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
677 ads_errstr(rc));
678 ads_destroy(&ads);
679 return -1;
682 int net_ads_user(struct net_context *c, int argc, const char **argv)
684 struct functable func[] = {
686 "add",
687 ads_user_add,
688 NET_TRANSPORT_ADS,
689 N_("Add an AD user"),
690 N_("net ads user add\n"
691 " Add an AD user")
694 "info",
695 ads_user_info,
696 NET_TRANSPORT_ADS,
697 N_("Display information about an AD user"),
698 N_("net ads user info\n"
699 " Display information about an AD user")
702 "delete",
703 ads_user_delete,
704 NET_TRANSPORT_ADS,
705 N_("Delete an AD user"),
706 N_("net ads user delete\n"
707 " Delete an AD user")
709 {NULL, NULL, 0, NULL, NULL}
711 ADS_STRUCT *ads;
712 ADS_STATUS rc;
713 const char *shortattrs[] = {"sAMAccountName", NULL};
714 const char *longattrs[] = {"sAMAccountName", "description", NULL};
715 char *disp_fields[2] = {NULL, NULL};
717 if (argc == 0) {
718 if (c->display_usage) {
719 d_printf( "%s\n"
720 "net ads user\n"
721 " %s\n",
722 _("Usage:"),
723 _("List AD users"));
724 net_display_usage_from_functable(func);
725 return 0;
728 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
729 return -1;
732 if (c->opt_long_list_entries)
733 d_printf(_("\nUser name Comment"
734 "\n-----------------------------\n"));
736 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
737 LDAP_SCOPE_SUBTREE,
738 "(objectCategory=user)",
739 c->opt_long_list_entries ? longattrs :
740 shortattrs, usergrp_display,
741 disp_fields);
742 ads_destroy(&ads);
743 return ADS_ERR_OK(rc) ? 0 : -1;
746 return net_run_function(c, argc, argv, "net ads user", func);
749 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
751 return net_group_usage(c, argc, argv);
754 static int ads_group_add(struct net_context *c, int argc, const char **argv)
756 ADS_STRUCT *ads;
757 ADS_STATUS status;
758 LDAPMessage *res=NULL;
759 int rc = -1;
760 char *ou_str = NULL;
762 if (argc < 1 || c->display_usage) {
763 return net_ads_group_usage(c, argc, argv);
766 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
767 return -1;
770 status = ads_find_user_acct(ads, &res, argv[0]);
772 if (!ADS_ERR_OK(status)) {
773 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
774 goto done;
777 if (ads_count_replies(ads, res)) {
778 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
779 goto done;
782 if (c->opt_container) {
783 ou_str = SMB_STRDUP(c->opt_container);
784 } else {
785 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
788 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
790 if (ADS_ERR_OK(status)) {
791 d_printf(_("Group %s added\n"), argv[0]);
792 rc = 0;
793 } else {
794 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
795 ads_errstr(status));
798 done:
799 if (res)
800 ads_msgfree(ads, res);
801 ads_destroy(&ads);
802 SAFE_FREE(ou_str);
803 return rc;
806 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
808 ADS_STRUCT *ads;
809 ADS_STATUS rc;
810 LDAPMessage *res = NULL;
811 char *groupdn;
813 if (argc < 1 || c->display_usage) {
814 return net_ads_group_usage(c, argc, argv);
817 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
818 return -1;
821 rc = ads_find_user_acct(ads, &res, argv[0]);
822 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
823 d_printf(_("Group %s does not exist.\n"), argv[0]);
824 ads_msgfree(ads, res);
825 ads_destroy(&ads);
826 return -1;
828 groupdn = ads_get_dn(ads, talloc_tos(), res);
829 ads_msgfree(ads, res);
830 rc = ads_del_dn(ads, groupdn);
831 TALLOC_FREE(groupdn);
832 if (ADS_ERR_OK(rc)) {
833 d_printf(_("Group %s deleted\n"), argv[0]);
834 ads_destroy(&ads);
835 return 0;
837 d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
838 ads_errstr(rc));
839 ads_destroy(&ads);
840 return -1;
843 int net_ads_group(struct net_context *c, int argc, const char **argv)
845 struct functable func[] = {
847 "add",
848 ads_group_add,
849 NET_TRANSPORT_ADS,
850 N_("Add an AD group"),
851 N_("net ads group add\n"
852 " Add an AD group")
855 "delete",
856 ads_group_delete,
857 NET_TRANSPORT_ADS,
858 N_("Delete an AD group"),
859 N_("net ads group delete\n"
860 " Delete an AD group")
862 {NULL, NULL, 0, NULL, NULL}
864 ADS_STRUCT *ads;
865 ADS_STATUS rc;
866 const char *shortattrs[] = {"sAMAccountName", NULL};
867 const char *longattrs[] = {"sAMAccountName", "description", NULL};
868 char *disp_fields[2] = {NULL, NULL};
870 if (argc == 0) {
871 if (c->display_usage) {
872 d_printf( "%s\n"
873 "net ads group\n"
874 " %s\n",
875 _("Usage:"),
876 _("List AD groups"));
877 net_display_usage_from_functable(func);
878 return 0;
881 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
882 return -1;
885 if (c->opt_long_list_entries)
886 d_printf(_("\nGroup name Comment"
887 "\n-----------------------------\n"));
888 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
889 LDAP_SCOPE_SUBTREE,
890 "(objectCategory=group)",
891 c->opt_long_list_entries ? longattrs :
892 shortattrs, usergrp_display,
893 disp_fields);
895 ads_destroy(&ads);
896 return ADS_ERR_OK(rc) ? 0 : -1;
898 return net_run_function(c, argc, argv, "net ads group", func);
901 static int net_ads_status(struct net_context *c, int argc, const char **argv)
903 ADS_STRUCT *ads;
904 ADS_STATUS rc;
905 LDAPMessage *res;
907 if (c->display_usage) {
908 d_printf( "%s\n"
909 "net ads status\n"
910 " %s\n",
911 _("Usage:"),
912 _("Display machine account details"));
913 return 0;
916 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
917 return -1;
920 rc = ads_find_machine_acct(ads, &res, global_myname());
921 if (!ADS_ERR_OK(rc)) {
922 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
923 ads_destroy(&ads);
924 return -1;
927 if (ads_count_replies(ads, res) == 0) {
928 d_fprintf(stderr, _("No machine account for '%s' found\n"), global_myname());
929 ads_destroy(&ads);
930 return -1;
933 ads_dump(ads, res);
934 ads_destroy(&ads);
935 return 0;
938 /*******************************************************************
939 Leave an AD domain. Windows XP disables the machine account.
940 We'll try the same. The old code would do an LDAP delete.
941 That only worked using the machine creds because added the machine
942 with full control to the computer object's ACL.
943 *******************************************************************/
945 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
947 TALLOC_CTX *ctx;
948 struct libnet_UnjoinCtx *r = NULL;
949 WERROR werr;
951 if (c->display_usage) {
952 d_printf( "%s\n"
953 "net ads leave\n"
954 " %s\n",
955 _("Usage:"),
956 _("Leave an AD domain"));
957 return 0;
960 if (!*lp_realm()) {
961 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
962 return -1;
965 if (!(ctx = talloc_init("net_ads_leave"))) {
966 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
967 return -1;
970 if (!c->opt_kerberos) {
971 use_in_memory_ccache();
974 if (!c->msg_ctx) {
975 d_fprintf(stderr, _("Could not initialise message context. "
976 "Try running as root\n"));
977 return -1;
980 werr = libnet_init_UnjoinCtx(ctx, &r);
981 if (!W_ERROR_IS_OK(werr)) {
982 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
983 return -1;
986 r->in.debug = true;
987 r->in.use_kerberos = c->opt_kerberos;
988 r->in.dc_name = c->opt_host;
989 r->in.domain_name = lp_realm();
990 r->in.admin_account = c->opt_user_name;
991 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
992 r->in.modify_config = lp_config_backend_is_registry();
994 /* Try to delete it, but if that fails, disable it. The
995 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
996 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
997 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
998 r->in.delete_machine_account = true;
999 r->in.msg_ctx = c->msg_ctx;
1001 werr = libnet_Unjoin(ctx, r);
1002 if (!W_ERROR_IS_OK(werr)) {
1003 d_printf(_("Failed to leave domain: %s\n"),
1004 r->out.error_string ? r->out.error_string :
1005 get_friendly_werror_msg(werr));
1006 goto done;
1009 if (r->out.deleted_machine_account) {
1010 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1011 r->in.machine_name, r->out.dns_domain_name);
1012 goto done;
1015 /* We couldn't delete it - see if the disable succeeded. */
1016 if (r->out.disabled_machine_account) {
1017 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1018 r->in.machine_name, r->out.dns_domain_name);
1019 werr = WERR_OK;
1020 goto done;
1023 /* Based on what we requseted, we shouldn't get here, but if
1024 we did, it means the secrets were removed, and therefore
1025 we have left the domain */
1026 d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1027 r->in.machine_name, r->out.dns_domain_name);
1029 done:
1030 TALLOC_FREE(r);
1031 TALLOC_FREE(ctx);
1033 if (W_ERROR_IS_OK(werr)) {
1034 return 0;
1037 return -1;
1040 static NTSTATUS net_ads_join_ok(struct net_context *c)
1042 ADS_STRUCT *ads = NULL;
1043 ADS_STATUS status;
1044 fstring dc_name;
1045 struct sockaddr_storage dcip;
1047 if (!secrets_init()) {
1048 DEBUG(1,("Failed to initialise secrets database\n"));
1049 return NT_STATUS_ACCESS_DENIED;
1052 net_use_krb_machine_account(c);
1054 get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1056 status = ads_startup(c, true, &ads);
1057 if (!ADS_ERR_OK(status)) {
1058 return ads_ntstatus(status);
1061 ads_destroy(&ads);
1062 return NT_STATUS_OK;
1066 check that an existing join is OK
1068 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1070 NTSTATUS status;
1071 use_in_memory_ccache();
1073 if (c->display_usage) {
1074 d_printf( "%s\n"
1075 "net ads testjoin\n"
1076 " %s\n",
1077 _("Usage:"),
1078 _("Test if the existing join is ok"));
1079 return 0;
1082 /* Display success or failure */
1083 status = net_ads_join_ok(c);
1084 if (!NT_STATUS_IS_OK(status)) {
1085 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1086 get_friendly_nt_error_msg(status));
1087 return -1;
1090 printf(_("Join is OK\n"));
1091 return 0;
1094 /*******************************************************************
1095 Simple configu checks before beginning the join
1096 ********************************************************************/
1098 static WERROR check_ads_config( void )
1100 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1101 d_printf(_("Host is not configured as a member server.\n"));
1102 return WERR_INVALID_DOMAIN_ROLE;
1105 if (strlen(global_myname()) > 15) {
1106 d_printf(_("Our netbios name can be at most 15 chars long, "
1107 "\"%s\" is %u chars long\n"), global_myname(),
1108 (unsigned int)strlen(global_myname()));
1109 return WERR_INVALID_COMPUTERNAME;
1112 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1113 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1114 "join to succeed.\n"), get_dyn_CONFIGFILE());
1115 return WERR_INVALID_PARAM;
1118 return WERR_OK;
1121 /*******************************************************************
1122 Send a DNS update request
1123 *******************************************************************/
1125 #if defined(WITH_DNS_UPDATES)
1126 #include "../lib/addns/dns.h"
1128 static NTSTATUS net_update_dns_internal(struct net_context *c,
1129 TALLOC_CTX *ctx, ADS_STRUCT *ads,
1130 const char *machine_name,
1131 const struct sockaddr_storage *addrs,
1132 int num_addrs)
1134 struct dns_rr_ns *nameservers = NULL;
1135 int ns_count = 0, i;
1136 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1137 DNS_ERROR dns_err;
1138 fstring dns_server;
1139 const char *dnsdomain = NULL;
1140 char *root_domain = NULL;
1142 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1143 d_printf(_("No DNS domain configured for %s. "
1144 "Unable to perform DNS Update.\n"), machine_name);
1145 status = NT_STATUS_INVALID_PARAMETER;
1146 goto done;
1148 dnsdomain++;
1150 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1151 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1152 /* Child domains often do not have NS records. Look
1153 for the NS record for the forest root domain
1154 (rootDomainNamingContext in therootDSE) */
1156 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1157 LDAPMessage *msg = NULL;
1158 char *root_dn;
1159 ADS_STATUS ads_status;
1161 if ( !ads->ldap.ld ) {
1162 ads_status = ads_connect( ads );
1163 if ( !ADS_ERR_OK(ads_status) ) {
1164 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1165 goto done;
1169 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1170 "(objectclass=*)", rootname_attrs, &msg);
1171 if (!ADS_ERR_OK(ads_status)) {
1172 goto done;
1175 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1176 if ( !root_dn ) {
1177 ads_msgfree( ads, msg );
1178 goto done;
1181 root_domain = ads_build_domain( root_dn );
1183 /* cleanup */
1184 ads_msgfree( ads, msg );
1186 /* try again for NS servers */
1188 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1190 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1191 DEBUG(3,("net_update_dns_internal: Failed to find name server for the %s "
1192 "realm\n", ads->config.realm));
1193 goto done;
1196 dnsdomain = root_domain;
1200 for (i=0; i < ns_count; i++) {
1202 uint32_t flags = DNS_UPDATE_SIGNED |
1203 DNS_UPDATE_UNSIGNED |
1204 DNS_UPDATE_UNSIGNED_SUFFICIENT |
1205 DNS_UPDATE_PROBE |
1206 DNS_UPDATE_PROBE_SUFFICIENT;
1208 if (c->opt_force) {
1209 flags &= ~DNS_UPDATE_PROBE_SUFFICIENT;
1210 flags &= ~DNS_UPDATE_UNSIGNED_SUFFICIENT;
1213 status = NT_STATUS_UNSUCCESSFUL;
1215 /* Now perform the dns update - we'll try non-secure and if we fail,
1216 we'll follow it up with a secure update */
1218 fstrcpy( dns_server, nameservers[i].hostname );
1220 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs, flags);
1221 if (ERR_DNS_IS_OK(dns_err)) {
1222 status = NT_STATUS_OK;
1223 goto done;
1226 if (ERR_DNS_EQUAL(dns_err, ERROR_DNS_INVALID_NAME_SERVER) ||
1227 ERR_DNS_EQUAL(dns_err, ERROR_DNS_CONNECTION_FAILED) ||
1228 ERR_DNS_EQUAL(dns_err, ERROR_DNS_SOCKET_ERROR)) {
1229 DEBUG(1,("retrying DNS update with next nameserver after receiving %s\n",
1230 dns_errstr(dns_err)));
1231 continue;
1234 d_printf(_("DNS Update for %s failed: %s\n"),
1235 machine_name, dns_errstr(dns_err));
1236 status = NT_STATUS_UNSUCCESSFUL;
1237 goto done;
1240 done:
1242 SAFE_FREE( root_domain );
1244 return status;
1247 static NTSTATUS net_update_dns_ext(struct net_context *c,
1248 TALLOC_CTX *mem_ctx, ADS_STRUCT *ads,
1249 const char *hostname,
1250 struct sockaddr_storage *iplist,
1251 int num_addrs)
1253 struct sockaddr_storage *iplist_alloc = NULL;
1254 fstring machine_name;
1255 NTSTATUS status;
1257 if (hostname) {
1258 fstrcpy(machine_name, hostname);
1259 } else {
1260 name_to_fqdn( machine_name, global_myname() );
1262 strlower_m( machine_name );
1264 if (num_addrs == 0 || iplist == NULL) {
1266 * Get our ip address
1267 * (not the 127.0.0.x address but a real ip address)
1269 num_addrs = get_my_ip_address(&iplist_alloc);
1270 if ( num_addrs <= 0 ) {
1271 DEBUG(4, ("net_update_dns_ext: Failed to find my "
1272 "non-loopback IP addresses!\n"));
1273 return NT_STATUS_INVALID_PARAMETER;
1275 iplist = iplist_alloc;
1278 status = net_update_dns_internal(c, mem_ctx, ads, machine_name,
1279 iplist, num_addrs);
1281 SAFE_FREE(iplist_alloc);
1282 return status;
1285 static NTSTATUS net_update_dns(struct net_context *c, TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, const char *hostname)
1287 NTSTATUS status;
1289 status = net_update_dns_ext(c, mem_ctx, ads, hostname, NULL, 0);
1290 return status;
1292 #endif
1295 /*******************************************************************
1296 ********************************************************************/
1298 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1300 d_printf(_("net ads join [options]\n"
1301 "Valid options:\n"));
1302 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1303 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1304 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1305 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1306 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1307 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1308 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1309 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1310 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1311 " NB: osName and osVer must be specified together for either to take effect.\n"
1312 " Also, the operatingSystemService attribute is also set when along with\n"
1313 " the two other attributes.\n"));
1315 return -1;
1318 /*******************************************************************
1319 ********************************************************************/
1321 int net_ads_join(struct net_context *c, int argc, const char **argv)
1323 TALLOC_CTX *ctx = NULL;
1324 struct libnet_JoinCtx *r = NULL;
1325 const char *domain = lp_realm();
1326 WERROR werr = WERR_SETUP_NOT_JOINED;
1327 bool createupn = false;
1328 const char *machineupn = NULL;
1329 const char *create_in_ou = NULL;
1330 int i;
1331 const char *os_name = NULL;
1332 const char *os_version = NULL;
1333 bool modify_config = lp_config_backend_is_registry();
1335 if (c->display_usage)
1336 return net_ads_join_usage(c, argc, argv);
1338 if (!modify_config) {
1340 werr = check_ads_config();
1341 if (!W_ERROR_IS_OK(werr)) {
1342 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1343 goto fail;
1347 if (!(ctx = talloc_init("net_ads_join"))) {
1348 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1349 werr = WERR_NOMEM;
1350 goto fail;
1353 if (!c->opt_kerberos) {
1354 use_in_memory_ccache();
1357 werr = libnet_init_JoinCtx(ctx, &r);
1358 if (!W_ERROR_IS_OK(werr)) {
1359 goto fail;
1362 /* process additional command line args */
1364 for ( i=0; i<argc; i++ ) {
1365 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1366 createupn = true;
1367 machineupn = get_string_param(argv[i]);
1369 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1370 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1371 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1372 werr = WERR_INVALID_PARAM;
1373 goto fail;
1376 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1377 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1378 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1379 werr = WERR_INVALID_PARAM;
1380 goto fail;
1383 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1384 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1385 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1386 werr = WERR_INVALID_PARAM;
1387 goto fail;
1390 else {
1391 domain = argv[i];
1395 if (!*domain) {
1396 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1397 werr = WERR_INVALID_PARAM;
1398 goto fail;
1401 if (!c->msg_ctx) {
1402 d_fprintf(stderr, _("Could not initialise message context. "
1403 "Try running as root\n"));
1404 werr = WERR_ACCESS_DENIED;
1405 goto fail;
1408 /* Do the domain join here */
1410 r->in.domain_name = domain;
1411 r->in.create_upn = createupn;
1412 r->in.upn = machineupn;
1413 r->in.account_ou = create_in_ou;
1414 r->in.os_name = os_name;
1415 r->in.os_version = os_version;
1416 r->in.dc_name = c->opt_host;
1417 r->in.admin_account = c->opt_user_name;
1418 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1419 r->in.debug = true;
1420 r->in.use_kerberos = c->opt_kerberos;
1421 r->in.modify_config = modify_config;
1422 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1423 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1424 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1425 r->in.msg_ctx = c->msg_ctx;
1427 werr = libnet_Join(ctx, r);
1428 if (W_ERROR_EQUAL(werr, WERR_DCNOTFOUND) &&
1429 strequal(domain, lp_realm())) {
1430 r->in.domain_name = lp_workgroup();
1431 werr = libnet_Join(ctx, r);
1433 if (!W_ERROR_IS_OK(werr)) {
1434 goto fail;
1437 /* Check the short name of the domain */
1439 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1440 d_printf(_("The workgroup in %s does not match the short\n"
1441 "domain name obtained from the server.\n"
1442 "Using the name [%s] from the server.\n"
1443 "You should set \"workgroup = %s\" in %s.\n"),
1444 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1445 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1448 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1450 if (r->out.dns_domain_name) {
1451 d_printf(_("Joined '%s' to dns domain '%s'\n"), r->in.machine_name,
1452 r->out.dns_domain_name);
1453 } else {
1454 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1455 r->out.netbios_domain_name);
1458 #if defined(WITH_DNS_UPDATES)
1460 * In a clustered environment, don't do dynamic dns updates:
1461 * Registering the set of ip addresses that are assigned to
1462 * the interfaces of the node that performs the join does usually
1463 * not have the desired effect, since the local interfaces do not
1464 * carry the complete set of the cluster's public IP addresses.
1465 * And it can also contain internal addresses that should not
1466 * be visible to the outside at all.
1467 * In order to do dns updates in a clustererd setup, use
1468 * net ads dns register.
1470 if (lp_clustering()) {
1471 d_fprintf(stderr, _("Not doing automatic DNS update in a"
1472 "clustered setup.\n"));
1473 goto done;
1476 if (r->out.domain_is_ad) {
1477 /* We enter this block with user creds */
1478 ADS_STRUCT *ads_dns = NULL;
1480 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1481 /* kinit with the machine password */
1483 use_in_memory_ccache();
1484 if (asprintf( &ads_dns->auth.user_name, "%s$", global_myname()) == -1) {
1485 goto fail;
1487 ads_dns->auth.password = secrets_fetch_machine_password(
1488 r->out.netbios_domain_name, NULL, NULL );
1489 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1490 strupper_m(ads_dns->auth.realm );
1491 ads_kinit_password( ads_dns );
1494 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns(c, ctx, ads_dns, NULL)) ) {
1495 d_fprintf( stderr, _("DNS update failed!\n") );
1498 /* exit from this block using machine creds */
1499 ads_destroy(&ads_dns);
1502 done:
1503 #endif
1505 TALLOC_FREE(r);
1506 TALLOC_FREE( ctx );
1508 return 0;
1510 fail:
1511 /* issue an overall failure message at the end. */
1512 d_printf(_("Failed to join domain: %s\n"),
1513 r && r->out.error_string ? r->out.error_string :
1514 get_friendly_werror_msg(werr));
1515 TALLOC_FREE( ctx );
1517 return -1;
1520 /*******************************************************************
1521 ********************************************************************/
1523 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1525 #if defined(WITH_DNS_UPDATES)
1526 ADS_STRUCT *ads;
1527 ADS_STATUS status;
1528 NTSTATUS ntstatus;
1529 TALLOC_CTX *ctx;
1530 const char *hostname = NULL;
1531 const char **addrs_list = NULL;
1532 struct sockaddr_storage *addrs = NULL;
1533 int num_addrs = 0;
1534 int count;
1536 #ifdef DEVELOPER
1537 talloc_enable_leak_report();
1538 #endif
1540 if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
1541 d_fprintf(stderr, _("Refusing DNS updates with automatic "
1542 "detection of addresses in a clustered "
1543 "setup.\n"));
1544 c->display_usage = true;
1547 if (c->display_usage) {
1548 d_printf( "%s\n"
1549 "net ads dns register [hostname [IP [IP...]]]\n"
1550 " %s\n",
1551 _("Usage:"),
1552 _("Register hostname with DNS\n"));
1553 return -1;
1556 if (!(ctx = talloc_init("net_ads_dns"))) {
1557 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1558 return -1;
1561 if (argc >= 1) {
1562 hostname = argv[0];
1565 if (argc > 1) {
1566 num_addrs = argc - 1;
1567 addrs_list = &argv[1];
1568 } else if (lp_clustering()) {
1569 addrs_list = lp_cluster_addresses();
1570 num_addrs = str_list_length(addrs_list);
1573 if (num_addrs > 0) {
1574 addrs = talloc_zero_array(ctx, struct sockaddr_storage, num_addrs);
1575 if (addrs == NULL) {
1576 d_fprintf(stderr, _("Error allocating memory!\n"));
1577 talloc_free(ctx);
1578 return -1;
1582 for (count = 0; count < num_addrs; count++) {
1583 if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
1584 d_fprintf(stderr, "%s '%s'.\n",
1585 _("Cannot interpret address"),
1586 addrs_list[count]);
1587 talloc_free(ctx);
1588 return -1;
1592 status = ads_startup(c, true, &ads);
1593 if ( !ADS_ERR_OK(status) ) {
1594 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1595 TALLOC_FREE(ctx);
1596 return -1;
1599 ntstatus = net_update_dns_ext(c, ctx, ads, hostname, addrs, num_addrs);
1600 if (!NT_STATUS_IS_OK(ntstatus)) {
1601 d_fprintf( stderr, _("DNS update failed!\n") );
1602 ads_destroy( &ads );
1603 TALLOC_FREE( ctx );
1604 return -1;
1607 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1609 ads_destroy(&ads);
1610 TALLOC_FREE( ctx );
1612 return 0;
1613 #else
1614 d_fprintf(stderr,
1615 _("DNS update support not enabled at compile time!\n"));
1616 return -1;
1617 #endif
1620 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1622 #if defined(WITH_DNS_UPDATES)
1623 DNS_ERROR err;
1625 #ifdef DEVELOPER
1626 talloc_enable_leak_report();
1627 #endif
1629 if (argc != 2 || c->display_usage) {
1630 d_printf( "%s\n"
1631 " %s\n"
1632 " %s\n",
1633 _("Usage:"),
1634 _("net ads dns gethostbyname <server> <name>\n"),
1635 _(" Look up hostname from the AD\n"
1636 " server\tName server to use\n"
1637 " name\tName to look up\n"));
1638 return -1;
1641 err = do_gethostbyname(argv[0], argv[1]);
1643 d_printf(_("do_gethostbyname returned %s (%d)\n"),
1644 dns_errstr(err), ERROR_DNS_V(err));
1645 #endif
1646 return 0;
1649 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1651 struct functable func[] = {
1653 "register",
1654 net_ads_dns_register,
1655 NET_TRANSPORT_ADS,
1656 N_("Add host dns entry to AD"),
1657 N_("net ads dns register\n"
1658 " Add host dns entry to AD")
1661 "gethostbyname",
1662 net_ads_dns_gethostbyname,
1663 NET_TRANSPORT_ADS,
1664 N_("Look up host"),
1665 N_("net ads dns gethostbyname\n"
1666 " Look up host")
1668 {NULL, NULL, 0, NULL, NULL}
1671 return net_run_function(c, argc, argv, "net ads dns", func);
1674 /*******************************************************************
1675 ********************************************************************/
1677 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1679 d_printf(_(
1680 "\nnet ads printer search <printer>"
1681 "\n\tsearch for a printer in the directory\n"
1682 "\nnet ads printer info <printer> <server>"
1683 "\n\tlookup info in directory for printer on server"
1684 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1685 "\nnet ads printer publish <printername>"
1686 "\n\tpublish printer in directory"
1687 "\n\t(note: printer name is required)\n"
1688 "\nnet ads printer remove <printername>"
1689 "\n\tremove printer from directory"
1690 "\n\t(note: printer name is required)\n"));
1691 return -1;
1694 /*******************************************************************
1695 ********************************************************************/
1697 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1699 ADS_STRUCT *ads;
1700 ADS_STATUS rc;
1701 LDAPMessage *res = NULL;
1703 if (c->display_usage) {
1704 d_printf( "%s\n"
1705 "net ads printer search\n"
1706 " %s\n",
1707 _("Usage:"),
1708 _("List printers in the AD"));
1709 return 0;
1712 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1713 return -1;
1716 rc = ads_find_printers(ads, &res);
1718 if (!ADS_ERR_OK(rc)) {
1719 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
1720 ads_msgfree(ads, res);
1721 ads_destroy(&ads);
1722 return -1;
1725 if (ads_count_replies(ads, res) == 0) {
1726 d_fprintf(stderr, _("No results found\n"));
1727 ads_msgfree(ads, res);
1728 ads_destroy(&ads);
1729 return -1;
1732 ads_dump(ads, res);
1733 ads_msgfree(ads, res);
1734 ads_destroy(&ads);
1735 return 0;
1738 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1740 ADS_STRUCT *ads;
1741 ADS_STATUS rc;
1742 const char *servername, *printername;
1743 LDAPMessage *res = NULL;
1745 if (c->display_usage) {
1746 d_printf("%s\n%s",
1747 _("Usage:"),
1748 _("net ads printer info [printername [servername]]\n"
1749 " Display printer info from AD\n"
1750 " printername\tPrinter name or wildcard\n"
1751 " servername\tName of the print server\n"));
1752 return 0;
1755 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1756 return -1;
1759 if (argc > 0) {
1760 printername = argv[0];
1761 } else {
1762 printername = "*";
1765 if (argc > 1) {
1766 servername = argv[1];
1767 } else {
1768 servername = global_myname();
1771 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1773 if (!ADS_ERR_OK(rc)) {
1774 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
1775 servername, ads_errstr(rc));
1776 ads_msgfree(ads, res);
1777 ads_destroy(&ads);
1778 return -1;
1781 if (ads_count_replies(ads, res) == 0) {
1782 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
1783 ads_msgfree(ads, res);
1784 ads_destroy(&ads);
1785 return -1;
1788 ads_dump(ads, res);
1789 ads_msgfree(ads, res);
1790 ads_destroy(&ads);
1792 return 0;
1795 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1797 ADS_STRUCT *ads;
1798 ADS_STATUS rc;
1799 const char *servername, *printername;
1800 struct cli_state *cli = NULL;
1801 struct rpc_pipe_client *pipe_hnd = NULL;
1802 struct sockaddr_storage server_ss;
1803 NTSTATUS nt_status;
1804 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1805 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1806 char *prt_dn, *srv_dn, **srv_cn;
1807 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1808 LDAPMessage *res = NULL;
1810 if (argc < 1 || c->display_usage) {
1811 d_printf("%s\n%s",
1812 _("Usage:"),
1813 _("net ads printer publish <printername> [servername]\n"
1814 " Publish printer in AD\n"
1815 " printername\tName of the printer\n"
1816 " servername\tName of the print server\n"));
1817 talloc_destroy(mem_ctx);
1818 return -1;
1821 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1822 talloc_destroy(mem_ctx);
1823 return -1;
1826 printername = argv[0];
1828 if (argc == 2) {
1829 servername = argv[1];
1830 } else {
1831 servername = global_myname();
1834 /* Get printer data from SPOOLSS */
1836 resolve_name(servername, &server_ss, 0x20, false);
1838 nt_status = cli_full_connection(&cli, global_myname(), servername,
1839 &server_ss, 0,
1840 "IPC$", "IPC",
1841 c->opt_user_name, c->opt_workgroup,
1842 c->opt_password ? c->opt_password : "",
1843 CLI_FULL_CONNECTION_USE_KERBEROS,
1844 Undefined);
1846 if (NT_STATUS_IS_ERR(nt_status)) {
1847 d_fprintf(stderr, _("Unable to open a connection to %s to "
1848 "obtain data for %s\n"),
1849 servername, printername);
1850 ads_destroy(&ads);
1851 talloc_destroy(mem_ctx);
1852 return -1;
1855 /* Publish on AD server */
1857 ads_find_machine_acct(ads, &res, servername);
1859 if (ads_count_replies(ads, res) == 0) {
1860 d_fprintf(stderr, _("Could not find machine account for server "
1861 "%s\n"),
1862 servername);
1863 ads_destroy(&ads);
1864 talloc_destroy(mem_ctx);
1865 return -1;
1868 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1869 srv_cn = ldap_explode_dn(srv_dn, 1);
1871 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1872 printername_escaped = escape_rdn_val_string_alloc(printername);
1873 if (!srv_cn_escaped || !printername_escaped) {
1874 SAFE_FREE(srv_cn_escaped);
1875 SAFE_FREE(printername_escaped);
1876 d_fprintf(stderr, _("Internal error, out of memory!"));
1877 ads_destroy(&ads);
1878 talloc_destroy(mem_ctx);
1879 return -1;
1882 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1883 SAFE_FREE(srv_cn_escaped);
1884 SAFE_FREE(printername_escaped);
1885 d_fprintf(stderr, _("Internal error, out of memory!"));
1886 ads_destroy(&ads);
1887 talloc_destroy(mem_ctx);
1888 return -1;
1891 SAFE_FREE(srv_cn_escaped);
1892 SAFE_FREE(printername_escaped);
1894 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
1895 if (!NT_STATUS_IS_OK(nt_status)) {
1896 d_fprintf(stderr, _("Unable to open a connection to the spoolss pipe on %s\n"),
1897 servername);
1898 SAFE_FREE(prt_dn);
1899 ads_destroy(&ads);
1900 talloc_destroy(mem_ctx);
1901 return -1;
1904 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1905 printername))) {
1906 SAFE_FREE(prt_dn);
1907 ads_destroy(&ads);
1908 talloc_destroy(mem_ctx);
1909 return -1;
1912 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1913 if (!ADS_ERR_OK(rc)) {
1914 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1915 SAFE_FREE(prt_dn);
1916 ads_destroy(&ads);
1917 talloc_destroy(mem_ctx);
1918 return -1;
1921 d_printf("published printer\n");
1922 SAFE_FREE(prt_dn);
1923 ads_destroy(&ads);
1924 talloc_destroy(mem_ctx);
1926 return 0;
1929 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1931 ADS_STRUCT *ads;
1932 ADS_STATUS rc;
1933 const char *servername;
1934 char *prt_dn;
1935 LDAPMessage *res = NULL;
1937 if (argc < 1 || c->display_usage) {
1938 d_printf("%s\n%s",
1939 _("Usage:"),
1940 _("net ads printer remove <printername> [servername]\n"
1941 " Remove a printer from the AD\n"
1942 " printername\tName of the printer\n"
1943 " servername\tName of the print server\n"));
1944 return -1;
1947 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1948 return -1;
1951 if (argc > 1) {
1952 servername = argv[1];
1953 } else {
1954 servername = global_myname();
1957 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1959 if (!ADS_ERR_OK(rc)) {
1960 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
1961 ads_msgfree(ads, res);
1962 ads_destroy(&ads);
1963 return -1;
1966 if (ads_count_replies(ads, res) == 0) {
1967 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
1968 ads_msgfree(ads, res);
1969 ads_destroy(&ads);
1970 return -1;
1973 prt_dn = ads_get_dn(ads, talloc_tos(), res);
1974 ads_msgfree(ads, res);
1975 rc = ads_del_dn(ads, prt_dn);
1976 TALLOC_FREE(prt_dn);
1978 if (!ADS_ERR_OK(rc)) {
1979 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
1980 ads_destroy(&ads);
1981 return -1;
1984 ads_destroy(&ads);
1985 return 0;
1988 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1990 struct functable func[] = {
1992 "search",
1993 net_ads_printer_search,
1994 NET_TRANSPORT_ADS,
1995 N_("Search for a printer"),
1996 N_("net ads printer search\n"
1997 " Search for a printer")
2000 "info",
2001 net_ads_printer_info,
2002 NET_TRANSPORT_ADS,
2003 N_("Display printer information"),
2004 N_("net ads printer info\n"
2005 " Display printer information")
2008 "publish",
2009 net_ads_printer_publish,
2010 NET_TRANSPORT_ADS,
2011 N_("Publish a printer"),
2012 N_("net ads printer publish\n"
2013 " Publish a printer")
2016 "remove",
2017 net_ads_printer_remove,
2018 NET_TRANSPORT_ADS,
2019 N_("Delete a printer"),
2020 N_("net ads printer remove\n"
2021 " Delete a printer")
2023 {NULL, NULL, 0, NULL, NULL}
2026 return net_run_function(c, argc, argv, "net ads printer", func);
2030 static int net_ads_password(struct net_context *c, int argc, const char **argv)
2032 ADS_STRUCT *ads;
2033 const char *auth_principal = c->opt_user_name;
2034 const char *auth_password = c->opt_password;
2035 char *realm = NULL;
2036 char *new_password = NULL;
2037 char *chr, *prompt;
2038 const char *user;
2039 ADS_STATUS ret;
2041 if (c->display_usage) {
2042 d_printf("%s\n%s",
2043 _("Usage:"),
2044 _("net ads password <username>\n"
2045 " Change password for user\n"
2046 " username\tName of user to change password for\n"));
2047 return 0;
2050 if (c->opt_user_name == NULL || c->opt_password == NULL) {
2051 d_fprintf(stderr, _("You must supply an administrator "
2052 "username/password\n"));
2053 return -1;
2056 if (argc < 1) {
2057 d_fprintf(stderr, _("ERROR: You must say which username to "
2058 "change password for\n"));
2059 return -1;
2062 user = argv[0];
2063 if (!strchr_m(user, '@')) {
2064 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
2065 return -1;
2067 user = chr;
2070 use_in_memory_ccache();
2071 chr = strchr_m(auth_principal, '@');
2072 if (chr) {
2073 realm = ++chr;
2074 } else {
2075 realm = lp_realm();
2078 /* use the realm so we can eventually change passwords for users
2079 in realms other than default */
2080 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
2081 return -1;
2084 /* we don't actually need a full connect, but it's the easy way to
2085 fill in the KDC's addresss */
2086 ads_connect(ads);
2088 if (!ads->config.realm) {
2089 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
2090 ads_destroy(&ads);
2091 return -1;
2094 if (argv[1]) {
2095 new_password = (char *)argv[1];
2096 } else {
2097 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
2098 return -1;
2100 new_password = getpass(prompt);
2101 free(prompt);
2104 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2105 auth_password, user, new_password, ads->auth.time_offset);
2106 if (!ADS_ERR_OK(ret)) {
2107 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2108 ads_destroy(&ads);
2109 return -1;
2112 d_printf(_("Password change for %s completed.\n"), user);
2113 ads_destroy(&ads);
2115 return 0;
2118 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2120 ADS_STRUCT *ads;
2121 char *host_principal;
2122 fstring my_name;
2123 ADS_STATUS ret;
2125 if (c->display_usage) {
2126 d_printf( "%s\n"
2127 "net ads changetrustpw\n"
2128 " %s\n",
2129 _("Usage:"),
2130 _("Change the machine account's trust password"));
2131 return 0;
2134 if (!secrets_init()) {
2135 DEBUG(1,("Failed to initialise secrets database\n"));
2136 return -1;
2139 net_use_krb_machine_account(c);
2141 use_in_memory_ccache();
2143 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2144 return -1;
2147 fstrcpy(my_name, global_myname());
2148 strlower_m(my_name);
2149 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2150 ads_destroy(&ads);
2151 return -1;
2153 d_printf(_("Changing password for principal: %s\n"), host_principal);
2155 ret = ads_change_trust_account_password(ads, host_principal);
2157 if (!ADS_ERR_OK(ret)) {
2158 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2159 ads_destroy(&ads);
2160 SAFE_FREE(host_principal);
2161 return -1;
2164 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2166 if (USE_SYSTEM_KEYTAB) {
2167 d_printf(_("Attempting to update system keytab with new password.\n"));
2168 if (ads_keytab_create_default(ads)) {
2169 d_printf(_("Failed to update system keytab.\n"));
2173 ads_destroy(&ads);
2174 SAFE_FREE(host_principal);
2176 return 0;
2180 help for net ads search
2182 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2184 d_printf(_(
2185 "\nnet ads search <expression> <attributes...>\n"
2186 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2187 "The expression is a standard LDAP search expression, and the\n"
2188 "attributes are a list of LDAP fields to show in the results.\n\n"
2189 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2191 net_common_flags_usage(c, argc, argv);
2192 return -1;
2197 general ADS search function. Useful in diagnosing problems in ADS
2199 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2201 ADS_STRUCT *ads;
2202 ADS_STATUS rc;
2203 const char *ldap_exp;
2204 const char **attrs;
2205 LDAPMessage *res = NULL;
2207 if (argc < 1 || c->display_usage) {
2208 return net_ads_search_usage(c, argc, argv);
2211 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2212 return -1;
2215 ldap_exp = argv[0];
2216 attrs = (argv + 1);
2218 rc = ads_do_search_retry(ads, ads->config.bind_path,
2219 LDAP_SCOPE_SUBTREE,
2220 ldap_exp, attrs, &res);
2221 if (!ADS_ERR_OK(rc)) {
2222 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2223 ads_destroy(&ads);
2224 return -1;
2227 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2229 /* dump the results */
2230 ads_dump(ads, res);
2232 ads_msgfree(ads, res);
2233 ads_destroy(&ads);
2235 return 0;
2240 help for net ads search
2242 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2244 d_printf(_(
2245 "\nnet ads dn <dn> <attributes...>\n"
2246 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2247 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2248 "to show in the results\n\n"
2249 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2250 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2252 net_common_flags_usage(c, argc, argv);
2253 return -1;
2258 general ADS search function. Useful in diagnosing problems in ADS
2260 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2262 ADS_STRUCT *ads;
2263 ADS_STATUS rc;
2264 const char *dn;
2265 const char **attrs;
2266 LDAPMessage *res = NULL;
2268 if (argc < 1 || c->display_usage) {
2269 return net_ads_dn_usage(c, argc, argv);
2272 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2273 return -1;
2276 dn = argv[0];
2277 attrs = (argv + 1);
2279 rc = ads_do_search_all(ads, dn,
2280 LDAP_SCOPE_BASE,
2281 "(objectclass=*)", attrs, &res);
2282 if (!ADS_ERR_OK(rc)) {
2283 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2284 ads_destroy(&ads);
2285 return -1;
2288 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2290 /* dump the results */
2291 ads_dump(ads, res);
2293 ads_msgfree(ads, res);
2294 ads_destroy(&ads);
2296 return 0;
2300 help for net ads sid search
2302 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2304 d_printf(_(
2305 "\nnet ads sid <sid> <attributes...>\n"
2306 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2307 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2308 "to show in the results\n\n"
2309 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2311 net_common_flags_usage(c, argc, argv);
2312 return -1;
2317 general ADS search function. Useful in diagnosing problems in ADS
2319 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2321 ADS_STRUCT *ads;
2322 ADS_STATUS rc;
2323 const char *sid_string;
2324 const char **attrs;
2325 LDAPMessage *res = NULL;
2326 struct dom_sid sid;
2328 if (argc < 1 || c->display_usage) {
2329 return net_ads_sid_usage(c, argc, argv);
2332 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2333 return -1;
2336 sid_string = argv[0];
2337 attrs = (argv + 1);
2339 if (!string_to_sid(&sid, sid_string)) {
2340 d_fprintf(stderr, _("could not convert sid\n"));
2341 ads_destroy(&ads);
2342 return -1;
2345 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2346 if (!ADS_ERR_OK(rc)) {
2347 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2348 ads_destroy(&ads);
2349 return -1;
2352 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2354 /* dump the results */
2355 ads_dump(ads, res);
2357 ads_msgfree(ads, res);
2358 ads_destroy(&ads);
2360 return 0;
2363 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2365 int ret;
2366 ADS_STRUCT *ads;
2368 if (c->display_usage) {
2369 d_printf( "%s\n"
2370 "net ads keytab flush\n"
2371 " %s\n",
2372 _("Usage:"),
2373 _("Delete the whole keytab"));
2374 return 0;
2377 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2378 return -1;
2380 ret = ads_keytab_flush(ads);
2381 ads_destroy(&ads);
2382 return ret;
2385 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2387 int i;
2388 int ret = 0;
2389 ADS_STRUCT *ads;
2391 if (c->display_usage) {
2392 d_printf("%s\n%s",
2393 _("Usage:"),
2394 _("net ads keytab add <principal> [principal ...]\n"
2395 " Add principals to local keytab\n"
2396 " principal\tKerberos principal to add to "
2397 "keytab\n"));
2398 return 0;
2401 d_printf(_("Processing principals to add...\n"));
2402 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2403 return -1;
2405 for (i = 0; i < argc; i++) {
2406 ret |= ads_keytab_add_entry(ads, argv[i]);
2408 ads_destroy(&ads);
2409 return ret;
2412 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2414 ADS_STRUCT *ads;
2415 int ret;
2417 if (c->display_usage) {
2418 d_printf( "%s\n"
2419 "net ads keytab create\n"
2420 " %s\n",
2421 _("Usage:"),
2422 _("Create new default keytab"));
2423 return 0;
2426 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2427 return -1;
2429 ret = ads_keytab_create_default(ads);
2430 ads_destroy(&ads);
2431 return ret;
2434 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2436 const char *keytab = NULL;
2438 if (c->display_usage) {
2439 d_printf("%s\n%s",
2440 _("Usage:"),
2441 _("net ads keytab list [keytab]\n"
2442 " List a local keytab\n"
2443 " keytab\tKeytab to list\n"));
2444 return 0;
2447 if (argc >= 1) {
2448 keytab = argv[0];
2451 return ads_keytab_list(keytab);
2455 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2457 struct functable func[] = {
2459 "add",
2460 net_ads_keytab_add,
2461 NET_TRANSPORT_ADS,
2462 N_("Add a service principal"),
2463 N_("net ads keytab add\n"
2464 " Add a service principal")
2467 "create",
2468 net_ads_keytab_create,
2469 NET_TRANSPORT_ADS,
2470 N_("Create a fresh keytab"),
2471 N_("net ads keytab create\n"
2472 " Create a fresh keytab")
2475 "flush",
2476 net_ads_keytab_flush,
2477 NET_TRANSPORT_ADS,
2478 N_("Remove all keytab entries"),
2479 N_("net ads keytab flush\n"
2480 " Remove all keytab entries")
2483 "list",
2484 net_ads_keytab_list,
2485 NET_TRANSPORT_ADS,
2486 N_("List a keytab"),
2487 N_("net ads keytab list\n"
2488 " List a keytab")
2490 {NULL, NULL, 0, NULL, NULL}
2493 if (!USE_KERBEROS_KEYTAB) {
2494 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2495 "keytab method to use keytab functions.\n"));
2498 return net_run_function(c, argc, argv, "net ads keytab", func);
2501 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2503 int ret = -1;
2505 if (c->display_usage) {
2506 d_printf( "%s\n"
2507 "net ads kerberos renew\n"
2508 " %s\n",
2509 _("Usage:"),
2510 _("Renew TGT from existing credential cache"));
2511 return 0;
2514 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2515 if (ret) {
2516 d_printf(_("failed to renew kerberos ticket: %s\n"),
2517 error_message(ret));
2519 return ret;
2522 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2524 struct PAC_LOGON_INFO *info = NULL;
2525 TALLOC_CTX *mem_ctx = NULL;
2526 NTSTATUS status;
2527 int ret = -1;
2528 const char *impersonate_princ_s = NULL;
2530 if (c->display_usage) {
2531 d_printf( "%s\n"
2532 "net ads kerberos pac\n"
2533 " %s\n",
2534 _("Usage:"),
2535 _("Dump the Kerberos PAC"));
2536 return 0;
2539 mem_ctx = talloc_init("net_ads_kerberos_pac");
2540 if (!mem_ctx) {
2541 goto out;
2544 if (argc > 0) {
2545 impersonate_princ_s = argv[0];
2548 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2550 status = kerberos_return_pac(mem_ctx,
2551 c->opt_user_name,
2552 c->opt_password,
2554 NULL,
2555 NULL,
2556 NULL,
2557 true,
2558 true,
2559 2592000, /* one month */
2560 impersonate_princ_s,
2561 &info);
2562 if (!NT_STATUS_IS_OK(status)) {
2563 d_printf(_("failed to query kerberos PAC: %s\n"),
2564 nt_errstr(status));
2565 goto out;
2568 if (info) {
2569 const char *s;
2570 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2571 d_printf(_("The Pac: %s\n"), s);
2574 ret = 0;
2575 out:
2576 TALLOC_FREE(mem_ctx);
2577 return ret;
2580 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2582 TALLOC_CTX *mem_ctx = NULL;
2583 int ret = -1;
2584 NTSTATUS status;
2586 if (c->display_usage) {
2587 d_printf( "%s\n"
2588 "net ads kerberos kinit\n"
2589 " %s\n",
2590 _("Usage:"),
2591 _("Get Ticket Granting Ticket (TGT) for the user"));
2592 return 0;
2595 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2596 if (!mem_ctx) {
2597 goto out;
2600 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2602 ret = kerberos_kinit_password_ext(c->opt_user_name,
2603 c->opt_password,
2605 NULL,
2606 NULL,
2607 NULL,
2608 true,
2609 true,
2610 2592000, /* one month */
2611 &status);
2612 if (ret) {
2613 d_printf(_("failed to kinit password: %s\n"),
2614 nt_errstr(status));
2616 out:
2617 return ret;
2620 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2622 struct functable func[] = {
2624 "kinit",
2625 net_ads_kerberos_kinit,
2626 NET_TRANSPORT_ADS,
2627 N_("Retrieve Ticket Granting Ticket (TGT)"),
2628 N_("net ads kerberos kinit\n"
2629 " Receive Ticket Granting Ticket (TGT)")
2632 "renew",
2633 net_ads_kerberos_renew,
2634 NET_TRANSPORT_ADS,
2635 N_("Renew Ticket Granting Ticket from credential cache"),
2636 N_("net ads kerberos renew\n"
2637 " Renew Ticket Granting Ticket (TGT) from "
2638 "credential cache")
2641 "pac",
2642 net_ads_kerberos_pac,
2643 NET_TRANSPORT_ADS,
2644 N_("Dump Kerberos PAC"),
2645 N_("net ads kerberos pac\n"
2646 " Dump Kerberos PAC")
2648 {NULL, NULL, 0, NULL, NULL}
2651 return net_run_function(c, argc, argv, "net ads kerberos", func);
2654 int net_ads(struct net_context *c, int argc, const char **argv)
2656 struct functable func[] = {
2658 "info",
2659 net_ads_info,
2660 NET_TRANSPORT_ADS,
2661 N_("Display details on remote ADS server"),
2662 N_("net ads info\n"
2663 " Display details on remote ADS server")
2666 "join",
2667 net_ads_join,
2668 NET_TRANSPORT_ADS,
2669 N_("Join the local machine to ADS realm"),
2670 N_("net ads join\n"
2671 " Join the local machine to ADS realm")
2674 "testjoin",
2675 net_ads_testjoin,
2676 NET_TRANSPORT_ADS,
2677 N_("Validate machine account"),
2678 N_("net ads testjoin\n"
2679 " Validate machine account")
2682 "leave",
2683 net_ads_leave,
2684 NET_TRANSPORT_ADS,
2685 N_("Remove the local machine from ADS"),
2686 N_("net ads leave\n"
2687 " Remove the local machine from ADS")
2690 "status",
2691 net_ads_status,
2692 NET_TRANSPORT_ADS,
2693 N_("Display machine account details"),
2694 N_("net ads status\n"
2695 " Display machine account details")
2698 "user",
2699 net_ads_user,
2700 NET_TRANSPORT_ADS,
2701 N_("List/modify users"),
2702 N_("net ads user\n"
2703 " List/modify users")
2706 "group",
2707 net_ads_group,
2708 NET_TRANSPORT_ADS,
2709 N_("List/modify groups"),
2710 N_("net ads group\n"
2711 " List/modify groups")
2714 "dns",
2715 net_ads_dns,
2716 NET_TRANSPORT_ADS,
2717 N_("Issue dynamic DNS update"),
2718 N_("net ads dns\n"
2719 " Issue dynamic DNS update")
2722 "password",
2723 net_ads_password,
2724 NET_TRANSPORT_ADS,
2725 N_("Change user passwords"),
2726 N_("net ads password\n"
2727 " Change user passwords")
2730 "changetrustpw",
2731 net_ads_changetrustpw,
2732 NET_TRANSPORT_ADS,
2733 N_("Change trust account password"),
2734 N_("net ads changetrustpw\n"
2735 " Change trust account password")
2738 "printer",
2739 net_ads_printer,
2740 NET_TRANSPORT_ADS,
2741 N_("List/modify printer entries"),
2742 N_("net ads printer\n"
2743 " List/modify printer entries")
2746 "search",
2747 net_ads_search,
2748 NET_TRANSPORT_ADS,
2749 N_("Issue LDAP search using filter"),
2750 N_("net ads search\n"
2751 " Issue LDAP search using filter")
2754 "dn",
2755 net_ads_dn,
2756 NET_TRANSPORT_ADS,
2757 N_("Issue LDAP search by DN"),
2758 N_("net ads dn\n"
2759 " Issue LDAP search by DN")
2762 "sid",
2763 net_ads_sid,
2764 NET_TRANSPORT_ADS,
2765 N_("Issue LDAP search by SID"),
2766 N_("net ads sid\n"
2767 " Issue LDAP search by SID")
2770 "workgroup",
2771 net_ads_workgroup,
2772 NET_TRANSPORT_ADS,
2773 N_("Display workgroup name"),
2774 N_("net ads workgroup\n"
2775 " Display the workgroup name")
2778 "lookup",
2779 net_ads_lookup,
2780 NET_TRANSPORT_ADS,
2781 N_("Perfom CLDAP query on DC"),
2782 N_("net ads lookup\n"
2783 " Find the ADS DC using CLDAP lookups")
2786 "keytab",
2787 net_ads_keytab,
2788 NET_TRANSPORT_ADS,
2789 N_("Manage local keytab file"),
2790 N_("net ads keytab\n"
2791 " Manage local keytab file")
2794 "gpo",
2795 net_ads_gpo,
2796 NET_TRANSPORT_ADS,
2797 N_("Manage group policy objects"),
2798 N_("net ads gpo\n"
2799 " Manage group policy objects")
2802 "kerberos",
2803 net_ads_kerberos,
2804 NET_TRANSPORT_ADS,
2805 N_("Manage kerberos keytab"),
2806 N_("net ads kerberos\n"
2807 " Manage kerberos keytab")
2809 {NULL, NULL, 0, NULL, NULL}
2812 return net_run_function(c, argc, argv, "net ads", func);
2815 #else
2817 static int net_ads_noads(void)
2819 d_fprintf(stderr, _("ADS support not compiled in\n"));
2820 return -1;
2823 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2825 return net_ads_noads();
2828 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2830 return net_ads_noads();
2833 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2835 return net_ads_noads();
2838 int net_ads_join(struct net_context *c, int argc, const char **argv)
2840 return net_ads_noads();
2843 int net_ads_user(struct net_context *c, int argc, const char **argv)
2845 return net_ads_noads();
2848 int net_ads_group(struct net_context *c, int argc, const char **argv)
2850 return net_ads_noads();
2853 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
2855 return net_ads_noads();
2858 /* this one shouldn't display a message */
2859 int net_ads_check(struct net_context *c)
2861 return -1;
2864 int net_ads_check_our_domain(struct net_context *c)
2866 return -1;
2869 int net_ads(struct net_context *c, int argc, const char **argv)
2871 return net_ads_noads();
2874 #endif /* WITH_ADS */