librpc/ndr: remove 'async' from ndr_interface_call
[Samba/gebeck_regimport.git] / source3 / utils / net_ads.c
bloba07e6c56eaaaa2bf237145ed708a8e5427a2a504
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 "librpc/gen_ndr/ndr_krb5pac.h"
26 #include "../librpc/gen_ndr/cli_spoolss.h"
27 #include "nsswitch/libwbclient/wbclient.h"
28 #include "ads.h"
29 #include "libads/cldap.h"
30 #include "libads/dns.h"
31 #include "../libds/common/flags.h"
32 #include "librpc/gen_ndr/libnet_join.h"
33 #include "libnet/libnet_join.h"
34 #include "smb_krb5.h"
35 #include "secrets.h"
36 #include "krb5_env.h"
38 #ifdef HAVE_ADS
40 /* when we do not have sufficient input parameters to contact a remote domain
41 * we always fall back to our own realm - Guenther*/
43 static const char *assume_own_realm(struct net_context *c)
45 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
46 return lp_realm();
49 return NULL;
53 do a cldap netlogon query
55 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
57 char addr[INET6_ADDRSTRLEN];
58 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
60 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
61 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
62 d_fprintf(stderr, _("CLDAP query failed!\n"));
63 return -1;
66 d_printf(_("Information for Domain Controller: %s\n\n"),
67 addr);
69 d_printf(_("Response Type: "));
70 switch (reply.command) {
71 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
72 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
73 break;
74 case LOGON_SAM_LOGON_RESPONSE_EX:
75 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
76 break;
77 default:
78 d_printf("0x%x\n", reply.command);
79 break;
82 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
84 d_printf(_("Flags:\n"
85 "\tIs a PDC: %s\n"
86 "\tIs a GC of the forest: %s\n"
87 "\tIs an LDAP server: %s\n"
88 "\tSupports DS: %s\n"
89 "\tIs running a KDC: %s\n"
90 "\tIs running time services: %s\n"
91 "\tIs the closest DC: %s\n"
92 "\tIs writable: %s\n"
93 "\tHas a hardware clock: %s\n"
94 "\tIs a non-domain NC serviced by LDAP server: %s\n"
95 "\tIs NT6 DC that has some secrets: %s\n"
96 "\tIs NT6 DC that has all secrets: %s\n"),
97 (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
98 (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
99 (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
100 (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
101 (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
102 (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
103 (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
104 (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
105 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
106 (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
107 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
108 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"));
111 printf(_("Forest:\t\t\t%s\n"), reply.forest);
112 printf(_("Domain:\t\t\t%s\n"), reply.dns_domain);
113 printf(_("Domain Controller:\t%s\n"), reply.pdc_dns_name);
115 printf(_("Pre-Win2k Domain:\t%s\n"), reply.domain_name);
116 printf(_("Pre-Win2k Hostname:\t%s\n"), reply.pdc_name);
118 if (*reply.user_name) printf(_("User name:\t%s\n"), reply.user_name);
120 printf(_("Server Site Name :\t\t%s\n"), reply.server_site);
121 printf(_("Client Site Name :\t\t%s\n"), reply.client_site);
123 d_printf(_("NT Version: %d\n"), reply.nt_version);
124 d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
125 d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
127 return 0;
131 this implements the CLDAP based netlogon lookup requests
132 for finding the domain controller of a ADS domain
134 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
136 ADS_STRUCT *ads;
137 int ret;
139 if (c->display_usage) {
140 d_printf("%s\n"
141 "net ads lookup\n"
142 " %s",
143 _("Usage:"),
144 _("Find the ADS DC using CLDAP lookup.\n"));
145 return 0;
148 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
149 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
150 ads_destroy(&ads);
151 return -1;
154 if (!ads->config.realm) {
155 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
156 ads->ldap.port = 389;
159 ret = net_ads_cldap_netlogon(c, ads);
160 ads_destroy(&ads);
161 return ret;
166 static int net_ads_info(struct net_context *c, int argc, const char **argv)
168 ADS_STRUCT *ads;
169 char addr[INET6_ADDRSTRLEN];
171 if (c->display_usage) {
172 d_printf("%s\n"
173 "net ads info\n"
174 " %s",
175 _("Usage:"),
176 _("Display information about an Active Directory "
177 "server.\n"));
178 return 0;
181 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
182 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
183 return -1;
186 if (!ads || !ads->config.realm) {
187 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
188 ads_destroy(&ads);
189 return -1;
192 /* Try to set the server's current time since we didn't do a full
193 TCP LDAP session initially */
195 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
196 d_fprintf( stderr, _("Failed to get server's current time!\n"));
199 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
201 d_printf(_("LDAP server: %s\n"), addr);
202 d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
203 d_printf(_("Realm: %s\n"), ads->config.realm);
204 d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
205 d_printf(_("LDAP port: %d\n"), ads->ldap.port);
206 d_printf(_("Server time: %s\n"),
207 http_timestring(talloc_tos(), ads->config.current_time));
209 d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
210 d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
212 ads_destroy(&ads);
213 return 0;
216 static void use_in_memory_ccache(void) {
217 /* Use in-memory credentials cache so we do not interfere with
218 * existing credentials */
219 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
222 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
223 uint32 auth_flags, ADS_STRUCT **ads_ret)
225 ADS_STRUCT *ads = NULL;
226 ADS_STATUS status;
227 bool need_password = false;
228 bool second_time = false;
229 char *cp;
230 const char *realm = NULL;
231 bool tried_closest_dc = false;
233 /* lp_realm() should be handled by a command line param,
234 However, the join requires that realm be set in smb.conf
235 and compares our realm with the remote server's so this is
236 ok until someone needs more flexibility */
238 *ads_ret = NULL;
240 retry_connect:
241 if (only_own_domain) {
242 realm = lp_realm();
243 } else {
244 realm = assume_own_realm(c);
247 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
249 if (!c->opt_user_name) {
250 c->opt_user_name = "administrator";
253 if (c->opt_user_specified) {
254 need_password = true;
257 retry:
258 if (!c->opt_password && need_password && !c->opt_machine_pass) {
259 c->opt_password = net_prompt_pass(c, c->opt_user_name);
260 if (!c->opt_password) {
261 ads_destroy(&ads);
262 return ADS_ERROR(LDAP_NO_MEMORY);
266 if (c->opt_password) {
267 use_in_memory_ccache();
268 SAFE_FREE(ads->auth.password);
269 ads->auth.password = smb_xstrdup(c->opt_password);
272 ads->auth.flags |= auth_flags;
273 SAFE_FREE(ads->auth.user_name);
274 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
277 * If the username is of the form "name@realm",
278 * extract the realm and convert to upper case.
279 * This is only used to establish the connection.
281 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
282 *cp++ = '\0';
283 SAFE_FREE(ads->auth.realm);
284 ads->auth.realm = smb_xstrdup(cp);
285 strupper_m(ads->auth.realm);
288 status = ads_connect(ads);
290 if (!ADS_ERR_OK(status)) {
292 if (NT_STATUS_EQUAL(ads_ntstatus(status),
293 NT_STATUS_NO_LOGON_SERVERS)) {
294 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
295 ads_destroy(&ads);
296 return status;
299 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
300 need_password = true;
301 second_time = true;
302 goto retry;
303 } else {
304 ads_destroy(&ads);
305 return status;
309 /* when contacting our own domain, make sure we use the closest DC.
310 * This is done by reconnecting to ADS because only the first call to
311 * ads_connect will give us our own sitename */
313 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
315 tried_closest_dc = true; /* avoid loop */
317 if (!ads_closest_dc(ads)) {
319 namecache_delete(ads->server.realm, 0x1C);
320 namecache_delete(ads->server.workgroup, 0x1C);
322 ads_destroy(&ads);
323 ads = NULL;
325 goto retry_connect;
329 *ads_ret = ads;
330 return status;
333 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
335 return ads_startup_int(c, only_own_domain, 0, ads);
338 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
340 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
344 Check to see if connection can be made via ads.
345 ads_startup() stores the password in opt_password if it needs to so
346 that rpc or rap can use it without re-prompting.
348 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
350 ADS_STRUCT *ads;
351 ADS_STATUS status;
353 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
354 return -1;
357 ads->auth.flags |= ADS_AUTH_NO_BIND;
359 status = ads_connect(ads);
360 if ( !ADS_ERR_OK(status) ) {
361 return -1;
364 ads_destroy(&ads);
365 return 0;
368 int net_ads_check_our_domain(struct net_context *c)
370 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
373 int net_ads_check(struct net_context *c)
375 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
379 determine the netbios workgroup name for a domain
381 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
383 ADS_STRUCT *ads;
384 char addr[INET6_ADDRSTRLEN];
385 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
387 if (c->display_usage) {
388 d_printf ("%s\n"
389 "net ads workgroup\n"
390 " %s\n",
391 _("Usage:"),
392 _("Print the workgroup name"));
393 return 0;
396 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
397 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
398 return -1;
401 if (!ads->config.realm) {
402 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
403 ads->ldap.port = 389;
406 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
407 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
408 d_fprintf(stderr, _("CLDAP query failed!\n"));
409 ads_destroy(&ads);
410 return -1;
413 d_printf(_("Workgroup: %s\n"), reply.domain_name);
415 ads_destroy(&ads);
417 return 0;
422 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
424 char **disp_fields = (char **) data_area;
426 if (!field) { /* must be end of record */
427 if (disp_fields[0]) {
428 if (!strchr_m(disp_fields[0], '$')) {
429 if (disp_fields[1])
430 d_printf("%-21.21s %s\n",
431 disp_fields[0], disp_fields[1]);
432 else
433 d_printf("%s\n", disp_fields[0]);
436 SAFE_FREE(disp_fields[0]);
437 SAFE_FREE(disp_fields[1]);
438 return true;
440 if (!values) /* must be new field, indicate string field */
441 return true;
442 if (StrCaseCmp(field, "sAMAccountName") == 0) {
443 disp_fields[0] = SMB_STRDUP((char *) values[0]);
445 if (StrCaseCmp(field, "description") == 0)
446 disp_fields[1] = SMB_STRDUP((char *) values[0]);
447 return true;
450 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
452 return net_user_usage(c, argc, argv);
455 static int ads_user_add(struct net_context *c, int argc, const char **argv)
457 ADS_STRUCT *ads;
458 ADS_STATUS status;
459 char *upn, *userdn;
460 LDAPMessage *res=NULL;
461 int rc = -1;
462 char *ou_str = NULL;
464 if (argc < 1 || c->display_usage)
465 return net_ads_user_usage(c, argc, argv);
467 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
468 return -1;
471 status = ads_find_user_acct(ads, &res, argv[0]);
473 if (!ADS_ERR_OK(status)) {
474 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
475 goto done;
478 if (ads_count_replies(ads, res)) {
479 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
480 argv[0]);
481 goto done;
484 if (c->opt_container) {
485 ou_str = SMB_STRDUP(c->opt_container);
486 } else {
487 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
490 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
492 if (!ADS_ERR_OK(status)) {
493 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
494 ads_errstr(status));
495 goto done;
498 /* if no password is to be set, we're done */
499 if (argc == 1) {
500 d_printf(_("User %s added\n"), argv[0]);
501 rc = 0;
502 goto done;
505 /* try setting the password */
506 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
507 goto done;
509 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
510 ads->auth.time_offset);
511 SAFE_FREE(upn);
512 if (ADS_ERR_OK(status)) {
513 d_printf(_("User %s added\n"), argv[0]);
514 rc = 0;
515 goto done;
518 /* password didn't set, delete account */
519 d_fprintf(stderr, _("Could not add user %s. "
520 "Error setting password %s\n"),
521 argv[0], ads_errstr(status));
522 ads_msgfree(ads, res);
523 status=ads_find_user_acct(ads, &res, argv[0]);
524 if (ADS_ERR_OK(status)) {
525 userdn = ads_get_dn(ads, talloc_tos(), res);
526 ads_del_dn(ads, userdn);
527 TALLOC_FREE(userdn);
530 done:
531 if (res)
532 ads_msgfree(ads, res);
533 ads_destroy(&ads);
534 SAFE_FREE(ou_str);
535 return rc;
538 static int ads_user_info(struct net_context *c, int argc, const char **argv)
540 ADS_STRUCT *ads = NULL;
541 ADS_STATUS rc;
542 LDAPMessage *res = NULL;
543 TALLOC_CTX *frame;
544 int ret = 0;
545 wbcErr wbc_status;
546 const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
547 char *searchstring=NULL;
548 char **grouplist;
549 char *primary_group;
550 char *escaped_user;
551 struct dom_sid primary_group_sid;
552 uint32_t group_rid;
553 enum wbcSidType type;
555 if (argc < 1 || c->display_usage) {
556 return net_ads_user_usage(c, argc, argv);
559 frame = talloc_new(talloc_tos());
560 if (frame == NULL) {
561 return -1;
564 escaped_user = escape_ldap_string(frame, argv[0]);
565 if (!escaped_user) {
566 d_fprintf(stderr,
567 _("ads_user_info: failed to escape user %s\n"),
568 argv[0]);
569 return -1;
572 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
573 ret = -1;
574 goto error;
577 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
578 ret =-1;
579 goto error;
581 rc = ads_search(ads, &res, searchstring, attrs);
582 SAFE_FREE(searchstring);
584 if (!ADS_ERR_OK(rc)) {
585 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(rc));
586 ret = -1;
587 goto error;
590 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
591 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
592 ret = -1;
593 goto error;
596 rc = ads_domain_sid(ads, &primary_group_sid);
597 if (!ADS_ERR_OK(rc)) {
598 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(rc));
599 ret = -1;
600 goto error;
603 sid_append_rid(&primary_group_sid, group_rid);
605 wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
606 NULL, /* don't look up domain */
607 &primary_group,
608 &type);
609 if (!WBC_ERROR_IS_OK(wbc_status)) {
610 d_fprintf(stderr, "wbcLookupSid: %s\n",
611 wbcErrorString(wbc_status));
612 ret = -1;
613 goto error;
616 d_printf("%s\n", primary_group);
618 wbcFreeMemory(primary_group);
620 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
621 (LDAPMessage *)res, "memberOf");
623 if (grouplist) {
624 int i;
625 char **groupname;
626 for (i=0;grouplist[i];i++) {
627 groupname = ldap_explode_dn(grouplist[i], 1);
628 d_printf("%s\n", groupname[0]);
629 ldap_value_free(groupname);
631 ldap_value_free(grouplist);
634 error:
635 if (res) ads_msgfree(ads, res);
636 if (ads) ads_destroy(&ads);
637 TALLOC_FREE(frame);
638 return ret;
641 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
643 ADS_STRUCT *ads;
644 ADS_STATUS rc;
645 LDAPMessage *res = NULL;
646 char *userdn;
648 if (argc < 1) {
649 return net_ads_user_usage(c, argc, argv);
652 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
653 return -1;
656 rc = ads_find_user_acct(ads, &res, argv[0]);
657 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
658 d_printf(_("User %s does not exist.\n"), argv[0]);
659 ads_msgfree(ads, res);
660 ads_destroy(&ads);
661 return -1;
663 userdn = ads_get_dn(ads, talloc_tos(), res);
664 ads_msgfree(ads, res);
665 rc = ads_del_dn(ads, userdn);
666 TALLOC_FREE(userdn);
667 if (ADS_ERR_OK(rc)) {
668 d_printf(_("User %s deleted\n"), argv[0]);
669 ads_destroy(&ads);
670 return 0;
672 d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
673 ads_errstr(rc));
674 ads_destroy(&ads);
675 return -1;
678 int net_ads_user(struct net_context *c, int argc, const char **argv)
680 struct functable func[] = {
682 "add",
683 ads_user_add,
684 NET_TRANSPORT_ADS,
685 N_("Add an AD user"),
686 N_("net ads user add\n"
687 " Add an AD user")
690 "info",
691 ads_user_info,
692 NET_TRANSPORT_ADS,
693 N_("Display information about an AD user"),
694 N_("net ads user info\n"
695 " Display information about an AD user")
698 "delete",
699 ads_user_delete,
700 NET_TRANSPORT_ADS,
701 N_("Delete an AD user"),
702 N_("net ads user delete\n"
703 " Delete an AD user")
705 {NULL, NULL, 0, NULL, NULL}
707 ADS_STRUCT *ads;
708 ADS_STATUS rc;
709 const char *shortattrs[] = {"sAMAccountName", NULL};
710 const char *longattrs[] = {"sAMAccountName", "description", NULL};
711 char *disp_fields[2] = {NULL, NULL};
713 if (argc == 0) {
714 if (c->display_usage) {
715 d_printf( "%s\n"
716 "net ads user\n"
717 " %s\n",
718 _("Usage:"),
719 _("List AD users"));
720 net_display_usage_from_functable(func);
721 return 0;
724 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
725 return -1;
728 if (c->opt_long_list_entries)
729 d_printf(_("\nUser name Comment"
730 "\n-----------------------------\n"));
732 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
733 LDAP_SCOPE_SUBTREE,
734 "(objectCategory=user)",
735 c->opt_long_list_entries ? longattrs :
736 shortattrs, usergrp_display,
737 disp_fields);
738 ads_destroy(&ads);
739 return ADS_ERR_OK(rc) ? 0 : -1;
742 return net_run_function(c, argc, argv, "net ads user", func);
745 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
747 return net_group_usage(c, argc, argv);
750 static int ads_group_add(struct net_context *c, int argc, const char **argv)
752 ADS_STRUCT *ads;
753 ADS_STATUS status;
754 LDAPMessage *res=NULL;
755 int rc = -1;
756 char *ou_str = NULL;
758 if (argc < 1 || c->display_usage) {
759 return net_ads_group_usage(c, argc, argv);
762 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
763 return -1;
766 status = ads_find_user_acct(ads, &res, argv[0]);
768 if (!ADS_ERR_OK(status)) {
769 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
770 goto done;
773 if (ads_count_replies(ads, res)) {
774 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
775 goto done;
778 if (c->opt_container) {
779 ou_str = SMB_STRDUP(c->opt_container);
780 } else {
781 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
784 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
786 if (ADS_ERR_OK(status)) {
787 d_printf(_("Group %s added\n"), argv[0]);
788 rc = 0;
789 } else {
790 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
791 ads_errstr(status));
794 done:
795 if (res)
796 ads_msgfree(ads, res);
797 ads_destroy(&ads);
798 SAFE_FREE(ou_str);
799 return rc;
802 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
804 ADS_STRUCT *ads;
805 ADS_STATUS rc;
806 LDAPMessage *res = NULL;
807 char *groupdn;
809 if (argc < 1 || c->display_usage) {
810 return net_ads_group_usage(c, argc, argv);
813 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
814 return -1;
817 rc = ads_find_user_acct(ads, &res, argv[0]);
818 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
819 d_printf(_("Group %s does not exist.\n"), argv[0]);
820 ads_msgfree(ads, res);
821 ads_destroy(&ads);
822 return -1;
824 groupdn = ads_get_dn(ads, talloc_tos(), res);
825 ads_msgfree(ads, res);
826 rc = ads_del_dn(ads, groupdn);
827 TALLOC_FREE(groupdn);
828 if (ADS_ERR_OK(rc)) {
829 d_printf(_("Group %s deleted\n"), argv[0]);
830 ads_destroy(&ads);
831 return 0;
833 d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
834 ads_errstr(rc));
835 ads_destroy(&ads);
836 return -1;
839 int net_ads_group(struct net_context *c, int argc, const char **argv)
841 struct functable func[] = {
843 "add",
844 ads_group_add,
845 NET_TRANSPORT_ADS,
846 N_("Add an AD group"),
847 N_("net ads group add\n"
848 " Add an AD group")
851 "delete",
852 ads_group_delete,
853 NET_TRANSPORT_ADS,
854 N_("Delete an AD group"),
855 N_("net ads group delete\n"
856 " Delete an AD group")
858 {NULL, NULL, 0, NULL, NULL}
860 ADS_STRUCT *ads;
861 ADS_STATUS rc;
862 const char *shortattrs[] = {"sAMAccountName", NULL};
863 const char *longattrs[] = {"sAMAccountName", "description", NULL};
864 char *disp_fields[2] = {NULL, NULL};
866 if (argc == 0) {
867 if (c->display_usage) {
868 d_printf( "%s\n"
869 "net ads group\n"
870 " %s\n",
871 _("Usage:"),
872 _("List AD groups"));
873 net_display_usage_from_functable(func);
874 return 0;
877 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
878 return -1;
881 if (c->opt_long_list_entries)
882 d_printf(_("\nGroup name Comment"
883 "\n-----------------------------\n"));
884 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
885 LDAP_SCOPE_SUBTREE,
886 "(objectCategory=group)",
887 c->opt_long_list_entries ? longattrs :
888 shortattrs, usergrp_display,
889 disp_fields);
891 ads_destroy(&ads);
892 return ADS_ERR_OK(rc) ? 0 : -1;
894 return net_run_function(c, argc, argv, "net ads group", func);
897 static int net_ads_status(struct net_context *c, int argc, const char **argv)
899 ADS_STRUCT *ads;
900 ADS_STATUS rc;
901 LDAPMessage *res;
903 if (c->display_usage) {
904 d_printf( "%s\n"
905 "net ads status\n"
906 " %s\n",
907 _("Usage:"),
908 _("Display machine account details"));
909 return 0;
912 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
913 return -1;
916 rc = ads_find_machine_acct(ads, &res, global_myname());
917 if (!ADS_ERR_OK(rc)) {
918 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
919 ads_destroy(&ads);
920 return -1;
923 if (ads_count_replies(ads, res) == 0) {
924 d_fprintf(stderr, _("No machine account for '%s' found\n"), global_myname());
925 ads_destroy(&ads);
926 return -1;
929 ads_dump(ads, res);
930 ads_destroy(&ads);
931 return 0;
934 /*******************************************************************
935 Leave an AD domain. Windows XP disables the machine account.
936 We'll try the same. The old code would do an LDAP delete.
937 That only worked using the machine creds because added the machine
938 with full control to the computer object's ACL.
939 *******************************************************************/
941 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
943 TALLOC_CTX *ctx;
944 struct libnet_UnjoinCtx *r = NULL;
945 WERROR werr;
947 if (c->display_usage) {
948 d_printf( "%s\n"
949 "net ads leave\n"
950 " %s\n",
951 _("Usage:"),
952 _("Leave an AD domain"));
953 return 0;
956 if (!*lp_realm()) {
957 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
958 return -1;
961 if (!(ctx = talloc_init("net_ads_leave"))) {
962 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
963 return -1;
966 if (!c->opt_kerberos) {
967 use_in_memory_ccache();
970 werr = libnet_init_UnjoinCtx(ctx, &r);
971 if (!W_ERROR_IS_OK(werr)) {
972 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
973 return -1;
976 r->in.debug = true;
977 r->in.use_kerberos = c->opt_kerberos;
978 r->in.dc_name = c->opt_host;
979 r->in.domain_name = lp_realm();
980 r->in.admin_account = c->opt_user_name;
981 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
982 r->in.modify_config = lp_config_backend_is_registry();
984 /* Try to delete it, but if that fails, disable it. The
985 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
986 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
987 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
988 r->in.delete_machine_account = true;
989 r->in.msg_ctx = c->msg_ctx;
991 werr = libnet_Unjoin(ctx, r);
992 if (!W_ERROR_IS_OK(werr)) {
993 d_printf(_("Failed to leave domain: %s\n"),
994 r->out.error_string ? r->out.error_string :
995 get_friendly_werror_msg(werr));
996 goto done;
999 if (r->out.deleted_machine_account) {
1000 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1001 r->in.machine_name, r->out.dns_domain_name);
1002 goto done;
1005 /* We couldn't delete it - see if the disable succeeded. */
1006 if (r->out.disabled_machine_account) {
1007 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1008 r->in.machine_name, r->out.dns_domain_name);
1009 werr = WERR_OK;
1010 goto done;
1013 /* Based on what we requseted, we shouldn't get here, but if
1014 we did, it means the secrets were removed, and therefore
1015 we have left the domain */
1016 d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1017 r->in.machine_name, r->out.dns_domain_name);
1019 done:
1020 TALLOC_FREE(r);
1021 TALLOC_FREE(ctx);
1023 if (W_ERROR_IS_OK(werr)) {
1024 return 0;
1027 return -1;
1030 static NTSTATUS net_ads_join_ok(struct net_context *c)
1032 ADS_STRUCT *ads = NULL;
1033 ADS_STATUS status;
1034 fstring dc_name;
1035 struct sockaddr_storage dcip;
1037 if (!secrets_init()) {
1038 DEBUG(1,("Failed to initialise secrets database\n"));
1039 return NT_STATUS_ACCESS_DENIED;
1042 net_use_krb_machine_account(c);
1044 get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1046 status = ads_startup(c, true, &ads);
1047 if (!ADS_ERR_OK(status)) {
1048 return ads_ntstatus(status);
1051 ads_destroy(&ads);
1052 return NT_STATUS_OK;
1056 check that an existing join is OK
1058 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1060 NTSTATUS status;
1061 use_in_memory_ccache();
1063 if (c->display_usage) {
1064 d_printf( "%s\n"
1065 "net ads testjoin\n"
1066 " %s\n",
1067 _("Usage:"),
1068 _("Test if the existing join is ok"));
1069 return 0;
1072 /* Display success or failure */
1073 status = net_ads_join_ok(c);
1074 if (!NT_STATUS_IS_OK(status)) {
1075 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1076 get_friendly_nt_error_msg(status));
1077 return -1;
1080 printf(_("Join is OK\n"));
1081 return 0;
1084 /*******************************************************************
1085 Simple configu checks before beginning the join
1086 ********************************************************************/
1088 static WERROR check_ads_config( void )
1090 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1091 d_printf(_("Host is not configured as a member server.\n"));
1092 return WERR_INVALID_DOMAIN_ROLE;
1095 if (strlen(global_myname()) > 15) {
1096 d_printf(_("Our netbios name can be at most 15 chars long, "
1097 "\"%s\" is %u chars long\n"), global_myname(),
1098 (unsigned int)strlen(global_myname()));
1099 return WERR_INVALID_COMPUTERNAME;
1102 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1103 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1104 "join to succeed.\n"), get_dyn_CONFIGFILE());
1105 return WERR_INVALID_PARAM;
1108 return WERR_OK;
1111 /*******************************************************************
1112 Send a DNS update request
1113 *******************************************************************/
1115 #if defined(WITH_DNS_UPDATES)
1116 #include "dns.h"
1117 DNS_ERROR DoDNSUpdate(char *pszServerName,
1118 const char *pszDomainName, const char *pszHostName,
1119 const struct sockaddr_storage *sslist,
1120 size_t num_addrs );
1122 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1123 const char *machine_name,
1124 const struct sockaddr_storage *addrs,
1125 int num_addrs)
1127 struct dns_rr_ns *nameservers = NULL;
1128 int ns_count = 0;
1129 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1130 DNS_ERROR dns_err;
1131 fstring dns_server;
1132 const char *dnsdomain = NULL;
1133 char *root_domain = NULL;
1135 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1136 d_printf(_("No DNS domain configured for %s. "
1137 "Unable to perform DNS Update.\n"), machine_name);
1138 status = NT_STATUS_INVALID_PARAMETER;
1139 goto done;
1141 dnsdomain++;
1143 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1144 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1145 /* Child domains often do not have NS records. Look
1146 for the NS record for the forest root domain
1147 (rootDomainNamingContext in therootDSE) */
1149 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1150 LDAPMessage *msg = NULL;
1151 char *root_dn;
1152 ADS_STATUS ads_status;
1154 if ( !ads->ldap.ld ) {
1155 ads_status = ads_connect( ads );
1156 if ( !ADS_ERR_OK(ads_status) ) {
1157 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1158 goto done;
1162 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1163 "(objectclass=*)", rootname_attrs, &msg);
1164 if (!ADS_ERR_OK(ads_status)) {
1165 goto done;
1168 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1169 if ( !root_dn ) {
1170 ads_msgfree( ads, msg );
1171 goto done;
1174 root_domain = ads_build_domain( root_dn );
1176 /* cleanup */
1177 ads_msgfree( ads, msg );
1179 /* try again for NS servers */
1181 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1183 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1184 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1185 "realm\n", ads->config.realm));
1186 goto done;
1189 dnsdomain = root_domain;
1193 /* Now perform the dns update - we'll try non-secure and if we fail,
1194 we'll follow it up with a secure update */
1196 fstrcpy( dns_server, nameservers[0].hostname );
1198 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1199 if (!ERR_DNS_IS_OK(dns_err)) {
1200 status = NT_STATUS_UNSUCCESSFUL;
1203 done:
1205 SAFE_FREE( root_domain );
1207 return status;
1210 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1212 int num_addrs;
1213 struct sockaddr_storage *iplist = NULL;
1214 fstring machine_name;
1215 NTSTATUS status;
1217 name_to_fqdn( machine_name, global_myname() );
1218 strlower_m( machine_name );
1220 /* Get our ip address (not the 127.0.0.x address but a real ip
1221 * address) */
1223 num_addrs = get_my_ip_address( &iplist );
1224 if ( num_addrs <= 0 ) {
1225 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1226 "addresses!\n"));
1227 return NT_STATUS_INVALID_PARAMETER;
1230 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1231 iplist, num_addrs);
1232 SAFE_FREE( iplist );
1233 return status;
1235 #endif
1238 /*******************************************************************
1239 ********************************************************************/
1241 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1243 d_printf(_("net ads join [options]\n"
1244 "Valid options:\n"));
1245 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1246 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1247 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1248 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1249 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1250 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1251 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1252 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1253 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1254 " NB: osName and osVer must be specified together for either to take effect.\n"
1255 " Also, the operatingSystemService attribute is also set when along with\n"
1256 " the two other attributes.\n"));
1258 return -1;
1261 /*******************************************************************
1262 ********************************************************************/
1264 int net_ads_join(struct net_context *c, int argc, const char **argv)
1266 TALLOC_CTX *ctx = NULL;
1267 struct libnet_JoinCtx *r = NULL;
1268 const char *domain = lp_realm();
1269 WERROR werr = WERR_SETUP_NOT_JOINED;
1270 bool createupn = false;
1271 const char *machineupn = NULL;
1272 const char *create_in_ou = NULL;
1273 int i;
1274 const char *os_name = NULL;
1275 const char *os_version = NULL;
1276 bool modify_config = lp_config_backend_is_registry();
1278 if (c->display_usage)
1279 return net_ads_join_usage(c, argc, argv);
1281 if (!modify_config) {
1283 werr = check_ads_config();
1284 if (!W_ERROR_IS_OK(werr)) {
1285 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1286 goto fail;
1290 if (!(ctx = talloc_init("net_ads_join"))) {
1291 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1292 werr = WERR_NOMEM;
1293 goto fail;
1296 if (!c->opt_kerberos) {
1297 use_in_memory_ccache();
1300 werr = libnet_init_JoinCtx(ctx, &r);
1301 if (!W_ERROR_IS_OK(werr)) {
1302 goto fail;
1305 /* process additional command line args */
1307 for ( i=0; i<argc; i++ ) {
1308 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1309 createupn = true;
1310 machineupn = get_string_param(argv[i]);
1312 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1313 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1314 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1315 werr = WERR_INVALID_PARAM;
1316 goto fail;
1319 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1320 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1321 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1322 werr = WERR_INVALID_PARAM;
1323 goto fail;
1326 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1327 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1328 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1329 werr = WERR_INVALID_PARAM;
1330 goto fail;
1333 else {
1334 domain = argv[i];
1338 if (!*domain) {
1339 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1340 werr = WERR_INVALID_PARAM;
1341 goto fail;
1344 /* Do the domain join here */
1346 r->in.domain_name = domain;
1347 r->in.create_upn = createupn;
1348 r->in.upn = machineupn;
1349 r->in.account_ou = create_in_ou;
1350 r->in.os_name = os_name;
1351 r->in.os_version = os_version;
1352 r->in.dc_name = c->opt_host;
1353 r->in.admin_account = c->opt_user_name;
1354 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1355 r->in.debug = true;
1356 r->in.use_kerberos = c->opt_kerberos;
1357 r->in.modify_config = modify_config;
1358 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1359 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1360 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1361 r->in.msg_ctx = c->msg_ctx;
1363 werr = libnet_Join(ctx, r);
1364 if (!W_ERROR_IS_OK(werr)) {
1365 goto fail;
1368 /* Check the short name of the domain */
1370 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1371 d_printf(_("The workgroup in %s does not match the short\n"
1372 "domain name obtained from the server.\n"
1373 "Using the name [%s] from the server.\n"
1374 "You should set \"workgroup = %s\" in %s.\n"),
1375 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1376 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1379 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1381 if (r->out.dns_domain_name) {
1382 d_printf(_("Joined '%s' to realm '%s'\n"), r->in.machine_name,
1383 r->out.dns_domain_name);
1384 } else {
1385 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1386 r->out.netbios_domain_name);
1389 #if defined(WITH_DNS_UPDATES)
1390 if (r->out.domain_is_ad) {
1391 /* We enter this block with user creds */
1392 ADS_STRUCT *ads_dns = NULL;
1394 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1395 /* kinit with the machine password */
1397 use_in_memory_ccache();
1398 if (asprintf( &ads_dns->auth.user_name, "%s$", global_myname()) == -1) {
1399 goto fail;
1401 ads_dns->auth.password = secrets_fetch_machine_password(
1402 r->out.netbios_domain_name, NULL, NULL );
1403 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1404 strupper_m(ads_dns->auth.realm );
1405 ads_kinit_password( ads_dns );
1408 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1409 d_fprintf( stderr, _("DNS update failed!\n") );
1412 /* exit from this block using machine creds */
1413 ads_destroy(&ads_dns);
1415 #endif
1416 TALLOC_FREE(r);
1417 TALLOC_FREE( ctx );
1419 return 0;
1421 fail:
1422 /* issue an overall failure message at the end. */
1423 d_printf(_("Failed to join domain: %s\n"),
1424 r && r->out.error_string ? r->out.error_string :
1425 get_friendly_werror_msg(werr));
1426 TALLOC_FREE( ctx );
1428 return -1;
1431 /*******************************************************************
1432 ********************************************************************/
1434 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1436 #if defined(WITH_DNS_UPDATES)
1437 ADS_STRUCT *ads;
1438 ADS_STATUS status;
1439 TALLOC_CTX *ctx;
1441 #ifdef DEVELOPER
1442 talloc_enable_leak_report();
1443 #endif
1445 if (argc > 0 || c->display_usage) {
1446 d_printf( "%s\n"
1447 "net ads dns register\n"
1448 " %s\n",
1449 _("Usage:"),
1450 _("Register hostname with DNS\n"));
1451 return -1;
1454 if (!(ctx = talloc_init("net_ads_dns"))) {
1455 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1456 return -1;
1459 status = ads_startup(c, true, &ads);
1460 if ( !ADS_ERR_OK(status) ) {
1461 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1462 TALLOC_FREE(ctx);
1463 return -1;
1466 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1467 d_fprintf( stderr, _("DNS update failed!\n") );
1468 ads_destroy( &ads );
1469 TALLOC_FREE( ctx );
1470 return -1;
1473 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1475 ads_destroy(&ads);
1476 TALLOC_FREE( ctx );
1478 return 0;
1479 #else
1480 d_fprintf(stderr,
1481 _("DNS update support not enabled at compile time!\n"));
1482 return -1;
1483 #endif
1486 #if defined(WITH_DNS_UPDATES)
1487 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1488 #endif
1490 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1492 #if defined(WITH_DNS_UPDATES)
1493 DNS_ERROR err;
1495 #ifdef DEVELOPER
1496 talloc_enable_leak_report();
1497 #endif
1499 if (argc != 2 || c->display_usage) {
1500 d_printf( "%s\n"
1501 " %s\n"
1502 " %s\n",
1503 _("Usage:"),
1504 _("net ads dns gethostbyname <server> <name>\n"),
1505 _(" Look up hostname from the AD\n"
1506 " server\tName server to use\n"
1507 " name\tName to look up\n"));
1508 return -1;
1511 err = do_gethostbyname(argv[0], argv[1]);
1513 d_printf(_("do_gethostbyname returned %d\n"), ERROR_DNS_V(err));
1514 #endif
1515 return 0;
1518 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1520 struct functable func[] = {
1522 "register",
1523 net_ads_dns_register,
1524 NET_TRANSPORT_ADS,
1525 N_("Add host dns entry to AD"),
1526 N_("net ads dns register\n"
1527 " Add host dns entry to AD")
1530 "gethostbyname",
1531 net_ads_dns_gethostbyname,
1532 NET_TRANSPORT_ADS,
1533 N_("Look up host"),
1534 N_("net ads dns gethostbyname\n"
1535 " Look up host")
1537 {NULL, NULL, 0, NULL, NULL}
1540 return net_run_function(c, argc, argv, "net ads dns", func);
1543 /*******************************************************************
1544 ********************************************************************/
1546 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1548 d_printf(_(
1549 "\nnet ads printer search <printer>"
1550 "\n\tsearch for a printer in the directory\n"
1551 "\nnet ads printer info <printer> <server>"
1552 "\n\tlookup info in directory for printer on server"
1553 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1554 "\nnet ads printer publish <printername>"
1555 "\n\tpublish printer in directory"
1556 "\n\t(note: printer name is required)\n"
1557 "\nnet ads printer remove <printername>"
1558 "\n\tremove printer from directory"
1559 "\n\t(note: printer name is required)\n"));
1560 return -1;
1563 /*******************************************************************
1564 ********************************************************************/
1566 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1568 ADS_STRUCT *ads;
1569 ADS_STATUS rc;
1570 LDAPMessage *res = NULL;
1572 if (c->display_usage) {
1573 d_printf( "%s\n"
1574 "net ads printer search\n"
1575 " %s\n",
1576 _("Usage:"),
1577 _("List printers in the AD"));
1578 return 0;
1581 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1582 return -1;
1585 rc = ads_find_printers(ads, &res);
1587 if (!ADS_ERR_OK(rc)) {
1588 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
1589 ads_msgfree(ads, res);
1590 ads_destroy(&ads);
1591 return -1;
1594 if (ads_count_replies(ads, res) == 0) {
1595 d_fprintf(stderr, _("No results found\n"));
1596 ads_msgfree(ads, res);
1597 ads_destroy(&ads);
1598 return -1;
1601 ads_dump(ads, res);
1602 ads_msgfree(ads, res);
1603 ads_destroy(&ads);
1604 return 0;
1607 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1609 ADS_STRUCT *ads;
1610 ADS_STATUS rc;
1611 const char *servername, *printername;
1612 LDAPMessage *res = NULL;
1614 if (c->display_usage) {
1615 d_printf("%s\n%s",
1616 _("Usage:"),
1617 _("net ads printer info [printername [servername]]\n"
1618 " Display printer info from AD\n"
1619 " printername\tPrinter name or wildcard\n"
1620 " servername\tName of the print server\n"));
1621 return 0;
1624 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1625 return -1;
1628 if (argc > 0) {
1629 printername = argv[0];
1630 } else {
1631 printername = "*";
1634 if (argc > 1) {
1635 servername = argv[1];
1636 } else {
1637 servername = global_myname();
1640 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1642 if (!ADS_ERR_OK(rc)) {
1643 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
1644 servername, ads_errstr(rc));
1645 ads_msgfree(ads, res);
1646 ads_destroy(&ads);
1647 return -1;
1650 if (ads_count_replies(ads, res) == 0) {
1651 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
1652 ads_msgfree(ads, res);
1653 ads_destroy(&ads);
1654 return -1;
1657 ads_dump(ads, res);
1658 ads_msgfree(ads, res);
1659 ads_destroy(&ads);
1661 return 0;
1664 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1666 ADS_STRUCT *ads;
1667 ADS_STATUS rc;
1668 const char *servername, *printername;
1669 struct cli_state *cli = NULL;
1670 struct rpc_pipe_client *pipe_hnd = NULL;
1671 struct sockaddr_storage server_ss;
1672 NTSTATUS nt_status;
1673 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1674 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1675 char *prt_dn, *srv_dn, **srv_cn;
1676 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1677 LDAPMessage *res = NULL;
1679 if (argc < 1 || c->display_usage) {
1680 d_printf("%s\n%s",
1681 _("Usage:"),
1682 _("net ads printer publish <printername> [servername]\n"
1683 " Publish printer in AD\n"
1684 " printername\tName of the printer\n"
1685 " servername\tName of the print server\n"));
1686 talloc_destroy(mem_ctx);
1687 return -1;
1690 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1691 talloc_destroy(mem_ctx);
1692 return -1;
1695 printername = argv[0];
1697 if (argc == 2) {
1698 servername = argv[1];
1699 } else {
1700 servername = global_myname();
1703 /* Get printer data from SPOOLSS */
1705 resolve_name(servername, &server_ss, 0x20, false);
1707 nt_status = cli_full_connection(&cli, global_myname(), servername,
1708 &server_ss, 0,
1709 "IPC$", "IPC",
1710 c->opt_user_name, c->opt_workgroup,
1711 c->opt_password ? c->opt_password : "",
1712 CLI_FULL_CONNECTION_USE_KERBEROS,
1713 Undefined, NULL);
1715 if (NT_STATUS_IS_ERR(nt_status)) {
1716 d_fprintf(stderr, _("Unable to open a connnection to %s to "
1717 "obtain data for %s\n"),
1718 servername, printername);
1719 ads_destroy(&ads);
1720 talloc_destroy(mem_ctx);
1721 return -1;
1724 /* Publish on AD server */
1726 ads_find_machine_acct(ads, &res, servername);
1728 if (ads_count_replies(ads, res) == 0) {
1729 d_fprintf(stderr, _("Could not find machine account for server "
1730 "%s\n"),
1731 servername);
1732 ads_destroy(&ads);
1733 talloc_destroy(mem_ctx);
1734 return -1;
1737 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1738 srv_cn = ldap_explode_dn(srv_dn, 1);
1740 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1741 printername_escaped = escape_rdn_val_string_alloc(printername);
1742 if (!srv_cn_escaped || !printername_escaped) {
1743 SAFE_FREE(srv_cn_escaped);
1744 SAFE_FREE(printername_escaped);
1745 d_fprintf(stderr, _("Internal error, out of memory!"));
1746 ads_destroy(&ads);
1747 talloc_destroy(mem_ctx);
1748 return -1;
1751 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1752 SAFE_FREE(srv_cn_escaped);
1753 SAFE_FREE(printername_escaped);
1754 d_fprintf(stderr, _("Internal error, out of memory!"));
1755 ads_destroy(&ads);
1756 talloc_destroy(mem_ctx);
1757 return -1;
1760 SAFE_FREE(srv_cn_escaped);
1761 SAFE_FREE(printername_escaped);
1763 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
1764 if (!NT_STATUS_IS_OK(nt_status)) {
1765 d_fprintf(stderr, _("Unable to open a connnection to the spoolss pipe on %s\n"),
1766 servername);
1767 SAFE_FREE(prt_dn);
1768 ads_destroy(&ads);
1769 talloc_destroy(mem_ctx);
1770 return -1;
1773 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1774 printername))) {
1775 SAFE_FREE(prt_dn);
1776 ads_destroy(&ads);
1777 talloc_destroy(mem_ctx);
1778 return -1;
1781 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1782 if (!ADS_ERR_OK(rc)) {
1783 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1784 SAFE_FREE(prt_dn);
1785 ads_destroy(&ads);
1786 talloc_destroy(mem_ctx);
1787 return -1;
1790 d_printf("published printer\n");
1791 SAFE_FREE(prt_dn);
1792 ads_destroy(&ads);
1793 talloc_destroy(mem_ctx);
1795 return 0;
1798 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1800 ADS_STRUCT *ads;
1801 ADS_STATUS rc;
1802 const char *servername;
1803 char *prt_dn;
1804 LDAPMessage *res = NULL;
1806 if (argc < 1 || c->display_usage) {
1807 d_printf("%s\n%s",
1808 _("Usage:"),
1809 _("net ads printer remove <printername> [servername]\n"
1810 " Remove a printer from the AD\n"
1811 " printername\tName of the printer\n"
1812 " servername\tName of the print server\n"));
1813 return -1;
1816 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1817 return -1;
1820 if (argc > 1) {
1821 servername = argv[1];
1822 } else {
1823 servername = global_myname();
1826 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1828 if (!ADS_ERR_OK(rc)) {
1829 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
1830 ads_msgfree(ads, res);
1831 ads_destroy(&ads);
1832 return -1;
1835 if (ads_count_replies(ads, res) == 0) {
1836 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
1837 ads_msgfree(ads, res);
1838 ads_destroy(&ads);
1839 return -1;
1842 prt_dn = ads_get_dn(ads, talloc_tos(), res);
1843 ads_msgfree(ads, res);
1844 rc = ads_del_dn(ads, prt_dn);
1845 TALLOC_FREE(prt_dn);
1847 if (!ADS_ERR_OK(rc)) {
1848 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
1849 ads_destroy(&ads);
1850 return -1;
1853 ads_destroy(&ads);
1854 return 0;
1857 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1859 struct functable func[] = {
1861 "search",
1862 net_ads_printer_search,
1863 NET_TRANSPORT_ADS,
1864 N_("Search for a printer"),
1865 N_("net ads printer search\n"
1866 " Search for a printer")
1869 "info",
1870 net_ads_printer_info,
1871 NET_TRANSPORT_ADS,
1872 N_("Display printer information"),
1873 N_("net ads printer info\n"
1874 " Display printer information")
1877 "publish",
1878 net_ads_printer_publish,
1879 NET_TRANSPORT_ADS,
1880 N_("Publish a printer"),
1881 N_("net ads printer publish\n"
1882 " Publish a printer")
1885 "remove",
1886 net_ads_printer_remove,
1887 NET_TRANSPORT_ADS,
1888 N_("Delete a printer"),
1889 N_("net ads printer remove\n"
1890 " Delete a printer")
1892 {NULL, NULL, 0, NULL, NULL}
1895 return net_run_function(c, argc, argv, "net ads printer", func);
1899 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1901 ADS_STRUCT *ads;
1902 const char *auth_principal = c->opt_user_name;
1903 const char *auth_password = c->opt_password;
1904 char *realm = NULL;
1905 char *new_password = NULL;
1906 char *chr, *prompt;
1907 const char *user;
1908 ADS_STATUS ret;
1910 if (c->display_usage) {
1911 d_printf("%s\n%s",
1912 _("Usage:"),
1913 _("net ads password <username>\n"
1914 " Change password for user\n"
1915 " username\tName of user to change password for\n"));
1916 return 0;
1919 if (c->opt_user_name == NULL || c->opt_password == NULL) {
1920 d_fprintf(stderr, _("You must supply an administrator "
1921 "username/password\n"));
1922 return -1;
1925 if (argc < 1) {
1926 d_fprintf(stderr, _("ERROR: You must say which username to "
1927 "change password for\n"));
1928 return -1;
1931 user = argv[0];
1932 if (!strchr_m(user, '@')) {
1933 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
1934 return -1;
1936 user = chr;
1939 use_in_memory_ccache();
1940 chr = strchr_m(auth_principal, '@');
1941 if (chr) {
1942 realm = ++chr;
1943 } else {
1944 realm = lp_realm();
1947 /* use the realm so we can eventually change passwords for users
1948 in realms other than default */
1949 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1950 return -1;
1953 /* we don't actually need a full connect, but it's the easy way to
1954 fill in the KDC's addresss */
1955 ads_connect(ads);
1957 if (!ads->config.realm) {
1958 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
1959 ads_destroy(&ads);
1960 return -1;
1963 if (argv[1]) {
1964 new_password = (char *)argv[1];
1965 } else {
1966 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
1967 return -1;
1969 new_password = getpass(prompt);
1970 free(prompt);
1973 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1974 auth_password, user, new_password, ads->auth.time_offset);
1975 if (!ADS_ERR_OK(ret)) {
1976 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
1977 ads_destroy(&ads);
1978 return -1;
1981 d_printf(_("Password change for %s completed.\n"), user);
1982 ads_destroy(&ads);
1984 return 0;
1987 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1989 ADS_STRUCT *ads;
1990 char *host_principal;
1991 fstring my_name;
1992 ADS_STATUS ret;
1994 if (c->display_usage) {
1995 d_printf( "%s\n"
1996 "net ads changetrustpw\n"
1997 " %s\n",
1998 _("Usage:"),
1999 _("Change the machine account's trust password"));
2000 return 0;
2003 if (!secrets_init()) {
2004 DEBUG(1,("Failed to initialise secrets database\n"));
2005 return -1;
2008 net_use_krb_machine_account(c);
2010 use_in_memory_ccache();
2012 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2013 return -1;
2016 fstrcpy(my_name, global_myname());
2017 strlower_m(my_name);
2018 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2019 ads_destroy(&ads);
2020 return -1;
2022 d_printf(_("Changing password for principal: %s\n"), host_principal);
2024 ret = ads_change_trust_account_password(ads, host_principal);
2026 if (!ADS_ERR_OK(ret)) {
2027 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2028 ads_destroy(&ads);
2029 SAFE_FREE(host_principal);
2030 return -1;
2033 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2035 if (USE_SYSTEM_KEYTAB) {
2036 d_printf(_("Attempting to update system keytab with new password.\n"));
2037 if (ads_keytab_create_default(ads)) {
2038 d_printf(_("Failed to update system keytab.\n"));
2042 ads_destroy(&ads);
2043 SAFE_FREE(host_principal);
2045 return 0;
2049 help for net ads search
2051 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2053 d_printf(_(
2054 "\nnet ads search <expression> <attributes...>\n"
2055 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2056 "The expression is a standard LDAP search expression, and the\n"
2057 "attributes are a list of LDAP fields to show in the results.\n\n"
2058 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2060 net_common_flags_usage(c, argc, argv);
2061 return -1;
2066 general ADS search function. Useful in diagnosing problems in ADS
2068 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2070 ADS_STRUCT *ads;
2071 ADS_STATUS rc;
2072 const char *ldap_exp;
2073 const char **attrs;
2074 LDAPMessage *res = NULL;
2076 if (argc < 1 || c->display_usage) {
2077 return net_ads_search_usage(c, argc, argv);
2080 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2081 return -1;
2084 ldap_exp = argv[0];
2085 attrs = (argv + 1);
2087 rc = ads_do_search_all(ads, ads->config.bind_path,
2088 LDAP_SCOPE_SUBTREE,
2089 ldap_exp, attrs, &res);
2090 if (!ADS_ERR_OK(rc)) {
2091 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2092 ads_destroy(&ads);
2093 return -1;
2096 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2098 /* dump the results */
2099 ads_dump(ads, res);
2101 ads_msgfree(ads, res);
2102 ads_destroy(&ads);
2104 return 0;
2109 help for net ads search
2111 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2113 d_printf(_(
2114 "\nnet ads dn <dn> <attributes...>\n"
2115 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2116 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2117 "to show in the results\n\n"
2118 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2119 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2121 net_common_flags_usage(c, argc, argv);
2122 return -1;
2127 general ADS search function. Useful in diagnosing problems in ADS
2129 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2131 ADS_STRUCT *ads;
2132 ADS_STATUS rc;
2133 const char *dn;
2134 const char **attrs;
2135 LDAPMessage *res = NULL;
2137 if (argc < 1 || c->display_usage) {
2138 return net_ads_dn_usage(c, argc, argv);
2141 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2142 return -1;
2145 dn = argv[0];
2146 attrs = (argv + 1);
2148 rc = ads_do_search_all(ads, dn,
2149 LDAP_SCOPE_BASE,
2150 "(objectclass=*)", attrs, &res);
2151 if (!ADS_ERR_OK(rc)) {
2152 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2153 ads_destroy(&ads);
2154 return -1;
2157 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2159 /* dump the results */
2160 ads_dump(ads, res);
2162 ads_msgfree(ads, res);
2163 ads_destroy(&ads);
2165 return 0;
2169 help for net ads sid search
2171 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2173 d_printf(_(
2174 "\nnet ads sid <sid> <attributes...>\n"
2175 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2176 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2177 "to show in the results\n\n"
2178 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2180 net_common_flags_usage(c, argc, argv);
2181 return -1;
2186 general ADS search function. Useful in diagnosing problems in ADS
2188 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2190 ADS_STRUCT *ads;
2191 ADS_STATUS rc;
2192 const char *sid_string;
2193 const char **attrs;
2194 LDAPMessage *res = NULL;
2195 struct dom_sid sid;
2197 if (argc < 1 || c->display_usage) {
2198 return net_ads_sid_usage(c, argc, argv);
2201 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2202 return -1;
2205 sid_string = argv[0];
2206 attrs = (argv + 1);
2208 if (!string_to_sid(&sid, sid_string)) {
2209 d_fprintf(stderr, _("could not convert sid\n"));
2210 ads_destroy(&ads);
2211 return -1;
2214 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2215 if (!ADS_ERR_OK(rc)) {
2216 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2217 ads_destroy(&ads);
2218 return -1;
2221 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2223 /* dump the results */
2224 ads_dump(ads, res);
2226 ads_msgfree(ads, res);
2227 ads_destroy(&ads);
2229 return 0;
2232 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2234 int ret;
2235 ADS_STRUCT *ads;
2237 if (c->display_usage) {
2238 d_printf( "%s\n"
2239 "net ads keytab flush\n"
2240 " %s\n",
2241 _("Usage:"),
2242 _("Delete the whole keytab"));
2243 return 0;
2246 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2247 return -1;
2249 ret = ads_keytab_flush(ads);
2250 ads_destroy(&ads);
2251 return ret;
2254 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2256 int i;
2257 int ret = 0;
2258 ADS_STRUCT *ads;
2260 if (c->display_usage) {
2261 d_printf("%s\n%s",
2262 _("Usage:"),
2263 _("net ads keytab add <principal> [principal ...]\n"
2264 " Add principals to local keytab\n"
2265 " principal\tKerberos principal to add to "
2266 "keytab\n"));
2267 return 0;
2270 d_printf(_("Processing principals to add...\n"));
2271 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2272 return -1;
2274 for (i = 0; i < argc; i++) {
2275 ret |= ads_keytab_add_entry(ads, argv[i]);
2277 ads_destroy(&ads);
2278 return ret;
2281 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2283 ADS_STRUCT *ads;
2284 int ret;
2286 if (c->display_usage) {
2287 d_printf( "%s\n"
2288 "net ads keytab create\n"
2289 " %s\n",
2290 _("Usage:"),
2291 _("Create new default keytab"));
2292 return 0;
2295 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2296 return -1;
2298 ret = ads_keytab_create_default(ads);
2299 ads_destroy(&ads);
2300 return ret;
2303 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2305 const char *keytab = NULL;
2307 if (c->display_usage) {
2308 d_printf("%s\n%s",
2309 _("Usage:"),
2310 _("net ads keytab list [keytab]\n"
2311 " List a local keytab\n"
2312 " keytab\tKeytab to list\n"));
2313 return 0;
2316 if (argc >= 1) {
2317 keytab = argv[0];
2320 return ads_keytab_list(keytab);
2324 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2326 struct functable func[] = {
2328 "add",
2329 net_ads_keytab_add,
2330 NET_TRANSPORT_ADS,
2331 N_("Add a service principal"),
2332 N_("net ads keytab add\n"
2333 " Add a service principal")
2336 "create",
2337 net_ads_keytab_create,
2338 NET_TRANSPORT_ADS,
2339 N_("Create a fresh keytab"),
2340 N_("net ads keytab create\n"
2341 " Create a fresh keytab")
2344 "flush",
2345 net_ads_keytab_flush,
2346 NET_TRANSPORT_ADS,
2347 N_("Remove all keytab entries"),
2348 N_("net ads keytab flush\n"
2349 " Remove all keytab entries")
2352 "list",
2353 net_ads_keytab_list,
2354 NET_TRANSPORT_ADS,
2355 N_("List a keytab"),
2356 N_("net ads keytab list\n"
2357 " List a keytab")
2359 {NULL, NULL, 0, NULL, NULL}
2362 if (!USE_KERBEROS_KEYTAB) {
2363 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2364 "keytab method to use keytab functions.\n"));
2367 return net_run_function(c, argc, argv, "net ads keytab", func);
2370 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2372 int ret = -1;
2374 if (c->display_usage) {
2375 d_printf( "%s\n"
2376 "net ads kerberos renew\n"
2377 " %s\n",
2378 _("Usage:"),
2379 _("Renew TGT from existing credential cache"));
2380 return 0;
2383 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2384 if (ret) {
2385 d_printf(_("failed to renew kerberos ticket: %s\n"),
2386 error_message(ret));
2388 return ret;
2391 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2393 struct PAC_LOGON_INFO *info = NULL;
2394 TALLOC_CTX *mem_ctx = NULL;
2395 NTSTATUS status;
2396 int ret = -1;
2397 const char *impersonate_princ_s = NULL;
2399 if (c->display_usage) {
2400 d_printf( "%s\n"
2401 "net ads kerberos pac\n"
2402 " %s\n",
2403 _("Usage:"),
2404 _("Dump the Kerberos PAC"));
2405 return 0;
2408 mem_ctx = talloc_init("net_ads_kerberos_pac");
2409 if (!mem_ctx) {
2410 goto out;
2413 if (argc > 0) {
2414 impersonate_princ_s = argv[0];
2417 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2419 status = kerberos_return_pac(mem_ctx,
2420 c->opt_user_name,
2421 c->opt_password,
2423 NULL,
2424 NULL,
2425 NULL,
2426 true,
2427 true,
2428 2592000, /* one month */
2429 impersonate_princ_s,
2430 &info);
2431 if (!NT_STATUS_IS_OK(status)) {
2432 d_printf(_("failed to query kerberos PAC: %s\n"),
2433 nt_errstr(status));
2434 goto out;
2437 if (info) {
2438 const char *s;
2439 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2440 d_printf(_("The Pac: %s\n"), s);
2443 ret = 0;
2444 out:
2445 TALLOC_FREE(mem_ctx);
2446 return ret;
2449 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2451 TALLOC_CTX *mem_ctx = NULL;
2452 int ret = -1;
2453 NTSTATUS status;
2455 if (c->display_usage) {
2456 d_printf( "%s\n"
2457 "net ads kerberos kinit\n"
2458 " %s\n",
2459 _("Usage:"),
2460 _("Get Ticket Granting Ticket (TGT) for the user"));
2461 return 0;
2464 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2465 if (!mem_ctx) {
2466 goto out;
2469 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2471 ret = kerberos_kinit_password_ext(c->opt_user_name,
2472 c->opt_password,
2474 NULL,
2475 NULL,
2476 NULL,
2477 true,
2478 true,
2479 2592000, /* one month */
2480 &status);
2481 if (ret) {
2482 d_printf(_("failed to kinit password: %s\n"),
2483 nt_errstr(status));
2485 out:
2486 return ret;
2489 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2491 struct functable func[] = {
2493 "kinit",
2494 net_ads_kerberos_kinit,
2495 NET_TRANSPORT_ADS,
2496 N_("Retrieve Ticket Granting Ticket (TGT)"),
2497 N_("net ads kerberos kinit\n"
2498 " Receive Ticket Granting Ticket (TGT)")
2501 "renew",
2502 net_ads_kerberos_renew,
2503 NET_TRANSPORT_ADS,
2504 N_("Renew Ticket Granting Ticket from credential cache"),
2505 N_("net ads kerberos renew\n"
2506 " Renew Ticket Granting Ticket (TGT) from "
2507 "credential cache")
2510 "pac",
2511 net_ads_kerberos_pac,
2512 NET_TRANSPORT_ADS,
2513 N_("Dump Kerberos PAC"),
2514 N_("net ads kerberos pac\n"
2515 " Dump Kerberos PAC")
2517 {NULL, NULL, 0, NULL, NULL}
2520 return net_run_function(c, argc, argv, "net ads kerberos", func);
2523 int net_ads(struct net_context *c, int argc, const char **argv)
2525 struct functable func[] = {
2527 "info",
2528 net_ads_info,
2529 NET_TRANSPORT_ADS,
2530 N_("Display details on remote ADS server"),
2531 N_("net ads info\n"
2532 " Display details on remote ADS server")
2535 "join",
2536 net_ads_join,
2537 NET_TRANSPORT_ADS,
2538 N_("Join the local machine to ADS realm"),
2539 N_("net ads join\n"
2540 " Join the local machine to ADS realm")
2543 "testjoin",
2544 net_ads_testjoin,
2545 NET_TRANSPORT_ADS,
2546 N_("Validate machine account"),
2547 N_("net ads testjoin\n"
2548 " Validate machine account")
2551 "leave",
2552 net_ads_leave,
2553 NET_TRANSPORT_ADS,
2554 N_("Remove the local machine from ADS"),
2555 N_("net ads leave\n"
2556 " Remove the local machine from ADS")
2559 "status",
2560 net_ads_status,
2561 NET_TRANSPORT_ADS,
2562 N_("Display machine account details"),
2563 N_("net ads status\n"
2564 " Display machine account details")
2567 "user",
2568 net_ads_user,
2569 NET_TRANSPORT_ADS,
2570 N_("List/modify users"),
2571 N_("net ads user\n"
2572 " List/modify users")
2575 "group",
2576 net_ads_group,
2577 NET_TRANSPORT_ADS,
2578 N_("List/modify groups"),
2579 N_("net ads group\n"
2580 " List/modify groups")
2583 "dns",
2584 net_ads_dns,
2585 NET_TRANSPORT_ADS,
2586 N_("Issue dynamic DNS update"),
2587 N_("net ads dns\n"
2588 " Issue dynamic DNS update")
2591 "password",
2592 net_ads_password,
2593 NET_TRANSPORT_ADS,
2594 N_("Change user passwords"),
2595 N_("net ads password\n"
2596 " Change user passwords")
2599 "changetrustpw",
2600 net_ads_changetrustpw,
2601 NET_TRANSPORT_ADS,
2602 N_("Change trust account password"),
2603 N_("net ads changetrustpw\n"
2604 " Change trust account password")
2607 "printer",
2608 net_ads_printer,
2609 NET_TRANSPORT_ADS,
2610 N_("List/modify printer entries"),
2611 N_("net ads printer\n"
2612 " List/modify printer entries")
2615 "search",
2616 net_ads_search,
2617 NET_TRANSPORT_ADS,
2618 N_("Issue LDAP search using filter"),
2619 N_("net ads search\n"
2620 " Issue LDAP search using filter")
2623 "dn",
2624 net_ads_dn,
2625 NET_TRANSPORT_ADS,
2626 N_("Issue LDAP search by DN"),
2627 N_("net ads dn\n"
2628 " Issue LDAP search by DN")
2631 "sid",
2632 net_ads_sid,
2633 NET_TRANSPORT_ADS,
2634 N_("Issue LDAP search by SID"),
2635 N_("net ads sid\n"
2636 " Issue LDAP search by SID")
2639 "workgroup",
2640 net_ads_workgroup,
2641 NET_TRANSPORT_ADS,
2642 N_("Display workgroup name"),
2643 N_("net ads workgroup\n"
2644 " Display the workgroup name")
2647 "lookup",
2648 net_ads_lookup,
2649 NET_TRANSPORT_ADS,
2650 N_("Perfom CLDAP query on DC"),
2651 N_("net ads lookup\n"
2652 " Find the ADS DC using CLDAP lookups")
2655 "keytab",
2656 net_ads_keytab,
2657 NET_TRANSPORT_ADS,
2658 N_("Manage local keytab file"),
2659 N_("net ads keytab\n"
2660 " Manage local keytab file")
2663 "gpo",
2664 net_ads_gpo,
2665 NET_TRANSPORT_ADS,
2666 N_("Manage group policy objects"),
2667 N_("net ads gpo\n"
2668 " Manage group policy objects")
2671 "kerberos",
2672 net_ads_kerberos,
2673 NET_TRANSPORT_ADS,
2674 N_("Manage kerberos keytab"),
2675 N_("net ads kerberos\n"
2676 " Manage kerberos keytab")
2678 {NULL, NULL, 0, NULL, NULL}
2681 return net_run_function(c, argc, argv, "net ads", func);
2684 #else
2686 static int net_ads_noads(void)
2688 d_fprintf(stderr, _("ADS support not compiled in\n"));
2689 return -1;
2692 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2694 return net_ads_noads();
2697 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2699 return net_ads_noads();
2702 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2704 return net_ads_noads();
2707 int net_ads_join(struct net_context *c, int argc, const char **argv)
2709 return net_ads_noads();
2712 int net_ads_user(struct net_context *c, int argc, const char **argv)
2714 return net_ads_noads();
2717 int net_ads_group(struct net_context *c, int argc, const char **argv)
2719 return net_ads_noads();
2722 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
2724 return net_ads_noads();
2727 /* this one shouldn't display a message */
2728 int net_ads_check(struct net_context *c)
2730 return -1;
2733 int net_ads_check_our_domain(struct net_context *c)
2735 return -1;
2738 int net_ads(struct net_context *c, int argc, const char **argv)
2740 return net_ads_noads();
2743 #endif /* WITH_ADS */