s3 net: Fix compile error with WITH_DNS_UPDATES
[Samba/gebeck_regimport.git] / source3 / utils / net_ads.c
blob8e9f412d6c85b72d74b013f539d991a1832c226b
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"
29 #ifdef HAVE_ADS
31 /* when we do not have sufficient input parameters to contact a remote domain
32 * we always fall back to our own realm - Guenther*/
34 static const char *assume_own_realm(struct net_context *c)
36 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
37 return lp_realm();
40 return NULL;
44 do a cldap netlogon query
46 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
48 char addr[INET6_ADDRSTRLEN];
49 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
51 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
52 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
53 d_fprintf(stderr, _("CLDAP query failed!\n"));
54 return -1;
57 d_printf(_("Information for Domain Controller: %s\n\n"),
58 addr);
60 d_printf(_("Response Type: "));
61 switch (reply.command) {
62 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
63 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
64 break;
65 case LOGON_SAM_LOGON_RESPONSE_EX:
66 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
67 break;
68 default:
69 d_printf("0x%x\n", reply.command);
70 break;
73 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
75 d_printf(_("Flags:\n"
76 "\tIs a PDC: %s\n"
77 "\tIs a GC of the forest: %s\n"
78 "\tIs an LDAP server: %s\n"
79 "\tSupports DS: %s\n"
80 "\tIs running a KDC: %s\n"
81 "\tIs running time services: %s\n"
82 "\tIs the closest DC: %s\n"
83 "\tIs writable: %s\n"
84 "\tHas a hardware clock: %s\n"
85 "\tIs a non-domain NC serviced by LDAP server: %s\n"
86 "\tIs NT6 DC that has some secrets: %s\n"
87 "\tIs NT6 DC that has all secrets: %s\n"),
88 (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
89 (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
90 (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
91 (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
92 (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
93 (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
94 (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
95 (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
96 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
97 (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
98 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
99 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"));
102 printf(_("Forest:\t\t\t%s\n"), reply.forest);
103 printf(_("Domain:\t\t\t%s\n"), reply.dns_domain);
104 printf(_("Domain Controller:\t%s\n"), reply.pdc_dns_name);
106 printf(_("Pre-Win2k Domain:\t%s\n"), reply.domain);
107 printf(_("Pre-Win2k Hostname:\t%s\n"), reply.pdc_name);
109 if (*reply.user_name) printf(_("User name:\t%s\n"), reply.user_name);
111 printf(_("Server Site Name :\t\t%s\n"), reply.server_site);
112 printf(_("Client Site Name :\t\t%s\n"), reply.client_site);
114 d_printf(_("NT Version: %d\n"), reply.nt_version);
115 d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
116 d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
118 return 0;
122 this implements the CLDAP based netlogon lookup requests
123 for finding the domain controller of a ADS domain
125 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
127 ADS_STRUCT *ads;
128 int ret;
130 if (c->display_usage) {
131 d_printf(_("Usage:\n"),
132 "net ads lookup\n"
133 " ",_("Find the ADS DC using CLDAP lookup.\n"));
134 return 0;
137 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
138 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
139 ads_destroy(&ads);
140 return -1;
143 if (!ads->config.realm) {
144 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
145 ads->ldap.port = 389;
148 ret = net_ads_cldap_netlogon(c, ads);
149 ads_destroy(&ads);
150 return ret;
155 static int net_ads_info(struct net_context *c, int argc, const char **argv)
157 ADS_STRUCT *ads;
158 char addr[INET6_ADDRSTRLEN];
160 if (c->display_usage) {
161 d_printf(_("Usage:\n"),
162 "net ads info\n",
163 " ",
164 _("Display information about an Active Directory "
165 "server.\n"));
166 return 0;
169 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
170 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
171 return -1;
174 if (!ads || !ads->config.realm) {
175 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
176 ads_destroy(&ads);
177 return -1;
180 /* Try to set the server's current time since we didn't do a full
181 TCP LDAP session initially */
183 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
184 d_fprintf( stderr, _("Failed to get server's current time!\n"));
187 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
189 d_printf(_("LDAP server: %s\n"), addr);
190 d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
191 d_printf(_("Realm: %s\n"), ads->config.realm);
192 d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
193 d_printf(_("LDAP port: %d\n"), ads->ldap.port);
194 d_printf(_("Server time: %s\n"),
195 http_timestring(talloc_tos(), ads->config.current_time));
197 d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
198 d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
200 ads_destroy(&ads);
201 return 0;
204 static void use_in_memory_ccache(void) {
205 /* Use in-memory credentials cache so we do not interfere with
206 * existing credentials */
207 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
210 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
211 uint32 auth_flags, ADS_STRUCT **ads_ret)
213 ADS_STRUCT *ads = NULL;
214 ADS_STATUS status;
215 bool need_password = false;
216 bool second_time = false;
217 char *cp;
218 const char *realm = NULL;
219 bool tried_closest_dc = false;
221 /* lp_realm() should be handled by a command line param,
222 However, the join requires that realm be set in smb.conf
223 and compares our realm with the remote server's so this is
224 ok until someone needs more flexibility */
226 *ads_ret = NULL;
228 retry_connect:
229 if (only_own_domain) {
230 realm = lp_realm();
231 } else {
232 realm = assume_own_realm(c);
235 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
237 if (!c->opt_user_name) {
238 c->opt_user_name = "administrator";
241 if (c->opt_user_specified) {
242 need_password = true;
245 retry:
246 if (!c->opt_password && need_password && !c->opt_machine_pass) {
247 c->opt_password = net_prompt_pass(c, c->opt_user_name);
248 if (!c->opt_password) {
249 ads_destroy(&ads);
250 return ADS_ERROR(LDAP_NO_MEMORY);
254 if (c->opt_password) {
255 use_in_memory_ccache();
256 SAFE_FREE(ads->auth.password);
257 ads->auth.password = smb_xstrdup(c->opt_password);
260 ads->auth.flags |= auth_flags;
261 SAFE_FREE(ads->auth.user_name);
262 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
265 * If the username is of the form "name@realm",
266 * extract the realm and convert to upper case.
267 * This is only used to establish the connection.
269 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
270 *cp++ = '\0';
271 SAFE_FREE(ads->auth.realm);
272 ads->auth.realm = smb_xstrdup(cp);
273 strupper_m(ads->auth.realm);
276 status = ads_connect(ads);
278 if (!ADS_ERR_OK(status)) {
280 if (NT_STATUS_EQUAL(ads_ntstatus(status),
281 NT_STATUS_NO_LOGON_SERVERS)) {
282 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
283 ads_destroy(&ads);
284 return status;
287 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
288 need_password = true;
289 second_time = true;
290 goto retry;
291 } else {
292 ads_destroy(&ads);
293 return status;
297 /* when contacting our own domain, make sure we use the closest DC.
298 * This is done by reconnecting to ADS because only the first call to
299 * ads_connect will give us our own sitename */
301 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
303 tried_closest_dc = true; /* avoid loop */
305 if (!ads_closest_dc(ads)) {
307 namecache_delete(ads->server.realm, 0x1C);
308 namecache_delete(ads->server.workgroup, 0x1C);
310 ads_destroy(&ads);
311 ads = NULL;
313 goto retry_connect;
317 *ads_ret = ads;
318 return status;
321 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
323 return ads_startup_int(c, only_own_domain, 0, ads);
326 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
328 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
332 Check to see if connection can be made via ads.
333 ads_startup() stores the password in opt_password if it needs to so
334 that rpc or rap can use it without re-prompting.
336 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
338 ADS_STRUCT *ads;
339 ADS_STATUS status;
341 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
342 return -1;
345 ads->auth.flags |= ADS_AUTH_NO_BIND;
347 status = ads_connect(ads);
348 if ( !ADS_ERR_OK(status) ) {
349 return -1;
352 ads_destroy(&ads);
353 return 0;
356 int net_ads_check_our_domain(struct net_context *c)
358 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
361 int net_ads_check(struct net_context *c)
363 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
367 determine the netbios workgroup name for a domain
369 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
371 ADS_STRUCT *ads;
372 char addr[INET6_ADDRSTRLEN];
373 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
375 if (c->display_usage) {
376 d_printf(_("Usage:\n"),
377 "net ads workgroup\n"
378 " ",_("Print the workgroup name\n"));
379 return 0;
382 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
383 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
384 return -1;
387 if (!ads->config.realm) {
388 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
389 ads->ldap.port = 389;
392 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
393 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
394 d_fprintf(stderr, _("CLDAP query failed!\n"));
395 ads_destroy(&ads);
396 return -1;
399 d_printf(_("Workgroup: %s\n"), reply.domain);
401 ads_destroy(&ads);
403 return 0;
408 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
410 char **disp_fields = (char **) data_area;
412 if (!field) { /* must be end of record */
413 if (disp_fields[0]) {
414 if (!strchr_m(disp_fields[0], '$')) {
415 if (disp_fields[1])
416 d_printf("%-21.21s %s\n",
417 disp_fields[0], disp_fields[1]);
418 else
419 d_printf("%s\n", disp_fields[0]);
422 SAFE_FREE(disp_fields[0]);
423 SAFE_FREE(disp_fields[1]);
424 return true;
426 if (!values) /* must be new field, indicate string field */
427 return true;
428 if (StrCaseCmp(field, "sAMAccountName") == 0) {
429 disp_fields[0] = SMB_STRDUP((char *) values[0]);
431 if (StrCaseCmp(field, "description") == 0)
432 disp_fields[1] = SMB_STRDUP((char *) values[0]);
433 return true;
436 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
438 return net_user_usage(c, argc, argv);
441 static int ads_user_add(struct net_context *c, int argc, const char **argv)
443 ADS_STRUCT *ads;
444 ADS_STATUS status;
445 char *upn, *userdn;
446 LDAPMessage *res=NULL;
447 int rc = -1;
448 char *ou_str = NULL;
450 if (argc < 1 || c->display_usage)
451 return net_ads_user_usage(c, argc, argv);
453 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
454 return -1;
457 status = ads_find_user_acct(ads, &res, argv[0]);
459 if (!ADS_ERR_OK(status)) {
460 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
461 goto done;
464 if (ads_count_replies(ads, res)) {
465 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
466 argv[0]);
467 goto done;
470 if (c->opt_container) {
471 ou_str = SMB_STRDUP(c->opt_container);
472 } else {
473 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
476 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
478 if (!ADS_ERR_OK(status)) {
479 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
480 ads_errstr(status));
481 goto done;
484 /* if no password is to be set, we're done */
485 if (argc == 1) {
486 d_printf(_("User %s added\n"), argv[0]);
487 rc = 0;
488 goto done;
491 /* try setting the password */
492 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
493 goto done;
495 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
496 ads->auth.time_offset);
497 SAFE_FREE(upn);
498 if (ADS_ERR_OK(status)) {
499 d_printf(_("User %s added\n"), argv[0]);
500 rc = 0;
501 goto done;
504 /* password didn't set, delete account */
505 d_fprintf(stderr, _("Could not add user %s. "
506 "Error setting password %s\n"),
507 argv[0], ads_errstr(status));
508 ads_msgfree(ads, res);
509 status=ads_find_user_acct(ads, &res, argv[0]);
510 if (ADS_ERR_OK(status)) {
511 userdn = ads_get_dn(ads, talloc_tos(), res);
512 ads_del_dn(ads, userdn);
513 TALLOC_FREE(userdn);
516 done:
517 if (res)
518 ads_msgfree(ads, res);
519 ads_destroy(&ads);
520 SAFE_FREE(ou_str);
521 return rc;
524 static int ads_user_info(struct net_context *c, int argc, const char **argv)
526 ADS_STRUCT *ads = NULL;
527 ADS_STATUS rc;
528 LDAPMessage *res = NULL;
529 TALLOC_CTX *frame;
530 int ret = 0;
531 wbcErr wbc_status;
532 const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
533 char *searchstring=NULL;
534 char **grouplist;
535 char *primary_group;
536 char *escaped_user;
537 DOM_SID primary_group_sid;
538 uint32_t group_rid;
539 enum SID_NAME_USE type;
541 if (argc < 1 || c->display_usage) {
542 return net_ads_user_usage(c, argc, argv);
545 frame = talloc_new(talloc_tos());
546 if (frame == NULL) {
547 return -1;
550 escaped_user = escape_ldap_string(frame, argv[0]);
551 if (!escaped_user) {
552 d_fprintf(stderr,
553 _("ads_user_info: failed to escape user %s\n"),
554 argv[0]);
555 return -1;
558 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
559 ret = -1;
560 goto error;
563 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
564 ret =-1;
565 goto error;
567 rc = ads_search(ads, &res, searchstring, attrs);
568 SAFE_FREE(searchstring);
570 if (!ADS_ERR_OK(rc)) {
571 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(rc));
572 ret = -1;
573 goto error;
576 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
577 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
578 ret = -1;
579 goto error;
582 rc = ads_domain_sid(ads, &primary_group_sid);
583 if (!ADS_ERR_OK(rc)) {
584 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(rc));
585 ret = -1;
586 goto error;
589 sid_append_rid(&primary_group_sid, group_rid);
591 wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
592 NULL, /* don't look up domain */
593 &primary_group,
594 (enum wbcSidType *) &type);
595 if (!WBC_ERROR_IS_OK(wbc_status)) {
596 d_fprintf(stderr, "wbcLookupSid: %s\n",
597 wbcErrorString(wbc_status));
598 ret = -1;
599 goto error;
602 d_printf("%s\n", primary_group);
604 wbcFreeMemory(primary_group);
606 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
607 (LDAPMessage *)res, "memberOf");
609 if (grouplist) {
610 int i;
611 char **groupname;
612 for (i=0;grouplist[i];i++) {
613 groupname = ldap_explode_dn(grouplist[i], 1);
614 d_printf("%s\n", groupname[0]);
615 ldap_value_free(groupname);
617 ldap_value_free(grouplist);
620 error:
621 if (res) ads_msgfree(ads, res);
622 if (ads) ads_destroy(&ads);
623 TALLOC_FREE(frame);
624 return ret;
627 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
629 ADS_STRUCT *ads;
630 ADS_STATUS rc;
631 LDAPMessage *res = NULL;
632 char *userdn;
634 if (argc < 1) {
635 return net_ads_user_usage(c, argc, argv);
638 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
639 return -1;
642 rc = ads_find_user_acct(ads, &res, argv[0]);
643 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
644 d_printf(_("User %s does not exist.\n"), argv[0]);
645 ads_msgfree(ads, res);
646 ads_destroy(&ads);
647 return -1;
649 userdn = ads_get_dn(ads, talloc_tos(), res);
650 ads_msgfree(ads, res);
651 rc = ads_del_dn(ads, userdn);
652 TALLOC_FREE(userdn);
653 if (ADS_ERR_OK(rc)) {
654 d_printf(_("User %s deleted\n"), argv[0]);
655 ads_destroy(&ads);
656 return 0;
658 d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
659 ads_errstr(rc));
660 ads_destroy(&ads);
661 return -1;
664 int net_ads_user(struct net_context *c, int argc, const char **argv)
666 struct functable func[] = {
668 "add",
669 ads_user_add,
670 NET_TRANSPORT_ADS,
671 N_("Add an AD user"),
672 N_("net ads user add\n"
673 " Add an AD user")
676 "info",
677 ads_user_info,
678 NET_TRANSPORT_ADS,
679 N_("Display information about an AD user"),
680 N_("net ads user info\n"
681 " Display information about an AD user")
684 "delete",
685 ads_user_delete,
686 NET_TRANSPORT_ADS,
687 N_("Delete an AD user"),
688 N_("net ads user delete\n"
689 " Delete an AD user")
691 {NULL, NULL, 0, NULL, NULL}
693 ADS_STRUCT *ads;
694 ADS_STATUS rc;
695 const char *shortattrs[] = {"sAMAccountName", NULL};
696 const char *longattrs[] = {"sAMAccountName", "description", NULL};
697 char *disp_fields[2] = {NULL, NULL};
699 if (argc == 0) {
700 if (c->display_usage) {
701 d_printf(_("Usage:\n"),
702 "net ads user\n"
703 " ",_("List AD users\n"));
704 net_display_usage_from_functable(func);
705 return 0;
708 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
709 return -1;
712 if (c->opt_long_list_entries)
713 d_printf(_("\nUser name Comment"
714 "\n-----------------------------\n"));
716 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
717 LDAP_SCOPE_SUBTREE,
718 "(objectCategory=user)",
719 c->opt_long_list_entries ? longattrs :
720 shortattrs, usergrp_display,
721 disp_fields);
722 ads_destroy(&ads);
723 return ADS_ERR_OK(rc) ? 0 : -1;
726 return net_run_function(c, argc, argv, "net ads user", func);
729 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
731 return net_group_usage(c, argc, argv);
734 static int ads_group_add(struct net_context *c, int argc, const char **argv)
736 ADS_STRUCT *ads;
737 ADS_STATUS status;
738 LDAPMessage *res=NULL;
739 int rc = -1;
740 char *ou_str = NULL;
742 if (argc < 1 || c->display_usage) {
743 return net_ads_group_usage(c, argc, argv);
746 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
747 return -1;
750 status = ads_find_user_acct(ads, &res, argv[0]);
752 if (!ADS_ERR_OK(status)) {
753 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
754 goto done;
757 if (ads_count_replies(ads, res)) {
758 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
759 goto done;
762 if (c->opt_container) {
763 ou_str = SMB_STRDUP(c->opt_container);
764 } else {
765 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
768 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
770 if (ADS_ERR_OK(status)) {
771 d_printf(_("Group %s added\n"), argv[0]);
772 rc = 0;
773 } else {
774 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
775 ads_errstr(status));
778 done:
779 if (res)
780 ads_msgfree(ads, res);
781 ads_destroy(&ads);
782 SAFE_FREE(ou_str);
783 return rc;
786 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
788 ADS_STRUCT *ads;
789 ADS_STATUS rc;
790 LDAPMessage *res = NULL;
791 char *groupdn;
793 if (argc < 1 || c->display_usage) {
794 return net_ads_group_usage(c, argc, argv);
797 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
798 return -1;
801 rc = ads_find_user_acct(ads, &res, argv[0]);
802 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
803 d_printf(_("Group %s does not exist.\n"), argv[0]);
804 ads_msgfree(ads, res);
805 ads_destroy(&ads);
806 return -1;
808 groupdn = ads_get_dn(ads, talloc_tos(), res);
809 ads_msgfree(ads, res);
810 rc = ads_del_dn(ads, groupdn);
811 TALLOC_FREE(groupdn);
812 if (ADS_ERR_OK(rc)) {
813 d_printf(_("Group %s deleted\n"), argv[0]);
814 ads_destroy(&ads);
815 return 0;
817 d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
818 ads_errstr(rc));
819 ads_destroy(&ads);
820 return -1;
823 int net_ads_group(struct net_context *c, int argc, const char **argv)
825 struct functable func[] = {
827 "add",
828 ads_group_add,
829 NET_TRANSPORT_ADS,
830 N_("Add an AD group"),
831 N_("net ads group add\n"
832 " Add an AD group")
835 "delete",
836 ads_group_delete,
837 NET_TRANSPORT_ADS,
838 N_("Delete an AD group"),
839 N_("net ads group delete\n"
840 " Delete an AD group")
842 {NULL, NULL, 0, NULL, NULL}
844 ADS_STRUCT *ads;
845 ADS_STATUS rc;
846 const char *shortattrs[] = {"sAMAccountName", NULL};
847 const char *longattrs[] = {"sAMAccountName", "description", NULL};
848 char *disp_fields[2] = {NULL, NULL};
850 if (argc == 0) {
851 if (c->display_usage) {
852 d_printf(_("Usage:\n"),
853 "net ads group\n"
854 " ", _("List AD groups\n"));
855 net_display_usage_from_functable(func);
856 return 0;
859 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
860 return -1;
863 if (c->opt_long_list_entries)
864 d_printf(_("\nGroup name Comment"
865 "\n-----------------------------\n"));
866 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
867 LDAP_SCOPE_SUBTREE,
868 "(objectCategory=group)",
869 c->opt_long_list_entries ? longattrs :
870 shortattrs, usergrp_display,
871 disp_fields);
873 ads_destroy(&ads);
874 return ADS_ERR_OK(rc) ? 0 : -1;
876 return net_run_function(c, argc, argv, "net ads group", func);
879 static int net_ads_status(struct net_context *c, int argc, const char **argv)
881 ADS_STRUCT *ads;
882 ADS_STATUS rc;
883 LDAPMessage *res;
885 if (c->display_usage) {
886 d_printf(_("Usage:\n"),
887 "net ads status\n"
888 " ",_("Display machine account details\n"));
889 return 0;
892 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
893 return -1;
896 rc = ads_find_machine_acct(ads, &res, global_myname());
897 if (!ADS_ERR_OK(rc)) {
898 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
899 ads_destroy(&ads);
900 return -1;
903 if (ads_count_replies(ads, res) == 0) {
904 d_fprintf(stderr, _("No machine account for '%s' found\n"), global_myname());
905 ads_destroy(&ads);
906 return -1;
909 ads_dump(ads, res);
910 ads_destroy(&ads);
911 return 0;
914 /*******************************************************************
915 Leave an AD domain. Windows XP disables the machine account.
916 We'll try the same. The old code would do an LDAP delete.
917 That only worked using the machine creds because added the machine
918 with full control to the computer object's ACL.
919 *******************************************************************/
921 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
923 TALLOC_CTX *ctx;
924 struct libnet_UnjoinCtx *r = NULL;
925 WERROR werr;
927 if (c->display_usage) {
928 d_printf(_("Usage:\n"),
929 "net ads leave\n"
930 " ", _("Leave an AD domain\n"));
931 return 0;
934 if (!*lp_realm()) {
935 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
936 return -1;
939 if (!(ctx = talloc_init("net_ads_leave"))) {
940 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
941 return -1;
944 if (!c->opt_kerberos) {
945 use_in_memory_ccache();
948 werr = libnet_init_UnjoinCtx(ctx, &r);
949 if (!W_ERROR_IS_OK(werr)) {
950 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
951 return -1;
954 r->in.debug = true;
955 r->in.use_kerberos = c->opt_kerberos;
956 r->in.dc_name = c->opt_host;
957 r->in.domain_name = lp_realm();
958 r->in.admin_account = c->opt_user_name;
959 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
960 r->in.modify_config = lp_config_backend_is_registry();
962 /* Try to delete it, but if that fails, disable it. The
963 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
964 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
965 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
966 r->in.delete_machine_account = true;
968 werr = libnet_Unjoin(ctx, r);
969 if (!W_ERROR_IS_OK(werr)) {
970 d_printf(_("Failed to leave domain: %s\n"),
971 r->out.error_string ? r->out.error_string :
972 get_friendly_werror_msg(werr));
973 goto done;
976 if (r->out.deleted_machine_account) {
977 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
978 r->in.machine_name, r->out.dns_domain_name);
979 goto done;
982 /* We couldn't delete it - see if the disable succeeded. */
983 if (r->out.disabled_machine_account) {
984 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
985 r->in.machine_name, r->out.dns_domain_name);
986 werr = WERR_OK;
987 goto done;
990 /* Based on what we requseted, we shouldn't get here, but if
991 we did, it means the secrets were removed, and therefore
992 we have left the domain */
993 d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
994 r->in.machine_name, r->out.dns_domain_name);
996 done:
997 TALLOC_FREE(r);
998 TALLOC_FREE(ctx);
1000 if (W_ERROR_IS_OK(werr)) {
1001 return 0;
1004 return -1;
1007 static NTSTATUS net_ads_join_ok(struct net_context *c)
1009 ADS_STRUCT *ads = NULL;
1010 ADS_STATUS status;
1011 fstring dc_name;
1012 struct sockaddr_storage dcip;
1014 if (!secrets_init()) {
1015 DEBUG(1,("Failed to initialise secrets database\n"));
1016 return NT_STATUS_ACCESS_DENIED;
1019 net_use_krb_machine_account(c);
1021 get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1023 status = ads_startup(c, true, &ads);
1024 if (!ADS_ERR_OK(status)) {
1025 return ads_ntstatus(status);
1028 ads_destroy(&ads);
1029 return NT_STATUS_OK;
1033 check that an existing join is OK
1035 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1037 NTSTATUS status;
1038 use_in_memory_ccache();
1040 if (c->display_usage) {
1041 d_printf(_("Usage:\n"),
1042 "net ads testjoin\n"
1043 " ", _("Test if the existing join is ok\n"));
1044 return 0;
1047 /* Display success or failure */
1048 status = net_ads_join_ok(c);
1049 if (!NT_STATUS_IS_OK(status)) {
1050 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1051 get_friendly_nt_error_msg(status));
1052 return -1;
1055 printf(_("Join is OK\n"));
1056 return 0;
1059 /*******************************************************************
1060 Simple configu checks before beginning the join
1061 ********************************************************************/
1063 static WERROR check_ads_config( void )
1065 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1066 d_printf(_("Host is not configured as a member server.\n"));
1067 return WERR_INVALID_DOMAIN_ROLE;
1070 if (strlen(global_myname()) > 15) {
1071 d_printf(_("Our netbios name can be at most 15 chars long, "
1072 "\"%s\" is %u chars long\n"), global_myname(),
1073 (unsigned int)strlen(global_myname()));
1074 return WERR_INVALID_COMPUTERNAME;
1077 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1078 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1079 "join to succeed.\n"), get_dyn_CONFIGFILE());
1080 return WERR_INVALID_PARAM;
1083 return WERR_OK;
1086 /*******************************************************************
1087 Send a DNS update request
1088 *******************************************************************/
1090 #if defined(WITH_DNS_UPDATES)
1091 #include "dns.h"
1092 DNS_ERROR DoDNSUpdate(char *pszServerName,
1093 const char *pszDomainName, const char *pszHostName,
1094 const struct sockaddr_storage *sslist,
1095 size_t num_addrs );
1097 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1098 const char *machine_name,
1099 const struct sockaddr_storage *addrs,
1100 int num_addrs)
1102 struct dns_rr_ns *nameservers = NULL;
1103 int ns_count = 0;
1104 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1105 DNS_ERROR dns_err;
1106 fstring dns_server;
1107 const char *dnsdomain = NULL;
1108 char *root_domain = NULL;
1110 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1111 d_printf(_("No DNS domain configured for %s. "
1112 "Unable to perform DNS Update.\n"), machine_name);
1113 status = NT_STATUS_INVALID_PARAMETER;
1114 goto done;
1116 dnsdomain++;
1118 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1119 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1120 /* Child domains often do not have NS records. Look
1121 for the NS record for the forest root domain
1122 (rootDomainNamingContext in therootDSE) */
1124 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1125 LDAPMessage *msg = NULL;
1126 char *root_dn;
1127 ADS_STATUS ads_status;
1129 if ( !ads->ldap.ld ) {
1130 ads_status = ads_connect( ads );
1131 if ( !ADS_ERR_OK(ads_status) ) {
1132 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1133 goto done;
1137 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1138 "(objectclass=*)", rootname_attrs, &msg);
1139 if (!ADS_ERR_OK(ads_status)) {
1140 goto done;
1143 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1144 if ( !root_dn ) {
1145 ads_msgfree( ads, msg );
1146 goto done;
1149 root_domain = ads_build_domain( root_dn );
1151 /* cleanup */
1152 ads_msgfree( ads, msg );
1154 /* try again for NS servers */
1156 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1158 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1159 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1160 "realm\n", ads->config.realm));
1161 goto done;
1164 dnsdomain = root_domain;
1168 /* Now perform the dns update - we'll try non-secure and if we fail,
1169 we'll follow it up with a secure update */
1171 fstrcpy( dns_server, nameservers[0].hostname );
1173 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1174 if (!ERR_DNS_IS_OK(dns_err)) {
1175 status = NT_STATUS_UNSUCCESSFUL;
1178 done:
1180 SAFE_FREE( root_domain );
1182 return status;
1185 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1187 int num_addrs;
1188 struct sockaddr_storage *iplist = NULL;
1189 fstring machine_name;
1190 NTSTATUS status;
1192 name_to_fqdn( machine_name, global_myname() );
1193 strlower_m( machine_name );
1195 /* Get our ip address (not the 127.0.0.x address but a real ip
1196 * address) */
1198 num_addrs = get_my_ip_address( &iplist );
1199 if ( num_addrs <= 0 ) {
1200 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1201 "addresses!\n"));
1202 return NT_STATUS_INVALID_PARAMETER;
1205 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1206 iplist, num_addrs);
1207 SAFE_FREE( iplist );
1208 return status;
1210 #endif
1213 /*******************************************************************
1214 ********************************************************************/
1216 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1218 d_printf(_("net ads join [options]\n"
1219 "Valid options:\n"));
1220 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1221 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1222 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1223 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1224 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1225 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1226 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1227 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1228 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1229 " NB: osName and osVer must be specified together for either to take effect.\n"
1230 " Also, the operatingSystemService attribute is also set when along with\n"
1231 " the two other attributes.\n"));
1233 return -1;
1236 /*******************************************************************
1237 ********************************************************************/
1239 int net_ads_join(struct net_context *c, int argc, const char **argv)
1241 TALLOC_CTX *ctx = NULL;
1242 struct libnet_JoinCtx *r = NULL;
1243 const char *domain = lp_realm();
1244 WERROR werr = WERR_SETUP_NOT_JOINED;
1245 bool createupn = false;
1246 const char *machineupn = NULL;
1247 const char *create_in_ou = NULL;
1248 int i;
1249 const char *os_name = NULL;
1250 const char *os_version = NULL;
1251 bool modify_config = lp_config_backend_is_registry();
1253 if (c->display_usage)
1254 return net_ads_join_usage(c, argc, argv);
1256 if (!modify_config) {
1258 werr = check_ads_config();
1259 if (!W_ERROR_IS_OK(werr)) {
1260 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1261 goto fail;
1265 if (!(ctx = talloc_init("net_ads_join"))) {
1266 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1267 werr = WERR_NOMEM;
1268 goto fail;
1271 if (!c->opt_kerberos) {
1272 use_in_memory_ccache();
1275 werr = libnet_init_JoinCtx(ctx, &r);
1276 if (!W_ERROR_IS_OK(werr)) {
1277 goto fail;
1280 /* process additional command line args */
1282 for ( i=0; i<argc; i++ ) {
1283 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1284 createupn = true;
1285 machineupn = get_string_param(argv[i]);
1287 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1288 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1289 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1290 werr = WERR_INVALID_PARAM;
1291 goto fail;
1294 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1295 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1296 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1297 werr = WERR_INVALID_PARAM;
1298 goto fail;
1301 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1302 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1303 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1304 werr = WERR_INVALID_PARAM;
1305 goto fail;
1308 else {
1309 domain = argv[i];
1313 if (!*domain) {
1314 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1315 werr = WERR_INVALID_PARAM;
1316 goto fail;
1319 /* Do the domain join here */
1321 r->in.domain_name = domain;
1322 r->in.create_upn = createupn;
1323 r->in.upn = machineupn;
1324 r->in.account_ou = create_in_ou;
1325 r->in.os_name = os_name;
1326 r->in.os_version = os_version;
1327 r->in.dc_name = c->opt_host;
1328 r->in.admin_account = c->opt_user_name;
1329 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1330 r->in.debug = true;
1331 r->in.use_kerberos = c->opt_kerberos;
1332 r->in.modify_config = modify_config;
1333 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1334 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1335 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1337 werr = libnet_Join(ctx, r);
1338 if (!W_ERROR_IS_OK(werr)) {
1339 goto fail;
1342 /* Check the short name of the domain */
1344 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1345 d_printf(_("The workgroup in %s does not match the short\n"
1346 "domain name obtained from the server.\n"
1347 "Using the name [%s] from the server.\n"
1348 "You should set \"workgroup = %s\" in %s.\n"),
1349 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1350 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1353 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1355 if (r->out.dns_domain_name) {
1356 d_printf(_("Joined '%s' to realm '%s'\n"), r->in.machine_name,
1357 r->out.dns_domain_name);
1358 } else {
1359 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1360 r->out.netbios_domain_name);
1363 #if defined(WITH_DNS_UPDATES)
1364 if (r->out.domain_is_ad) {
1365 /* We enter this block with user creds */
1366 ADS_STRUCT *ads_dns = NULL;
1368 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1369 /* kinit with the machine password */
1371 use_in_memory_ccache();
1372 if (asprintf( &ads_dns->auth.user_name, "%s$", global_myname()) == -1) {
1373 goto fail;
1375 ads_dns->auth.password = secrets_fetch_machine_password(
1376 r->out.netbios_domain_name, NULL, NULL );
1377 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1378 strupper_m(ads_dns->auth.realm );
1379 ads_kinit_password( ads_dns );
1382 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1383 d_fprintf( stderr, _("DNS update failed!\n") );
1386 /* exit from this block using machine creds */
1387 ads_destroy(&ads_dns);
1389 #endif
1390 TALLOC_FREE(r);
1391 TALLOC_FREE( ctx );
1393 return 0;
1395 fail:
1396 /* issue an overall failure message at the end. */
1397 d_printf(_("Failed to join domain: %s\n"),
1398 r && r->out.error_string ? r->out.error_string :
1399 get_friendly_werror_msg(werr));
1400 TALLOC_FREE( ctx );
1402 return -1;
1405 /*******************************************************************
1406 ********************************************************************/
1408 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1410 #if defined(WITH_DNS_UPDATES)
1411 ADS_STRUCT *ads;
1412 ADS_STATUS status;
1413 TALLOC_CTX *ctx;
1415 #ifdef DEVELOPER
1416 talloc_enable_leak_report();
1417 #endif
1419 if (argc > 0 || c->display_usage) {
1420 d_printf(_("Usage:\n"),
1421 "net ads dns register\n"
1422 " ", _("Register hostname with DNS\n"));
1423 return -1;
1426 if (!(ctx = talloc_init("net_ads_dns"))) {
1427 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1428 return -1;
1431 status = ads_startup(c, true, &ads);
1432 if ( !ADS_ERR_OK(status) ) {
1433 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1434 TALLOC_FREE(ctx);
1435 return -1;
1438 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1439 d_fprintf( stderr, _("DNS update failed!\n") );
1440 ads_destroy( &ads );
1441 TALLOC_FREE( ctx );
1442 return -1;
1445 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1447 ads_destroy(&ads);
1448 TALLOC_FREE( ctx );
1450 return 0;
1451 #else
1452 d_fprintf(stderr,
1453 _("DNS update support not enabled at compile time!\n"));
1454 return -1;
1455 #endif
1458 #if defined(WITH_DNS_UPDATES)
1459 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1460 #endif
1462 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1464 #if defined(WITH_DNS_UPDATES)
1465 DNS_ERROR err;
1467 #ifdef DEVELOPER
1468 talloc_enable_leak_report();
1469 #endif
1471 if (argc != 2 || c->display_usage) {
1472 d_printf(_("Usage:\n"),
1473 _("net ads dns gethostbyname <server> <name>\n"),
1474 _(" Look up hostname from the AD\n"
1475 " server\tName server to use\n"
1476 " name\tName to look up\n"));
1477 return -1;
1480 err = do_gethostbyname(argv[0], argv[1]);
1482 d_printf(_("do_gethostbyname returned %d\n"), ERROR_DNS_V(err));
1483 #endif
1484 return 0;
1487 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1489 struct functable func[] = {
1491 "register",
1492 net_ads_dns_register,
1493 NET_TRANSPORT_ADS,
1494 N_("Add host dns entry to AD"),
1495 N_("net ads dns register\n"
1496 " Add host dns entry to AD")
1499 "gethostbyname",
1500 net_ads_dns_gethostbyname,
1501 NET_TRANSPORT_ADS,
1502 N_("Look up host"),
1503 N_("net ads dns gethostbyname\n"
1504 " Look up host")
1506 {NULL, NULL, 0, NULL, NULL}
1509 return net_run_function(c, argc, argv, "net ads dns", func);
1512 /*******************************************************************
1513 ********************************************************************/
1515 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1517 d_printf(_(
1518 "\nnet ads printer search <printer>"
1519 "\n\tsearch for a printer in the directory\n"
1520 "\nnet ads printer info <printer> <server>"
1521 "\n\tlookup info in directory for printer on server"
1522 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1523 "\nnet ads printer publish <printername>"
1524 "\n\tpublish printer in directory"
1525 "\n\t(note: printer name is required)\n"
1526 "\nnet ads printer remove <printername>"
1527 "\n\tremove printer from directory"
1528 "\n\t(note: printer name is required)\n"));
1529 return -1;
1532 /*******************************************************************
1533 ********************************************************************/
1535 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1537 ADS_STRUCT *ads;
1538 ADS_STATUS rc;
1539 LDAPMessage *res = NULL;
1541 if (c->display_usage) {
1542 d_printf(_("Usage:\n"),
1543 "net ads printer search\n"
1544 " ", _("List printers in the AD\n"));
1545 return 0;
1548 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1549 return -1;
1552 rc = ads_find_printers(ads, &res);
1554 if (!ADS_ERR_OK(rc)) {
1555 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
1556 ads_msgfree(ads, res);
1557 ads_destroy(&ads);
1558 return -1;
1561 if (ads_count_replies(ads, res) == 0) {
1562 d_fprintf(stderr, _("No results found\n"));
1563 ads_msgfree(ads, res);
1564 ads_destroy(&ads);
1565 return -1;
1568 ads_dump(ads, res);
1569 ads_msgfree(ads, res);
1570 ads_destroy(&ads);
1571 return 0;
1574 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1576 ADS_STRUCT *ads;
1577 ADS_STATUS rc;
1578 const char *servername, *printername;
1579 LDAPMessage *res = NULL;
1581 if (c->display_usage) {
1582 d_printf(_("Usage:\n"),
1583 _("net ads printer info [printername [servername]]\n"
1584 " Display printer info from AD\n"
1585 " printername\tPrinter name or wildcard\n"
1586 " servername\tName of the print server\n"));
1587 return 0;
1590 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1591 return -1;
1594 if (argc > 0) {
1595 printername = argv[0];
1596 } else {
1597 printername = "*";
1600 if (argc > 1) {
1601 servername = argv[1];
1602 } else {
1603 servername = global_myname();
1606 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1608 if (!ADS_ERR_OK(rc)) {
1609 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
1610 servername, ads_errstr(rc));
1611 ads_msgfree(ads, res);
1612 ads_destroy(&ads);
1613 return -1;
1616 if (ads_count_replies(ads, res) == 0) {
1617 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
1618 ads_msgfree(ads, res);
1619 ads_destroy(&ads);
1620 return -1;
1623 ads_dump(ads, res);
1624 ads_msgfree(ads, res);
1625 ads_destroy(&ads);
1627 return 0;
1630 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1632 ADS_STRUCT *ads;
1633 ADS_STATUS rc;
1634 const char *servername, *printername;
1635 struct cli_state *cli = NULL;
1636 struct rpc_pipe_client *pipe_hnd = NULL;
1637 struct sockaddr_storage server_ss;
1638 NTSTATUS nt_status;
1639 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1640 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1641 char *prt_dn, *srv_dn, **srv_cn;
1642 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1643 LDAPMessage *res = NULL;
1645 if (argc < 1 || c->display_usage) {
1646 d_printf(_("Usage:\n"),
1647 _("net ads printer publish <printername> [servername]\n"
1648 " Publish printer in AD\n"
1649 " printername\tName of the printer\n"
1650 " servername\tName of the print server\n"));
1651 talloc_destroy(mem_ctx);
1652 return -1;
1655 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1656 talloc_destroy(mem_ctx);
1657 return -1;
1660 printername = argv[0];
1662 if (argc == 2) {
1663 servername = argv[1];
1664 } else {
1665 servername = global_myname();
1668 /* Get printer data from SPOOLSS */
1670 resolve_name(servername, &server_ss, 0x20, false);
1672 nt_status = cli_full_connection(&cli, global_myname(), servername,
1673 &server_ss, 0,
1674 "IPC$", "IPC",
1675 c->opt_user_name, c->opt_workgroup,
1676 c->opt_password ? c->opt_password : "",
1677 CLI_FULL_CONNECTION_USE_KERBEROS,
1678 Undefined, NULL);
1680 if (NT_STATUS_IS_ERR(nt_status)) {
1681 d_fprintf(stderr, _("Unable to open a connnection to %s to "
1682 "obtain data for %s\n"),
1683 servername, printername);
1684 ads_destroy(&ads);
1685 talloc_destroy(mem_ctx);
1686 return -1;
1689 /* Publish on AD server */
1691 ads_find_machine_acct(ads, &res, servername);
1693 if (ads_count_replies(ads, res) == 0) {
1694 d_fprintf(stderr, _("Could not find machine account for server "
1695 "%s\n"),
1696 servername);
1697 ads_destroy(&ads);
1698 talloc_destroy(mem_ctx);
1699 return -1;
1702 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1703 srv_cn = ldap_explode_dn(srv_dn, 1);
1705 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1706 printername_escaped = escape_rdn_val_string_alloc(printername);
1707 if (!srv_cn_escaped || !printername_escaped) {
1708 SAFE_FREE(srv_cn_escaped);
1709 SAFE_FREE(printername_escaped);
1710 d_fprintf(stderr, _("Internal error, out of memory!"));
1711 ads_destroy(&ads);
1712 talloc_destroy(mem_ctx);
1713 return -1;
1716 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1717 SAFE_FREE(srv_cn_escaped);
1718 SAFE_FREE(printername_escaped);
1719 d_fprintf(stderr, _("Internal error, out of memory!"));
1720 ads_destroy(&ads);
1721 talloc_destroy(mem_ctx);
1722 return -1;
1725 SAFE_FREE(srv_cn_escaped);
1726 SAFE_FREE(printername_escaped);
1728 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
1729 if (!NT_STATUS_IS_OK(nt_status)) {
1730 d_fprintf(stderr, _("Unable to open a connnection to the spoolss pipe on %s\n"),
1731 servername);
1732 SAFE_FREE(prt_dn);
1733 ads_destroy(&ads);
1734 talloc_destroy(mem_ctx);
1735 return -1;
1738 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1739 printername))) {
1740 SAFE_FREE(prt_dn);
1741 ads_destroy(&ads);
1742 talloc_destroy(mem_ctx);
1743 return -1;
1746 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1747 if (!ADS_ERR_OK(rc)) {
1748 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1749 SAFE_FREE(prt_dn);
1750 ads_destroy(&ads);
1751 talloc_destroy(mem_ctx);
1752 return -1;
1755 d_printf("published printer\n");
1756 SAFE_FREE(prt_dn);
1757 ads_destroy(&ads);
1758 talloc_destroy(mem_ctx);
1760 return 0;
1763 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1765 ADS_STRUCT *ads;
1766 ADS_STATUS rc;
1767 const char *servername;
1768 char *prt_dn;
1769 LDAPMessage *res = NULL;
1771 if (argc < 1 || c->display_usage) {
1772 d_printf(_("Usage:\n"),
1773 _("net ads printer remove <printername> [servername]\n"
1774 " Remove a printer from the AD\n"
1775 " printername\tName of the printer\n"
1776 " servername\tName of the print server\n"));
1777 return -1;
1780 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1781 return -1;
1784 if (argc > 1) {
1785 servername = argv[1];
1786 } else {
1787 servername = global_myname();
1790 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1792 if (!ADS_ERR_OK(rc)) {
1793 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
1794 ads_msgfree(ads, res);
1795 ads_destroy(&ads);
1796 return -1;
1799 if (ads_count_replies(ads, res) == 0) {
1800 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
1801 ads_msgfree(ads, res);
1802 ads_destroy(&ads);
1803 return -1;
1806 prt_dn = ads_get_dn(ads, talloc_tos(), res);
1807 ads_msgfree(ads, res);
1808 rc = ads_del_dn(ads, prt_dn);
1809 TALLOC_FREE(prt_dn);
1811 if (!ADS_ERR_OK(rc)) {
1812 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
1813 ads_destroy(&ads);
1814 return -1;
1817 ads_destroy(&ads);
1818 return 0;
1821 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1823 struct functable func[] = {
1825 "search",
1826 net_ads_printer_search,
1827 NET_TRANSPORT_ADS,
1828 N_("Search for a printer"),
1829 N_("net ads printer search\n"
1830 " Search for a printer")
1833 "info",
1834 net_ads_printer_info,
1835 NET_TRANSPORT_ADS,
1836 N_("Display printer information"),
1837 N_("net ads printer info\n"
1838 " Display printer information")
1841 "publish",
1842 net_ads_printer_publish,
1843 NET_TRANSPORT_ADS,
1844 N_("Publish a printer"),
1845 N_("net ads printer publish\n"
1846 " Publish a printer")
1849 "remove",
1850 net_ads_printer_remove,
1851 NET_TRANSPORT_ADS,
1852 N_("Delete a printer"),
1853 N_("net ads printer remove\n"
1854 " Delete a printer")
1856 {NULL, NULL, 0, NULL, NULL}
1859 return net_run_function(c, argc, argv, "net ads printer", func);
1863 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1865 ADS_STRUCT *ads;
1866 const char *auth_principal = c->opt_user_name;
1867 const char *auth_password = c->opt_password;
1868 char *realm = NULL;
1869 char *new_password = NULL;
1870 char *chr, *prompt;
1871 const char *user;
1872 ADS_STATUS ret;
1874 if (c->display_usage) {
1875 d_printf(_("Usage:\n"),
1876 _("net ads password <username>\n"
1877 " Change password for user\n"
1878 " username\tName of user to change password for\n"));
1879 return 0;
1882 if (c->opt_user_name == NULL || c->opt_password == NULL) {
1883 d_fprintf(stderr, _("You must supply an administrator "
1884 "username/password\n"));
1885 return -1;
1888 if (argc < 1) {
1889 d_fprintf(stderr, _("ERROR: You must say which username to "
1890 "change password for\n"));
1891 return -1;
1894 user = argv[0];
1895 if (!strchr_m(user, '@')) {
1896 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
1897 return -1;
1899 user = chr;
1902 use_in_memory_ccache();
1903 chr = strchr_m(auth_principal, '@');
1904 if (chr) {
1905 realm = ++chr;
1906 } else {
1907 realm = lp_realm();
1910 /* use the realm so we can eventually change passwords for users
1911 in realms other than default */
1912 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1913 return -1;
1916 /* we don't actually need a full connect, but it's the easy way to
1917 fill in the KDC's addresss */
1918 ads_connect(ads);
1920 if (!ads->config.realm) {
1921 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
1922 ads_destroy(&ads);
1923 return -1;
1926 if (argv[1]) {
1927 new_password = (char *)argv[1];
1928 } else {
1929 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
1930 return -1;
1932 new_password = getpass(prompt);
1933 free(prompt);
1936 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1937 auth_password, user, new_password, ads->auth.time_offset);
1938 if (!ADS_ERR_OK(ret)) {
1939 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
1940 ads_destroy(&ads);
1941 return -1;
1944 d_printf(_("Password change for %s completed.\n"), user);
1945 ads_destroy(&ads);
1947 return 0;
1950 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1952 ADS_STRUCT *ads;
1953 char *host_principal;
1954 fstring my_name;
1955 ADS_STATUS ret;
1957 if (c->display_usage) {
1958 d_printf(_("Usage:\n"),
1959 "net ads changetrustpw\n"
1960 " ", _("Change the machine account's trust password\n"));
1961 return 0;
1964 if (!secrets_init()) {
1965 DEBUG(1,("Failed to initialise secrets database\n"));
1966 return -1;
1969 net_use_krb_machine_account(c);
1971 use_in_memory_ccache();
1973 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1974 return -1;
1977 fstrcpy(my_name, global_myname());
1978 strlower_m(my_name);
1979 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
1980 ads_destroy(&ads);
1981 return -1;
1983 d_printf(_("Changing password for principal: %s\n"), host_principal);
1985 ret = ads_change_trust_account_password(ads, host_principal);
1987 if (!ADS_ERR_OK(ret)) {
1988 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
1989 ads_destroy(&ads);
1990 SAFE_FREE(host_principal);
1991 return -1;
1994 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
1996 if (USE_SYSTEM_KEYTAB) {
1997 d_printf(_("Attempting to update system keytab with new password.\n"));
1998 if (ads_keytab_create_default(ads)) {
1999 d_printf(_("Failed to update system keytab.\n"));
2003 ads_destroy(&ads);
2004 SAFE_FREE(host_principal);
2006 return 0;
2010 help for net ads search
2012 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2014 d_printf(_(
2015 "\nnet ads search <expression> <attributes...>\n"
2016 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2017 "The expression is a standard LDAP search expression, and the\n"
2018 "attributes are a list of LDAP fields to show in the results.\n\n"
2019 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2021 net_common_flags_usage(c, argc, argv);
2022 return -1;
2027 general ADS search function. Useful in diagnosing problems in ADS
2029 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2031 ADS_STRUCT *ads;
2032 ADS_STATUS rc;
2033 const char *ldap_exp;
2034 const char **attrs;
2035 LDAPMessage *res = NULL;
2037 if (argc < 1 || c->display_usage) {
2038 return net_ads_search_usage(c, argc, argv);
2041 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2042 return -1;
2045 ldap_exp = argv[0];
2046 attrs = (argv + 1);
2048 rc = ads_do_search_all(ads, ads->config.bind_path,
2049 LDAP_SCOPE_SUBTREE,
2050 ldap_exp, attrs, &res);
2051 if (!ADS_ERR_OK(rc)) {
2052 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2053 ads_destroy(&ads);
2054 return -1;
2057 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2059 /* dump the results */
2060 ads_dump(ads, res);
2062 ads_msgfree(ads, res);
2063 ads_destroy(&ads);
2065 return 0;
2070 help for net ads search
2072 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2074 d_printf(_(
2075 "\nnet ads dn <dn> <attributes...>\n"
2076 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2077 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2078 "to show in the results\n\n"
2079 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2080 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2082 net_common_flags_usage(c, argc, argv);
2083 return -1;
2088 general ADS search function. Useful in diagnosing problems in ADS
2090 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2092 ADS_STRUCT *ads;
2093 ADS_STATUS rc;
2094 const char *dn;
2095 const char **attrs;
2096 LDAPMessage *res = NULL;
2098 if (argc < 1 || c->display_usage) {
2099 return net_ads_dn_usage(c, argc, argv);
2102 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2103 return -1;
2106 dn = argv[0];
2107 attrs = (argv + 1);
2109 rc = ads_do_search_all(ads, dn,
2110 LDAP_SCOPE_BASE,
2111 "(objectclass=*)", attrs, &res);
2112 if (!ADS_ERR_OK(rc)) {
2113 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2114 ads_destroy(&ads);
2115 return -1;
2118 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2120 /* dump the results */
2121 ads_dump(ads, res);
2123 ads_msgfree(ads, res);
2124 ads_destroy(&ads);
2126 return 0;
2130 help for net ads sid search
2132 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2134 d_printf(_(
2135 "\nnet ads sid <sid> <attributes...>\n"
2136 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2137 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2138 "to show in the results\n\n"
2139 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2141 net_common_flags_usage(c, argc, argv);
2142 return -1;
2147 general ADS search function. Useful in diagnosing problems in ADS
2149 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2151 ADS_STRUCT *ads;
2152 ADS_STATUS rc;
2153 const char *sid_string;
2154 const char **attrs;
2155 LDAPMessage *res = NULL;
2156 DOM_SID sid;
2158 if (argc < 1 || c->display_usage) {
2159 return net_ads_sid_usage(c, argc, argv);
2162 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2163 return -1;
2166 sid_string = argv[0];
2167 attrs = (argv + 1);
2169 if (!string_to_sid(&sid, sid_string)) {
2170 d_fprintf(stderr, _("could not convert sid\n"));
2171 ads_destroy(&ads);
2172 return -1;
2175 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2176 if (!ADS_ERR_OK(rc)) {
2177 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2178 ads_destroy(&ads);
2179 return -1;
2182 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2184 /* dump the results */
2185 ads_dump(ads, res);
2187 ads_msgfree(ads, res);
2188 ads_destroy(&ads);
2190 return 0;
2193 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2195 int ret;
2196 ADS_STRUCT *ads;
2198 if (c->display_usage) {
2199 d_printf(_("Usage:\n"),
2200 "net ads keytab flush\n"
2201 " ", _("Delete the whole keytab\n"));
2202 return 0;
2205 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2206 return -1;
2208 ret = ads_keytab_flush(ads);
2209 ads_destroy(&ads);
2210 return ret;
2213 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2215 int i;
2216 int ret = 0;
2217 ADS_STRUCT *ads;
2219 if (c->display_usage) {
2220 d_printf(_("Usage:\n"),
2221 _("net ads keytab add <principal> [principal ...]\n"
2222 " Add principals to local keytab\n"
2223 " principal\tKerberos principal to add to "
2224 "keytab\n"));
2225 return 0;
2228 d_printf(_("Processing principals to add...\n"));
2229 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2230 return -1;
2232 for (i = 0; i < argc; i++) {
2233 ret |= ads_keytab_add_entry(ads, argv[i]);
2235 ads_destroy(&ads);
2236 return ret;
2239 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2241 ADS_STRUCT *ads;
2242 int ret;
2244 if (c->display_usage) {
2245 d_printf(_("Usage:\n"),
2246 "net ads keytab create\n"
2247 " ", _("Create new default keytab\n"));
2248 return 0;
2251 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2252 return -1;
2254 ret = ads_keytab_create_default(ads);
2255 ads_destroy(&ads);
2256 return ret;
2259 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2261 const char *keytab = NULL;
2263 if (c->display_usage) {
2264 d_printf(_("Usage:\n"),
2265 _("net ads keytab list [keytab]\n"
2266 " List a local keytab\n"
2267 " keytab\tKeytab to list\n"));
2268 return 0;
2271 if (argc >= 1) {
2272 keytab = argv[0];
2275 return ads_keytab_list(keytab);
2279 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2281 struct functable func[] = {
2283 "add",
2284 net_ads_keytab_add,
2285 NET_TRANSPORT_ADS,
2286 N_("Add a service principal"),
2287 N_("net ads keytab add\n"
2288 " Add a service principal")
2291 "create",
2292 net_ads_keytab_create,
2293 NET_TRANSPORT_ADS,
2294 N_("Create a fresh keytab"),
2295 N_("net ads keytab create\n"
2296 " Create a fresh keytab")
2299 "flush",
2300 net_ads_keytab_flush,
2301 NET_TRANSPORT_ADS,
2302 N_("Remove all keytab entries"),
2303 N_("net ads keytab flush\n"
2304 " Remove all keytab entries")
2307 "list",
2308 net_ads_keytab_list,
2309 NET_TRANSPORT_ADS,
2310 N_("List a keytab"),
2311 N_("net ads keytab list\n"
2312 " List a keytab")
2314 {NULL, NULL, 0, NULL, NULL}
2317 if (!USE_KERBEROS_KEYTAB) {
2318 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2319 "keytab method to use keytab functions.\n"));
2322 return net_run_function(c, argc, argv, "net ads keytab", func);
2325 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2327 int ret = -1;
2329 if (c->display_usage) {
2330 d_printf(_("Usage:\n"),
2331 "net ads kerberos renew\n"
2332 " ", _("Renew TGT from existing credential cache\n"));
2333 return 0;
2336 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2337 if (ret) {
2338 d_printf(_("failed to renew kerberos ticket: %s\n"),
2339 error_message(ret));
2341 return ret;
2344 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2346 struct PAC_DATA *pac = NULL;
2347 struct PAC_LOGON_INFO *info = NULL;
2348 TALLOC_CTX *mem_ctx = NULL;
2349 NTSTATUS status;
2350 int ret = -1;
2351 const char *impersonate_princ_s = NULL;
2353 if (c->display_usage) {
2354 d_printf(_("Usage:\n"),
2355 "net ads kerberos pac\n"
2356 " ", _("Dump the Kerberos PAC\n"));
2357 return 0;
2360 mem_ctx = talloc_init("net_ads_kerberos_pac");
2361 if (!mem_ctx) {
2362 goto out;
2365 if (argc > 0) {
2366 impersonate_princ_s = argv[0];
2369 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2371 status = kerberos_return_pac(mem_ctx,
2372 c->opt_user_name,
2373 c->opt_password,
2375 NULL,
2376 NULL,
2377 NULL,
2378 true,
2379 true,
2380 2592000, /* one month */
2381 impersonate_princ_s,
2382 &pac);
2383 if (!NT_STATUS_IS_OK(status)) {
2384 d_printf(_("failed to query kerberos PAC: %s\n"),
2385 nt_errstr(status));
2386 goto out;
2389 info = get_logon_info_from_pac(pac);
2390 if (info) {
2391 const char *s;
2392 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2393 d_printf(_("The Pac: %s\n"), s);
2396 ret = 0;
2397 out:
2398 TALLOC_FREE(mem_ctx);
2399 return ret;
2402 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2404 TALLOC_CTX *mem_ctx = NULL;
2405 int ret = -1;
2406 NTSTATUS status;
2408 if (c->display_usage) {
2409 d_printf(_("Usage:\n"),
2410 "net ads kerberos kinit\n"
2411 " ", _("Get Ticket Granting Ticket (TGT) for the user\n"));
2412 return 0;
2415 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2416 if (!mem_ctx) {
2417 goto out;
2420 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2422 ret = kerberos_kinit_password_ext(c->opt_user_name,
2423 c->opt_password,
2425 NULL,
2426 NULL,
2427 NULL,
2428 true,
2429 true,
2430 2592000, /* one month */
2431 &status);
2432 if (ret) {
2433 d_printf(_("failed to kinit password: %s\n"),
2434 nt_errstr(status));
2436 out:
2437 return ret;
2440 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2442 struct functable func[] = {
2444 "kinit",
2445 net_ads_kerberos_kinit,
2446 NET_TRANSPORT_ADS,
2447 N_("Retrieve Ticket Granting Ticket (TGT)"),
2448 N_("net ads kerberos kinit\n"
2449 " Receive Ticket Granting Ticket (TGT)")
2452 "renew",
2453 net_ads_kerberos_renew,
2454 NET_TRANSPORT_ADS,
2455 N_("Renew Ticket Granting Ticket from credential cache"),
2456 N_("net ads kerberos renew\n"
2457 " Renew Ticket Granting Ticket (TGT) from "
2458 "credential cache")
2461 "pac",
2462 net_ads_kerberos_pac,
2463 NET_TRANSPORT_ADS,
2464 N_("Dump Kerberos PAC"),
2465 N_("net ads kerberos pac\n"
2466 " Dump Kerberos PAC")
2468 {NULL, NULL, 0, NULL, NULL}
2471 return net_run_function(c, argc, argv, "net ads kerberos", func);
2474 int net_ads(struct net_context *c, int argc, const char **argv)
2476 struct functable func[] = {
2478 "info",
2479 net_ads_info,
2480 NET_TRANSPORT_ADS,
2481 N_("Display details on remote ADS server"),
2482 N_("net ads info\n"
2483 " Display details on remote ADS server")
2486 "join",
2487 net_ads_join,
2488 NET_TRANSPORT_ADS,
2489 N_("Join the local machine to ADS realm"),
2490 N_("net ads join\n"
2491 " Join the local machine to ADS realm")
2494 "testjoin",
2495 net_ads_testjoin,
2496 NET_TRANSPORT_ADS,
2497 N_("Validate machine account"),
2498 N_("net ads testjoin\n"
2499 " Validate machine account")
2502 "leave",
2503 net_ads_leave,
2504 NET_TRANSPORT_ADS,
2505 N_("Remove the local machine from ADS"),
2506 N_("net ads leave\n"
2507 " Remove the local machine from ADS")
2510 "status",
2511 net_ads_status,
2512 NET_TRANSPORT_ADS,
2513 N_("Display machine account details"),
2514 N_("net ads status\n"
2515 " Display machine account details")
2518 "user",
2519 net_ads_user,
2520 NET_TRANSPORT_ADS,
2521 N_("List/modify users"),
2522 N_("net ads user\n"
2523 " List/modify users")
2526 "group",
2527 net_ads_group,
2528 NET_TRANSPORT_ADS,
2529 N_("List/modify groups"),
2530 N_("net ads group\n"
2531 " List/modify groups")
2534 "dns",
2535 net_ads_dns,
2536 NET_TRANSPORT_ADS,
2537 N_("Issue dynamic DNS update"),
2538 N_("net ads dns\n"
2539 " Issue dynamic DNS update")
2542 "password",
2543 net_ads_password,
2544 NET_TRANSPORT_ADS,
2545 N_("Change user passwords"),
2546 N_("net ads password\n"
2547 " Change user passwords")
2550 "changetrustpw",
2551 net_ads_changetrustpw,
2552 NET_TRANSPORT_ADS,
2553 N_("Change trust account password"),
2554 N_("net ads changetrustpw\n"
2555 " Change trust account password")
2558 "printer",
2559 net_ads_printer,
2560 NET_TRANSPORT_ADS,
2561 N_("List/modify printer entries"),
2562 N_("net ads printer\n"
2563 " List/modify printer entries")
2566 "search",
2567 net_ads_search,
2568 NET_TRANSPORT_ADS,
2569 N_("Issue LDAP search using filter"),
2570 N_("net ads search\n"
2571 " Issue LDAP search using filter")
2574 "dn",
2575 net_ads_dn,
2576 NET_TRANSPORT_ADS,
2577 N_("Issue LDAP search by DN"),
2578 N_("net ads dn\n"
2579 " Issue LDAP search by DN")
2582 "sid",
2583 net_ads_sid,
2584 NET_TRANSPORT_ADS,
2585 N_("Issue LDAP search by SID"),
2586 N_("net ads sid\n"
2587 " Issue LDAP search by SID")
2590 "workgroup",
2591 net_ads_workgroup,
2592 NET_TRANSPORT_ADS,
2593 N_("Display workgroup name"),
2594 N_("net ads workgroup\n"
2595 " Display the workgroup name")
2598 "lookup",
2599 net_ads_lookup,
2600 NET_TRANSPORT_ADS,
2601 N_("Perfom CLDAP query on DC"),
2602 N_("net ads lookup\n"
2603 " Find the ADS DC using CLDAP lookups")
2606 "keytab",
2607 net_ads_keytab,
2608 NET_TRANSPORT_ADS,
2609 N_("Manage local keytab file"),
2610 N_("net ads keytab\n"
2611 " Manage local keytab file")
2614 "gpo",
2615 net_ads_gpo,
2616 NET_TRANSPORT_ADS,
2617 N_("Manage group policy objects"),
2618 N_("net ads gpo\n"
2619 " Manage group policy objects")
2622 "kerberos",
2623 net_ads_kerberos,
2624 NET_TRANSPORT_ADS,
2625 N_("Manage kerberos keytab"),
2626 N_("net ads kerberos\n"
2627 " Manage kerberos keytab")
2629 {NULL, NULL, 0, NULL, NULL}
2632 return net_run_function(c, argc, argv, "net ads", func);
2635 #else
2637 static int net_ads_noads(void)
2639 d_fprintf(stderr, _("ADS support not compiled in\n"));
2640 return -1;
2643 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2645 return net_ads_noads();
2648 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2650 return net_ads_noads();
2653 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2655 return net_ads_noads();
2658 int net_ads_join(struct net_context *c, int argc, const char **argv)
2660 return net_ads_noads();
2663 int net_ads_user(struct net_context *c, int argc, const char **argv)
2665 return net_ads_noads();
2668 int net_ads_group(struct net_context *c, int argc, const char **argv)
2670 return net_ads_noads();
2673 /* this one shouldn't display a message */
2674 int net_ads_check(struct net_context *c)
2676 return -1;
2679 int net_ads_check_our_domain(struct net_context *c)
2681 return -1;
2684 int net_ads(struct net_context *c, int argc, const char **argv)
2686 return net_ads_noads();
2689 #endif /* WITH_ADS */