s3-kerberos: let kerberos_return_pac() return a PAC container.
[Samba.git] / source3 / utils / net_ads.c
blob19c28b12f7b8cc0a03e0e374ab32b0abfae24e06
1 /*
2 Samba Unix/Linux SMB client library
3 net ads commands
4 Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
5 Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
6 Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
7 Copyright (C) 2006 Gerald (Jerry) Carter (jerry@samba.org)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "utils/net.h"
25 #include "rpc_client/cli_pipe.h"
26 #include "librpc/gen_ndr/ndr_krb5pac.h"
27 #include "../librpc/gen_ndr/ndr_spoolss.h"
28 #include "nsswitch/libwbclient/wbclient.h"
29 #include "ads.h"
30 #include "libads/cldap.h"
31 #include "../lib/addns/dnsquery.h"
32 #include "../libds/common/flags.h"
33 #include "librpc/gen_ndr/libnet_join.h"
34 #include "libnet/libnet_join.h"
35 #include "smb_krb5.h"
36 #include "secrets.h"
37 #include "krb5_env.h"
38 #include "../libcli/security/security.h"
39 #include "libsmb/libsmb.h"
40 #include "lib/param/loadparm.h"
41 #include "utils/net_dns.h"
43 #ifdef HAVE_ADS
45 /* when we do not have sufficient input parameters to contact a remote domain
46 * we always fall back to our own realm - Guenther*/
48 static const char *assume_own_realm(struct net_context *c)
50 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
51 return lp_realm();
54 return NULL;
58 do a cldap netlogon query
60 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
62 char addr[INET6_ADDRSTRLEN];
63 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
65 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
67 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads->ldap.ss, ads->server.realm, &reply ) ) {
68 d_fprintf(stderr, _("CLDAP query failed!\n"));
69 return -1;
72 d_printf(_("Information for Domain Controller: %s\n\n"),
73 addr);
75 d_printf(_("Response Type: "));
76 switch (reply.command) {
77 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
78 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
79 break;
80 case LOGON_SAM_LOGON_RESPONSE_EX:
81 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
82 break;
83 default:
84 d_printf("0x%x\n", reply.command);
85 break;
88 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
90 d_printf(_("Flags:\n"
91 "\tIs a PDC: %s\n"
92 "\tIs a GC of the forest: %s\n"
93 "\tIs an LDAP server: %s\n"
94 "\tSupports DS: %s\n"
95 "\tIs running a KDC: %s\n"
96 "\tIs running time services: %s\n"
97 "\tIs the closest DC: %s\n"
98 "\tIs writable: %s\n"
99 "\tHas a hardware clock: %s\n"
100 "\tIs a non-domain NC serviced by LDAP server: %s\n"
101 "\tIs NT6 DC that has some secrets: %s\n"
102 "\tIs NT6 DC that has all secrets: %s\n"),
103 (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
104 (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
105 (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
106 (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
107 (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
108 (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
109 (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
110 (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
111 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
112 (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
113 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
114 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"));
117 printf(_("Forest:\t\t\t%s\n"), reply.forest);
118 printf(_("Domain:\t\t\t%s\n"), reply.dns_domain);
119 printf(_("Domain Controller:\t%s\n"), reply.pdc_dns_name);
121 printf(_("Pre-Win2k Domain:\t%s\n"), reply.domain_name);
122 printf(_("Pre-Win2k Hostname:\t%s\n"), reply.pdc_name);
124 if (*reply.user_name) printf(_("User name:\t%s\n"), reply.user_name);
126 printf(_("Server Site Name :\t\t%s\n"), reply.server_site);
127 printf(_("Client Site Name :\t\t%s\n"), reply.client_site);
129 d_printf(_("NT Version: %d\n"), reply.nt_version);
130 d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
131 d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
133 return 0;
137 this implements the CLDAP based netlogon lookup requests
138 for finding the domain controller of a ADS domain
140 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
142 ADS_STRUCT *ads;
143 int ret;
145 if (c->display_usage) {
146 d_printf("%s\n"
147 "net ads lookup\n"
148 " %s",
149 _("Usage:"),
150 _("Find the ADS DC using CLDAP lookup.\n"));
151 return 0;
154 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
155 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
156 ads_destroy(&ads);
157 return -1;
160 if (!ads->config.realm) {
161 ads->config.realm = discard_const_p(char, c->opt_target_workgroup);
162 ads->ldap.port = 389;
165 ret = net_ads_cldap_netlogon(c, ads);
166 ads_destroy(&ads);
167 return ret;
172 static int net_ads_info(struct net_context *c, int argc, const char **argv)
174 ADS_STRUCT *ads;
175 char addr[INET6_ADDRSTRLEN];
177 if (c->display_usage) {
178 d_printf("%s\n"
179 "net ads info\n"
180 " %s",
181 _("Usage:"),
182 _("Display information about an Active Directory "
183 "server.\n"));
184 return 0;
187 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
188 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
189 return -1;
192 if (!ads || !ads->config.realm) {
193 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
194 ads_destroy(&ads);
195 return -1;
198 /* Try to set the server's current time since we didn't do a full
199 TCP LDAP session initially */
201 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
202 d_fprintf( stderr, _("Failed to get server's current time!\n"));
205 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
207 d_printf(_("LDAP server: %s\n"), addr);
208 d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
209 d_printf(_("Realm: %s\n"), ads->config.realm);
210 d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
211 d_printf(_("LDAP port: %d\n"), ads->ldap.port);
212 d_printf(_("Server time: %s\n"),
213 http_timestring(talloc_tos(), ads->config.current_time));
215 d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
216 d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
218 ads_destroy(&ads);
219 return 0;
222 static void use_in_memory_ccache(void) {
223 /* Use in-memory credentials cache so we do not interfere with
224 * existing credentials */
225 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
228 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
229 uint32 auth_flags, ADS_STRUCT **ads_ret)
231 ADS_STRUCT *ads = NULL;
232 ADS_STATUS status;
233 bool need_password = false;
234 bool second_time = false;
235 char *cp;
236 const char *realm = NULL;
237 bool tried_closest_dc = false;
239 /* lp_realm() should be handled by a command line param,
240 However, the join requires that realm be set in smb.conf
241 and compares our realm with the remote server's so this is
242 ok until someone needs more flexibility */
244 *ads_ret = NULL;
246 retry_connect:
247 if (only_own_domain) {
248 realm = lp_realm();
249 } else {
250 realm = assume_own_realm(c);
253 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
255 if (!c->opt_user_name) {
256 c->opt_user_name = "administrator";
259 if (c->opt_user_specified) {
260 need_password = true;
263 retry:
264 if (!c->opt_password && need_password && !c->opt_machine_pass) {
265 c->opt_password = net_prompt_pass(c, c->opt_user_name);
266 if (!c->opt_password) {
267 ads_destroy(&ads);
268 return ADS_ERROR(LDAP_NO_MEMORY);
272 if (c->opt_password) {
273 use_in_memory_ccache();
274 SAFE_FREE(ads->auth.password);
275 ads->auth.password = smb_xstrdup(c->opt_password);
278 ads->auth.flags |= auth_flags;
279 SAFE_FREE(ads->auth.user_name);
280 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
283 * If the username is of the form "name@realm",
284 * extract the realm and convert to upper case.
285 * This is only used to establish the connection.
287 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
288 *cp++ = '\0';
289 SAFE_FREE(ads->auth.realm);
290 ads->auth.realm = smb_xstrdup(cp);
291 if (!strupper_m(ads->auth.realm)) {
292 ads_destroy(&ads);
293 return ADS_ERROR(LDAP_NO_MEMORY);
297 status = ads_connect(ads);
299 if (!ADS_ERR_OK(status)) {
301 if (NT_STATUS_EQUAL(ads_ntstatus(status),
302 NT_STATUS_NO_LOGON_SERVERS)) {
303 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
304 ads_destroy(&ads);
305 return status;
308 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
309 need_password = true;
310 second_time = true;
311 goto retry;
312 } else {
313 ads_destroy(&ads);
314 return status;
318 /* when contacting our own domain, make sure we use the closest DC.
319 * This is done by reconnecting to ADS because only the first call to
320 * ads_connect will give us our own sitename */
322 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
324 tried_closest_dc = true; /* avoid loop */
326 if (!ads_closest_dc(ads)) {
328 namecache_delete(ads->server.realm, 0x1C);
329 namecache_delete(ads->server.workgroup, 0x1C);
331 ads_destroy(&ads);
332 ads = NULL;
334 goto retry_connect;
338 *ads_ret = ads;
339 return status;
342 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
344 return ads_startup_int(c, only_own_domain, 0, ads);
347 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
349 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
353 Check to see if connection can be made via ads.
354 ads_startup() stores the password in opt_password if it needs to so
355 that rpc or rap can use it without re-prompting.
357 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
359 ADS_STRUCT *ads;
360 ADS_STATUS status;
362 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
363 return -1;
366 ads->auth.flags |= ADS_AUTH_NO_BIND;
368 status = ads_connect(ads);
369 if ( !ADS_ERR_OK(status) ) {
370 return -1;
373 ads_destroy(&ads);
374 return 0;
377 int net_ads_check_our_domain(struct net_context *c)
379 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
382 int net_ads_check(struct net_context *c)
384 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
388 determine the netbios workgroup name for a domain
390 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
392 ADS_STRUCT *ads;
393 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
395 if (c->display_usage) {
396 d_printf ("%s\n"
397 "net ads workgroup\n"
398 " %s\n",
399 _("Usage:"),
400 _("Print the workgroup name"));
401 return 0;
404 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
405 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
406 return -1;
409 if (!ads->config.realm) {
410 ads->config.realm = discard_const_p(char, c->opt_target_workgroup);
411 ads->ldap.port = 389;
414 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads->ldap.ss, ads->server.realm, &reply ) ) {
415 d_fprintf(stderr, _("CLDAP query failed!\n"));
416 ads_destroy(&ads);
417 return -1;
420 d_printf(_("Workgroup: %s\n"), reply.domain_name);
422 ads_destroy(&ads);
424 return 0;
429 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
431 char **disp_fields = (char **) data_area;
433 if (!field) { /* must be end of record */
434 if (disp_fields[0]) {
435 if (!strchr_m(disp_fields[0], '$')) {
436 if (disp_fields[1])
437 d_printf("%-21.21s %s\n",
438 disp_fields[0], disp_fields[1]);
439 else
440 d_printf("%s\n", disp_fields[0]);
443 SAFE_FREE(disp_fields[0]);
444 SAFE_FREE(disp_fields[1]);
445 return true;
447 if (!values) /* must be new field, indicate string field */
448 return true;
449 if (strcasecmp_m(field, "sAMAccountName") == 0) {
450 disp_fields[0] = SMB_STRDUP((char *) values[0]);
452 if (strcasecmp_m(field, "description") == 0)
453 disp_fields[1] = SMB_STRDUP((char *) values[0]);
454 return true;
457 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
459 return net_user_usage(c, argc, argv);
462 static int ads_user_add(struct net_context *c, int argc, const char **argv)
464 ADS_STRUCT *ads;
465 ADS_STATUS status;
466 char *upn, *userdn;
467 LDAPMessage *res=NULL;
468 int rc = -1;
469 char *ou_str = NULL;
471 if (argc < 1 || c->display_usage)
472 return net_ads_user_usage(c, argc, argv);
474 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
475 return -1;
478 status = ads_find_user_acct(ads, &res, argv[0]);
480 if (!ADS_ERR_OK(status)) {
481 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
482 goto done;
485 if (ads_count_replies(ads, res)) {
486 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
487 argv[0]);
488 goto done;
491 if (c->opt_container) {
492 ou_str = SMB_STRDUP(c->opt_container);
493 } else {
494 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
497 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
499 if (!ADS_ERR_OK(status)) {
500 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
501 ads_errstr(status));
502 goto done;
505 /* if no password is to be set, we're done */
506 if (argc == 1) {
507 d_printf(_("User %s added\n"), argv[0]);
508 rc = 0;
509 goto done;
512 /* try setting the password */
513 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
514 goto done;
516 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
517 ads->auth.time_offset);
518 SAFE_FREE(upn);
519 if (ADS_ERR_OK(status)) {
520 d_printf(_("User %s added\n"), argv[0]);
521 rc = 0;
522 goto done;
525 /* password didn't set, delete account */
526 d_fprintf(stderr, _("Could not add user %s. "
527 "Error setting password %s\n"),
528 argv[0], ads_errstr(status));
529 ads_msgfree(ads, res);
530 status=ads_find_user_acct(ads, &res, argv[0]);
531 if (ADS_ERR_OK(status)) {
532 userdn = ads_get_dn(ads, talloc_tos(), res);
533 ads_del_dn(ads, userdn);
534 TALLOC_FREE(userdn);
537 done:
538 if (res)
539 ads_msgfree(ads, res);
540 ads_destroy(&ads);
541 SAFE_FREE(ou_str);
542 return rc;
545 static int ads_user_info(struct net_context *c, int argc, const char **argv)
547 ADS_STRUCT *ads = NULL;
548 ADS_STATUS rc;
549 LDAPMessage *res = NULL;
550 TALLOC_CTX *frame;
551 int ret = 0;
552 wbcErr wbc_status;
553 const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
554 char *searchstring=NULL;
555 char **grouplist;
556 char *primary_group;
557 char *escaped_user;
558 struct dom_sid primary_group_sid;
559 uint32_t group_rid;
560 enum wbcSidType type;
562 if (argc < 1 || c->display_usage) {
563 return net_ads_user_usage(c, argc, argv);
566 frame = talloc_new(talloc_tos());
567 if (frame == NULL) {
568 return -1;
571 escaped_user = escape_ldap_string(frame, argv[0]);
572 if (!escaped_user) {
573 d_fprintf(stderr,
574 _("ads_user_info: failed to escape user %s\n"),
575 argv[0]);
576 return -1;
579 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
580 ret = -1;
581 goto error;
584 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
585 ret =-1;
586 goto error;
588 rc = ads_search(ads, &res, searchstring, attrs);
589 SAFE_FREE(searchstring);
591 if (!ADS_ERR_OK(rc)) {
592 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(rc));
593 ret = -1;
594 goto error;
597 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
598 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
599 ret = -1;
600 goto error;
603 rc = ads_domain_sid(ads, &primary_group_sid);
604 if (!ADS_ERR_OK(rc)) {
605 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(rc));
606 ret = -1;
607 goto error;
610 sid_append_rid(&primary_group_sid, group_rid);
612 wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
613 NULL, /* don't look up domain */
614 &primary_group,
615 &type);
616 if (!WBC_ERROR_IS_OK(wbc_status)) {
617 d_fprintf(stderr, "wbcLookupSid: %s\n",
618 wbcErrorString(wbc_status));
619 ret = -1;
620 goto error;
623 d_printf("%s\n", primary_group);
625 wbcFreeMemory(primary_group);
627 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
628 (LDAPMessage *)res, "memberOf");
630 if (grouplist) {
631 int i;
632 char **groupname;
633 for (i=0;grouplist[i];i++) {
634 groupname = ldap_explode_dn(grouplist[i], 1);
635 d_printf("%s\n", groupname[0]);
636 ldap_value_free(groupname);
638 ldap_value_free(grouplist);
641 error:
642 if (res) ads_msgfree(ads, res);
643 if (ads) ads_destroy(&ads);
644 TALLOC_FREE(frame);
645 return ret;
648 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
650 ADS_STRUCT *ads;
651 ADS_STATUS rc;
652 LDAPMessage *res = NULL;
653 char *userdn;
655 if (argc < 1) {
656 return net_ads_user_usage(c, argc, argv);
659 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
660 return -1;
663 rc = ads_find_user_acct(ads, &res, argv[0]);
664 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
665 d_printf(_("User %s does not exist.\n"), argv[0]);
666 ads_msgfree(ads, res);
667 ads_destroy(&ads);
668 return -1;
670 userdn = ads_get_dn(ads, talloc_tos(), res);
671 ads_msgfree(ads, res);
672 rc = ads_del_dn(ads, userdn);
673 TALLOC_FREE(userdn);
674 if (ADS_ERR_OK(rc)) {
675 d_printf(_("User %s deleted\n"), argv[0]);
676 ads_destroy(&ads);
677 return 0;
679 d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
680 ads_errstr(rc));
681 ads_destroy(&ads);
682 return -1;
685 int net_ads_user(struct net_context *c, int argc, const char **argv)
687 struct functable func[] = {
689 "add",
690 ads_user_add,
691 NET_TRANSPORT_ADS,
692 N_("Add an AD user"),
693 N_("net ads user add\n"
694 " Add an AD user")
697 "info",
698 ads_user_info,
699 NET_TRANSPORT_ADS,
700 N_("Display information about an AD user"),
701 N_("net ads user info\n"
702 " Display information about an AD user")
705 "delete",
706 ads_user_delete,
707 NET_TRANSPORT_ADS,
708 N_("Delete an AD user"),
709 N_("net ads user delete\n"
710 " Delete an AD user")
712 {NULL, NULL, 0, NULL, NULL}
714 ADS_STRUCT *ads;
715 ADS_STATUS rc;
716 const char *shortattrs[] = {"sAMAccountName", NULL};
717 const char *longattrs[] = {"sAMAccountName", "description", NULL};
718 char *disp_fields[2] = {NULL, NULL};
720 if (argc == 0) {
721 if (c->display_usage) {
722 d_printf( "%s\n"
723 "net ads user\n"
724 " %s\n",
725 _("Usage:"),
726 _("List AD users"));
727 net_display_usage_from_functable(func);
728 return 0;
731 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
732 return -1;
735 if (c->opt_long_list_entries)
736 d_printf(_("\nUser name Comment"
737 "\n-----------------------------\n"));
739 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
740 LDAP_SCOPE_SUBTREE,
741 "(objectCategory=user)",
742 c->opt_long_list_entries ? longattrs :
743 shortattrs, usergrp_display,
744 disp_fields);
745 ads_destroy(&ads);
746 return ADS_ERR_OK(rc) ? 0 : -1;
749 return net_run_function(c, argc, argv, "net ads user", func);
752 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
754 return net_group_usage(c, argc, argv);
757 static int ads_group_add(struct net_context *c, int argc, const char **argv)
759 ADS_STRUCT *ads;
760 ADS_STATUS status;
761 LDAPMessage *res=NULL;
762 int rc = -1;
763 char *ou_str = NULL;
765 if (argc < 1 || c->display_usage) {
766 return net_ads_group_usage(c, argc, argv);
769 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
770 return -1;
773 status = ads_find_user_acct(ads, &res, argv[0]);
775 if (!ADS_ERR_OK(status)) {
776 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
777 goto done;
780 if (ads_count_replies(ads, res)) {
781 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
782 goto done;
785 if (c->opt_container) {
786 ou_str = SMB_STRDUP(c->opt_container);
787 } else {
788 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
791 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
793 if (ADS_ERR_OK(status)) {
794 d_printf(_("Group %s added\n"), argv[0]);
795 rc = 0;
796 } else {
797 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
798 ads_errstr(status));
801 done:
802 if (res)
803 ads_msgfree(ads, res);
804 ads_destroy(&ads);
805 SAFE_FREE(ou_str);
806 return rc;
809 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
811 ADS_STRUCT *ads;
812 ADS_STATUS rc;
813 LDAPMessage *res = NULL;
814 char *groupdn;
816 if (argc < 1 || c->display_usage) {
817 return net_ads_group_usage(c, argc, argv);
820 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
821 return -1;
824 rc = ads_find_user_acct(ads, &res, argv[0]);
825 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
826 d_printf(_("Group %s does not exist.\n"), argv[0]);
827 ads_msgfree(ads, res);
828 ads_destroy(&ads);
829 return -1;
831 groupdn = ads_get_dn(ads, talloc_tos(), res);
832 ads_msgfree(ads, res);
833 rc = ads_del_dn(ads, groupdn);
834 TALLOC_FREE(groupdn);
835 if (ADS_ERR_OK(rc)) {
836 d_printf(_("Group %s deleted\n"), argv[0]);
837 ads_destroy(&ads);
838 return 0;
840 d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
841 ads_errstr(rc));
842 ads_destroy(&ads);
843 return -1;
846 int net_ads_group(struct net_context *c, int argc, const char **argv)
848 struct functable func[] = {
850 "add",
851 ads_group_add,
852 NET_TRANSPORT_ADS,
853 N_("Add an AD group"),
854 N_("net ads group add\n"
855 " Add an AD group")
858 "delete",
859 ads_group_delete,
860 NET_TRANSPORT_ADS,
861 N_("Delete an AD group"),
862 N_("net ads group delete\n"
863 " Delete an AD group")
865 {NULL, NULL, 0, NULL, NULL}
867 ADS_STRUCT *ads;
868 ADS_STATUS rc;
869 const char *shortattrs[] = {"sAMAccountName", NULL};
870 const char *longattrs[] = {"sAMAccountName", "description", NULL};
871 char *disp_fields[2] = {NULL, NULL};
873 if (argc == 0) {
874 if (c->display_usage) {
875 d_printf( "%s\n"
876 "net ads group\n"
877 " %s\n",
878 _("Usage:"),
879 _("List AD groups"));
880 net_display_usage_from_functable(func);
881 return 0;
884 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
885 return -1;
888 if (c->opt_long_list_entries)
889 d_printf(_("\nGroup name Comment"
890 "\n-----------------------------\n"));
891 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
892 LDAP_SCOPE_SUBTREE,
893 "(objectCategory=group)",
894 c->opt_long_list_entries ? longattrs :
895 shortattrs, usergrp_display,
896 disp_fields);
898 ads_destroy(&ads);
899 return ADS_ERR_OK(rc) ? 0 : -1;
901 return net_run_function(c, argc, argv, "net ads group", func);
904 static int net_ads_status(struct net_context *c, int argc, const char **argv)
906 ADS_STRUCT *ads;
907 ADS_STATUS rc;
908 LDAPMessage *res;
910 if (c->display_usage) {
911 d_printf( "%s\n"
912 "net ads status\n"
913 " %s\n",
914 _("Usage:"),
915 _("Display machine account details"));
916 return 0;
919 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
920 return -1;
923 rc = ads_find_machine_acct(ads, &res, lp_netbios_name());
924 if (!ADS_ERR_OK(rc)) {
925 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
926 ads_destroy(&ads);
927 return -1;
930 if (ads_count_replies(ads, res) == 0) {
931 d_fprintf(stderr, _("No machine account for '%s' found\n"), lp_netbios_name());
932 ads_destroy(&ads);
933 return -1;
936 ads_dump(ads, res);
937 ads_destroy(&ads);
938 return 0;
941 /*******************************************************************
942 Leave an AD domain. Windows XP disables the machine account.
943 We'll try the same. The old code would do an LDAP delete.
944 That only worked using the machine creds because added the machine
945 with full control to the computer object's ACL.
946 *******************************************************************/
948 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
950 TALLOC_CTX *ctx;
951 struct libnet_UnjoinCtx *r = NULL;
952 WERROR werr;
954 if (c->display_usage) {
955 d_printf( "%s\n"
956 "net ads leave\n"
957 " %s\n",
958 _("Usage:"),
959 _("Leave an AD domain"));
960 return 0;
963 if (!*lp_realm()) {
964 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
965 return -1;
968 if (!(ctx = talloc_init("net_ads_leave"))) {
969 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
970 return -1;
973 if (!c->opt_kerberos) {
974 use_in_memory_ccache();
977 if (!c->msg_ctx) {
978 d_fprintf(stderr, _("Could not initialise message context. "
979 "Try running as root\n"));
980 return -1;
983 werr = libnet_init_UnjoinCtx(ctx, &r);
984 if (!W_ERROR_IS_OK(werr)) {
985 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
986 return -1;
989 r->in.debug = true;
990 r->in.use_kerberos = c->opt_kerberos;
991 r->in.dc_name = c->opt_host;
992 r->in.domain_name = lp_realm();
993 r->in.admin_account = c->opt_user_name;
994 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
995 r->in.modify_config = lp_config_backend_is_registry();
997 /* Try to delete it, but if that fails, disable it. The
998 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
999 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1000 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
1001 r->in.delete_machine_account = true;
1002 r->in.msg_ctx = c->msg_ctx;
1004 werr = libnet_Unjoin(ctx, r);
1005 if (!W_ERROR_IS_OK(werr)) {
1006 d_printf(_("Failed to leave domain: %s\n"),
1007 r->out.error_string ? r->out.error_string :
1008 get_friendly_werror_msg(werr));
1009 goto done;
1012 if (r->out.deleted_machine_account) {
1013 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1014 r->in.machine_name, r->out.dns_domain_name);
1015 goto done;
1018 /* We couldn't delete it - see if the disable succeeded. */
1019 if (r->out.disabled_machine_account) {
1020 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1021 r->in.machine_name, r->out.dns_domain_name);
1022 werr = WERR_OK;
1023 goto done;
1026 /* Based on what we requested, we shouldn't get here, but if
1027 we did, it means the secrets were removed, and therefore
1028 we have left the domain */
1029 d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1030 r->in.machine_name, r->out.dns_domain_name);
1032 done:
1033 TALLOC_FREE(r);
1034 TALLOC_FREE(ctx);
1036 if (W_ERROR_IS_OK(werr)) {
1037 return 0;
1040 return -1;
1043 static NTSTATUS net_ads_join_ok(struct net_context *c)
1045 ADS_STRUCT *ads = NULL;
1046 ADS_STATUS status;
1047 fstring dc_name;
1048 struct sockaddr_storage dcip;
1050 if (!secrets_init()) {
1051 DEBUG(1,("Failed to initialise secrets database\n"));
1052 return NT_STATUS_ACCESS_DENIED;
1055 net_use_krb_machine_account(c);
1057 get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1059 status = ads_startup(c, true, &ads);
1060 if (!ADS_ERR_OK(status)) {
1061 return ads_ntstatus(status);
1064 ads_destroy(&ads);
1065 return NT_STATUS_OK;
1069 check that an existing join is OK
1071 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1073 NTSTATUS status;
1074 use_in_memory_ccache();
1076 if (c->display_usage) {
1077 d_printf( "%s\n"
1078 "net ads testjoin\n"
1079 " %s\n",
1080 _("Usage:"),
1081 _("Test if the existing join is ok"));
1082 return 0;
1085 /* Display success or failure */
1086 status = net_ads_join_ok(c);
1087 if (!NT_STATUS_IS_OK(status)) {
1088 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1089 get_friendly_nt_error_msg(status));
1090 return -1;
1093 printf(_("Join is OK\n"));
1094 return 0;
1097 /*******************************************************************
1098 Simple configu checks before beginning the join
1099 ********************************************************************/
1101 static WERROR check_ads_config( void )
1103 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1104 d_printf(_("Host is not configured as a member server.\n"));
1105 return WERR_INVALID_DOMAIN_ROLE;
1108 if (strlen(lp_netbios_name()) > 15) {
1109 d_printf(_("Our netbios name can be at most 15 chars long, "
1110 "\"%s\" is %u chars long\n"), lp_netbios_name(),
1111 (unsigned int)strlen(lp_netbios_name()));
1112 return WERR_INVALID_COMPUTERNAME;
1115 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1116 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1117 "join to succeed.\n"), get_dyn_CONFIGFILE());
1118 return WERR_INVALID_PARAM;
1121 return WERR_OK;
1124 /*******************************************************************
1125 Send a DNS update request
1126 *******************************************************************/
1128 #if defined(WITH_DNS_UPDATES)
1129 #include "../lib/addns/dns.h"
1131 static NTSTATUS net_update_dns_internal(struct net_context *c,
1132 TALLOC_CTX *ctx, ADS_STRUCT *ads,
1133 const char *machine_name,
1134 const struct sockaddr_storage *addrs,
1135 int num_addrs)
1137 struct dns_rr_ns *nameservers = NULL;
1138 int ns_count = 0, i;
1139 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1140 DNS_ERROR dns_err;
1141 fstring dns_server;
1142 const char *dns_hosts_file;
1143 const char *dnsdomain = NULL;
1144 char *root_domain = NULL;
1146 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1147 d_printf(_("No DNS domain configured for %s. "
1148 "Unable to perform DNS Update.\n"), machine_name);
1149 status = NT_STATUS_INVALID_PARAMETER;
1150 goto done;
1152 dnsdomain++;
1154 dns_hosts_file = lp_parm_const_string(-1, "resolv", "host file", NULL);
1155 status = ads_dns_lookup_ns(ctx, dns_hosts_file,
1156 dnsdomain, &nameservers, &ns_count);
1157 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1158 /* Child domains often do not have NS records. Look
1159 for the NS record for the forest root domain
1160 (rootDomainNamingContext in therootDSE) */
1162 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1163 LDAPMessage *msg = NULL;
1164 char *root_dn;
1165 ADS_STATUS ads_status;
1167 if ( !ads->ldap.ld ) {
1168 ads_status = ads_connect( ads );
1169 if ( !ADS_ERR_OK(ads_status) ) {
1170 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1171 goto done;
1175 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1176 "(objectclass=*)", rootname_attrs, &msg);
1177 if (!ADS_ERR_OK(ads_status)) {
1178 goto done;
1181 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1182 if ( !root_dn ) {
1183 ads_msgfree( ads, msg );
1184 goto done;
1187 root_domain = ads_build_domain( root_dn );
1189 /* cleanup */
1190 ads_msgfree( ads, msg );
1192 /* try again for NS servers */
1194 status = ads_dns_lookup_ns(ctx, dns_hosts_file, root_domain,
1195 &nameservers, &ns_count);
1197 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1198 DEBUG(3,("net_update_dns_internal: Failed to find name server for the %s "
1199 "realm\n", ads->config.realm));
1200 goto done;
1203 dnsdomain = root_domain;
1207 for (i=0; i < ns_count; i++) {
1209 uint32_t flags = DNS_UPDATE_SIGNED |
1210 DNS_UPDATE_UNSIGNED |
1211 DNS_UPDATE_UNSIGNED_SUFFICIENT |
1212 DNS_UPDATE_PROBE |
1213 DNS_UPDATE_PROBE_SUFFICIENT;
1215 if (c->opt_force) {
1216 flags &= ~DNS_UPDATE_PROBE_SUFFICIENT;
1217 flags &= ~DNS_UPDATE_UNSIGNED_SUFFICIENT;
1220 status = NT_STATUS_UNSUCCESSFUL;
1222 /* Now perform the dns update - we'll try non-secure and if we fail,
1223 we'll follow it up with a secure update */
1225 fstrcpy( dns_server, nameservers[i].hostname );
1227 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs, flags);
1228 if (ERR_DNS_IS_OK(dns_err)) {
1229 status = NT_STATUS_OK;
1230 goto done;
1233 if (ERR_DNS_EQUAL(dns_err, ERROR_DNS_INVALID_NAME_SERVER) ||
1234 ERR_DNS_EQUAL(dns_err, ERROR_DNS_CONNECTION_FAILED) ||
1235 ERR_DNS_EQUAL(dns_err, ERROR_DNS_SOCKET_ERROR)) {
1236 DEBUG(1,("retrying DNS update with next nameserver after receiving %s\n",
1237 dns_errstr(dns_err)));
1238 continue;
1241 d_printf(_("DNS Update for %s failed: %s\n"),
1242 machine_name, dns_errstr(dns_err));
1243 status = NT_STATUS_UNSUCCESSFUL;
1244 goto done;
1247 done:
1249 SAFE_FREE( root_domain );
1251 return status;
1254 static NTSTATUS net_update_dns_ext(struct net_context *c,
1255 TALLOC_CTX *mem_ctx, ADS_STRUCT *ads,
1256 const char *hostname,
1257 struct sockaddr_storage *iplist,
1258 int num_addrs)
1260 struct sockaddr_storage *iplist_alloc = NULL;
1261 fstring machine_name;
1262 NTSTATUS status;
1264 if (hostname) {
1265 fstrcpy(machine_name, hostname);
1266 } else {
1267 name_to_fqdn( machine_name, lp_netbios_name() );
1269 if (!strlower_m( machine_name )) {
1270 return NT_STATUS_INVALID_PARAMETER;
1273 if (num_addrs == 0 || iplist == NULL) {
1275 * Get our ip address
1276 * (not the 127.0.0.x address but a real ip address)
1278 num_addrs = get_my_ip_address(&iplist_alloc);
1279 if ( num_addrs <= 0 ) {
1280 DEBUG(4, ("net_update_dns_ext: Failed to find my "
1281 "non-loopback IP addresses!\n"));
1282 return NT_STATUS_INVALID_PARAMETER;
1284 iplist = iplist_alloc;
1287 status = net_update_dns_internal(c, mem_ctx, ads, machine_name,
1288 iplist, num_addrs);
1290 SAFE_FREE(iplist_alloc);
1291 return status;
1294 static NTSTATUS net_update_dns(struct net_context *c, TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, const char *hostname)
1296 NTSTATUS status;
1298 status = net_update_dns_ext(c, mem_ctx, ads, hostname, NULL, 0);
1299 return status;
1301 #endif
1304 /*******************************************************************
1305 ********************************************************************/
1307 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1309 d_printf(_("net ads join [options]\n"
1310 "Valid options:\n"));
1311 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1312 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1313 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1314 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1315 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1316 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1317 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1318 d_printf(_(" machinepass=PASS Set the machine password to a specific value during the join.\n"
1319 " The deault password is random.\n"));
1320 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1321 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1322 " NB: osName and osVer must be specified together for either to take effect.\n"
1323 " Also, the operatingSystemService attribute is also set when along with\n"
1324 " the two other attributes.\n"));
1326 return -1;
1330 static void _net_ads_join_dns_updates(struct net_context *c, TALLOC_CTX *ctx, struct libnet_JoinCtx *r)
1332 #if defined(WITH_DNS_UPDATES)
1333 ADS_STRUCT *ads_dns = NULL;
1334 int ret;
1335 NTSTATUS status;
1338 * In a clustered environment, don't do dynamic dns updates:
1339 * Registering the set of ip addresses that are assigned to
1340 * the interfaces of the node that performs the join does usually
1341 * not have the desired effect, since the local interfaces do not
1342 * carry the complete set of the cluster's public IP addresses.
1343 * And it can also contain internal addresses that should not
1344 * be visible to the outside at all.
1345 * In order to do dns updates in a clustererd setup, use
1346 * net ads dns register.
1348 if (lp_clustering()) {
1349 d_fprintf(stderr, _("Not doing automatic DNS update in a "
1350 "clustered setup.\n"));
1351 return;
1354 if (!r->out.domain_is_ad) {
1355 return;
1359 * We enter this block with user creds.
1360 * kinit with the machine password to do dns update.
1363 ads_dns = ads_init(lp_realm(), NULL, r->in.dc_name);
1365 if (ads_dns == NULL) {
1366 d_fprintf(stderr, _("DNS update failed: out of memory!\n"));
1367 goto done;
1370 use_in_memory_ccache();
1372 ret = asprintf(&ads_dns->auth.user_name, "%s$", lp_netbios_name());
1373 if (ret == -1) {
1374 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1375 goto done;
1378 ads_dns->auth.password = secrets_fetch_machine_password(
1379 r->out.netbios_domain_name, NULL, NULL);
1380 if (ads_dns->auth.password == NULL) {
1381 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1382 goto done;
1385 ads_dns->auth.realm = SMB_STRDUP(r->out.dns_domain_name);
1386 if (ads_dns->auth.realm == NULL) {
1387 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1388 goto done;
1391 if (!strupper_m(ads_dns->auth.realm)) {
1392 d_fprintf(stderr, _("strupper_m %s failed\n"), ads_dns->auth.realm);
1393 goto done;
1396 ret = ads_kinit_password(ads_dns);
1397 if (ret != 0) {
1398 d_fprintf(stderr,
1399 _("DNS update failed: kinit failed: %s\n"),
1400 error_message(ret));
1401 goto done;
1404 status = net_update_dns(c, ctx, ads_dns, NULL);
1405 if (!NT_STATUS_IS_OK(status)) {
1406 d_fprintf( stderr, _("DNS update failed: %s\n"),
1407 nt_errstr(status));
1410 done:
1411 ads_destroy(&ads_dns);
1412 #endif
1414 return;
1418 int net_ads_join(struct net_context *c, int argc, const char **argv)
1420 TALLOC_CTX *ctx = NULL;
1421 struct libnet_JoinCtx *r = NULL;
1422 const char *domain = lp_realm();
1423 WERROR werr = WERR_SETUP_NOT_JOINED;
1424 bool createupn = false;
1425 const char *machineupn = NULL;
1426 const char *machine_password = NULL;
1427 const char *create_in_ou = NULL;
1428 int i;
1429 const char *os_name = NULL;
1430 const char *os_version = NULL;
1431 bool modify_config = lp_config_backend_is_registry();
1433 if (c->display_usage)
1434 return net_ads_join_usage(c, argc, argv);
1436 if (!modify_config) {
1438 werr = check_ads_config();
1439 if (!W_ERROR_IS_OK(werr)) {
1440 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1441 goto fail;
1445 if (!(ctx = talloc_init("net_ads_join"))) {
1446 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1447 werr = WERR_NOMEM;
1448 goto fail;
1451 if (!c->opt_kerberos) {
1452 use_in_memory_ccache();
1455 werr = libnet_init_JoinCtx(ctx, &r);
1456 if (!W_ERROR_IS_OK(werr)) {
1457 goto fail;
1460 /* process additional command line args */
1462 for ( i=0; i<argc; i++ ) {
1463 if ( !strncasecmp_m(argv[i], "createupn", strlen("createupn")) ) {
1464 createupn = true;
1465 machineupn = get_string_param(argv[i]);
1467 else if ( !strncasecmp_m(argv[i], "createcomputer", strlen("createcomputer")) ) {
1468 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1469 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1470 werr = WERR_INVALID_PARAM;
1471 goto fail;
1474 else if ( !strncasecmp_m(argv[i], "osName", strlen("osName")) ) {
1475 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1476 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1477 werr = WERR_INVALID_PARAM;
1478 goto fail;
1481 else if ( !strncasecmp_m(argv[i], "osVer", strlen("osVer")) ) {
1482 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1483 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1484 werr = WERR_INVALID_PARAM;
1485 goto fail;
1488 else if ( !strncasecmp_m(argv[i], "machinepass", strlen("machinepass")) ) {
1489 if ( (machine_password = get_string_param(argv[i])) == NULL ) {
1490 d_fprintf(stderr, _("Please supply a valid password to set as trust account password.\n"));
1491 werr = WERR_INVALID_PARAM;
1492 goto fail;
1495 else {
1496 domain = argv[i];
1500 if (!*domain) {
1501 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1502 werr = WERR_INVALID_PARAM;
1503 goto fail;
1506 if (!c->msg_ctx) {
1507 d_fprintf(stderr, _("Could not initialise message context. "
1508 "Try running as root\n"));
1509 werr = WERR_ACCESS_DENIED;
1510 goto fail;
1513 /* Do the domain join here */
1515 r->in.domain_name = domain;
1516 r->in.create_upn = createupn;
1517 r->in.upn = machineupn;
1518 r->in.account_ou = create_in_ou;
1519 r->in.os_name = os_name;
1520 r->in.os_version = os_version;
1521 r->in.dc_name = c->opt_host;
1522 r->in.admin_account = c->opt_user_name;
1523 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1524 r->in.machine_password = machine_password;
1525 r->in.debug = true;
1526 r->in.use_kerberos = c->opt_kerberos;
1527 r->in.modify_config = modify_config;
1528 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1529 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1530 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1531 r->in.msg_ctx = c->msg_ctx;
1533 werr = libnet_Join(ctx, r);
1534 if (W_ERROR_EQUAL(werr, WERR_DCNOTFOUND) &&
1535 strequal(domain, lp_realm())) {
1536 r->in.domain_name = lp_workgroup();
1537 werr = libnet_Join(ctx, r);
1539 if (!W_ERROR_IS_OK(werr)) {
1540 goto fail;
1543 /* Check the short name of the domain */
1545 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1546 d_printf(_("The workgroup in %s does not match the short\n"
1547 "domain name obtained from the server.\n"
1548 "Using the name [%s] from the server.\n"
1549 "You should set \"workgroup = %s\" in %s.\n"),
1550 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1551 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1554 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1556 if (r->out.dns_domain_name) {
1557 d_printf(_("Joined '%s' to dns domain '%s'\n"), r->in.machine_name,
1558 r->out.dns_domain_name);
1559 } else {
1560 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1561 r->out.netbios_domain_name);
1565 * We try doing the dns update (if it was compiled in).
1566 * If the dns update fails, we still consider the join
1567 * operation as succeeded if we came this far.
1569 _net_ads_join_dns_updates(c, ctx, r);
1571 TALLOC_FREE(r);
1572 TALLOC_FREE( ctx );
1574 return 0;
1576 fail:
1577 /* issue an overall failure message at the end. */
1578 d_printf(_("Failed to join domain: %s\n"),
1579 r && r->out.error_string ? r->out.error_string :
1580 get_friendly_werror_msg(werr));
1581 TALLOC_FREE( ctx );
1583 return -1;
1586 /*******************************************************************
1587 ********************************************************************/
1589 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1591 #if defined(WITH_DNS_UPDATES)
1592 ADS_STRUCT *ads;
1593 ADS_STATUS status;
1594 NTSTATUS ntstatus;
1595 TALLOC_CTX *ctx;
1596 const char *hostname = NULL;
1597 const char **addrs_list = NULL;
1598 struct sockaddr_storage *addrs = NULL;
1599 int num_addrs = 0;
1600 int count;
1602 #ifdef DEVELOPER
1603 talloc_enable_leak_report();
1604 #endif
1606 if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
1607 d_fprintf(stderr, _("Refusing DNS updates with automatic "
1608 "detection of addresses in a clustered "
1609 "setup.\n"));
1610 c->display_usage = true;
1613 if (c->display_usage) {
1614 d_printf( "%s\n"
1615 "net ads dns register [hostname [IP [IP...]]]\n"
1616 " %s\n",
1617 _("Usage:"),
1618 _("Register hostname with DNS\n"));
1619 return -1;
1622 if (!(ctx = talloc_init("net_ads_dns"))) {
1623 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1624 return -1;
1627 if (argc >= 1) {
1628 hostname = argv[0];
1631 if (argc > 1) {
1632 num_addrs = argc - 1;
1633 addrs_list = &argv[1];
1634 } else if (lp_clustering()) {
1635 addrs_list = lp_cluster_addresses();
1636 num_addrs = str_list_length(addrs_list);
1639 if (num_addrs > 0) {
1640 addrs = talloc_zero_array(ctx, struct sockaddr_storage, num_addrs);
1641 if (addrs == NULL) {
1642 d_fprintf(stderr, _("Error allocating memory!\n"));
1643 talloc_free(ctx);
1644 return -1;
1648 for (count = 0; count < num_addrs; count++) {
1649 if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
1650 d_fprintf(stderr, "%s '%s'.\n",
1651 _("Cannot interpret address"),
1652 addrs_list[count]);
1653 talloc_free(ctx);
1654 return -1;
1658 status = ads_startup(c, true, &ads);
1659 if ( !ADS_ERR_OK(status) ) {
1660 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1661 TALLOC_FREE(ctx);
1662 return -1;
1665 ntstatus = net_update_dns_ext(c, ctx, ads, hostname, addrs, num_addrs);
1666 if (!NT_STATUS_IS_OK(ntstatus)) {
1667 d_fprintf( stderr, _("DNS update failed!\n") );
1668 ads_destroy( &ads );
1669 TALLOC_FREE( ctx );
1670 return -1;
1673 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1675 ads_destroy(&ads);
1676 TALLOC_FREE( ctx );
1678 return 0;
1679 #else
1680 d_fprintf(stderr,
1681 _("DNS update support not enabled at compile time!\n"));
1682 return -1;
1683 #endif
1686 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1688 #if defined(WITH_DNS_UPDATES)
1689 DNS_ERROR err;
1691 #ifdef DEVELOPER
1692 talloc_enable_leak_report();
1693 #endif
1695 if (argc != 2 || c->display_usage) {
1696 d_printf( "%s\n"
1697 " %s\n"
1698 " %s\n",
1699 _("Usage:"),
1700 _("net ads dns gethostbyname <server> <name>\n"),
1701 _(" Look up hostname from the AD\n"
1702 " server\tName server to use\n"
1703 " name\tName to look up\n"));
1704 return -1;
1707 err = do_gethostbyname(argv[0], argv[1]);
1709 d_printf(_("do_gethostbyname returned %s (%d)\n"),
1710 dns_errstr(err), ERROR_DNS_V(err));
1711 #endif
1712 return 0;
1715 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1717 struct functable func[] = {
1719 "register",
1720 net_ads_dns_register,
1721 NET_TRANSPORT_ADS,
1722 N_("Add host dns entry to AD"),
1723 N_("net ads dns register\n"
1724 " Add host dns entry to AD")
1727 "gethostbyname",
1728 net_ads_dns_gethostbyname,
1729 NET_TRANSPORT_ADS,
1730 N_("Look up host"),
1731 N_("net ads dns gethostbyname\n"
1732 " Look up host")
1734 {NULL, NULL, 0, NULL, NULL}
1737 return net_run_function(c, argc, argv, "net ads dns", func);
1740 /*******************************************************************
1741 ********************************************************************/
1743 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1745 d_printf(_(
1746 "\nnet ads printer search <printer>"
1747 "\n\tsearch for a printer in the directory\n"
1748 "\nnet ads printer info <printer> <server>"
1749 "\n\tlookup info in directory for printer on server"
1750 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1751 "\nnet ads printer publish <printername>"
1752 "\n\tpublish printer in directory"
1753 "\n\t(note: printer name is required)\n"
1754 "\nnet ads printer remove <printername>"
1755 "\n\tremove printer from directory"
1756 "\n\t(note: printer name is required)\n"));
1757 return -1;
1760 /*******************************************************************
1761 ********************************************************************/
1763 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1765 ADS_STRUCT *ads;
1766 ADS_STATUS rc;
1767 LDAPMessage *res = NULL;
1769 if (c->display_usage) {
1770 d_printf( "%s\n"
1771 "net ads printer search\n"
1772 " %s\n",
1773 _("Usage:"),
1774 _("List printers in the AD"));
1775 return 0;
1778 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1779 return -1;
1782 rc = ads_find_printers(ads, &res);
1784 if (!ADS_ERR_OK(rc)) {
1785 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
1786 ads_msgfree(ads, res);
1787 ads_destroy(&ads);
1788 return -1;
1791 if (ads_count_replies(ads, res) == 0) {
1792 d_fprintf(stderr, _("No results found\n"));
1793 ads_msgfree(ads, res);
1794 ads_destroy(&ads);
1795 return -1;
1798 ads_dump(ads, res);
1799 ads_msgfree(ads, res);
1800 ads_destroy(&ads);
1801 return 0;
1804 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1806 ADS_STRUCT *ads;
1807 ADS_STATUS rc;
1808 const char *servername, *printername;
1809 LDAPMessage *res = NULL;
1811 if (c->display_usage) {
1812 d_printf("%s\n%s",
1813 _("Usage:"),
1814 _("net ads printer info [printername [servername]]\n"
1815 " Display printer info from AD\n"
1816 " printername\tPrinter name or wildcard\n"
1817 " servername\tName of the print server\n"));
1818 return 0;
1821 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1822 return -1;
1825 if (argc > 0) {
1826 printername = argv[0];
1827 } else {
1828 printername = "*";
1831 if (argc > 1) {
1832 servername = argv[1];
1833 } else {
1834 servername = lp_netbios_name();
1837 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1839 if (!ADS_ERR_OK(rc)) {
1840 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
1841 servername, ads_errstr(rc));
1842 ads_msgfree(ads, res);
1843 ads_destroy(&ads);
1844 return -1;
1847 if (ads_count_replies(ads, res) == 0) {
1848 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
1849 ads_msgfree(ads, res);
1850 ads_destroy(&ads);
1851 return -1;
1854 ads_dump(ads, res);
1855 ads_msgfree(ads, res);
1856 ads_destroy(&ads);
1858 return 0;
1861 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1863 ADS_STRUCT *ads;
1864 ADS_STATUS rc;
1865 const char *servername, *printername;
1866 struct cli_state *cli = NULL;
1867 struct rpc_pipe_client *pipe_hnd = NULL;
1868 struct sockaddr_storage server_ss;
1869 NTSTATUS nt_status;
1870 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1871 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1872 char *prt_dn, *srv_dn, **srv_cn;
1873 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1874 LDAPMessage *res = NULL;
1876 if (argc < 1 || c->display_usage) {
1877 d_printf("%s\n%s",
1878 _("Usage:"),
1879 _("net ads printer publish <printername> [servername]\n"
1880 " Publish printer in AD\n"
1881 " printername\tName of the printer\n"
1882 " servername\tName of the print server\n"));
1883 talloc_destroy(mem_ctx);
1884 return -1;
1887 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1888 talloc_destroy(mem_ctx);
1889 return -1;
1892 printername = argv[0];
1894 if (argc == 2) {
1895 servername = argv[1];
1896 } else {
1897 servername = lp_netbios_name();
1900 /* Get printer data from SPOOLSS */
1902 resolve_name(servername, &server_ss, 0x20, false);
1904 nt_status = cli_full_connection(&cli, lp_netbios_name(), servername,
1905 &server_ss, 0,
1906 "IPC$", "IPC",
1907 c->opt_user_name, c->opt_workgroup,
1908 c->opt_password ? c->opt_password : "",
1909 CLI_FULL_CONNECTION_USE_KERBEROS,
1910 SMB_SIGNING_DEFAULT);
1912 if (NT_STATUS_IS_ERR(nt_status)) {
1913 d_fprintf(stderr, _("Unable to open a connection to %s to "
1914 "obtain data for %s\n"),
1915 servername, printername);
1916 ads_destroy(&ads);
1917 talloc_destroy(mem_ctx);
1918 return -1;
1921 /* Publish on AD server */
1923 ads_find_machine_acct(ads, &res, servername);
1925 if (ads_count_replies(ads, res) == 0) {
1926 d_fprintf(stderr, _("Could not find machine account for server "
1927 "%s\n"),
1928 servername);
1929 ads_destroy(&ads);
1930 talloc_destroy(mem_ctx);
1931 return -1;
1934 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1935 srv_cn = ldap_explode_dn(srv_dn, 1);
1937 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1938 printername_escaped = escape_rdn_val_string_alloc(printername);
1939 if (!srv_cn_escaped || !printername_escaped) {
1940 SAFE_FREE(srv_cn_escaped);
1941 SAFE_FREE(printername_escaped);
1942 d_fprintf(stderr, _("Internal error, out of memory!"));
1943 ads_destroy(&ads);
1944 talloc_destroy(mem_ctx);
1945 return -1;
1948 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1949 SAFE_FREE(srv_cn_escaped);
1950 SAFE_FREE(printername_escaped);
1951 d_fprintf(stderr, _("Internal error, out of memory!"));
1952 ads_destroy(&ads);
1953 talloc_destroy(mem_ctx);
1954 return -1;
1957 SAFE_FREE(srv_cn_escaped);
1958 SAFE_FREE(printername_escaped);
1960 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss, &pipe_hnd);
1961 if (!NT_STATUS_IS_OK(nt_status)) {
1962 d_fprintf(stderr, _("Unable to open a connection to the spoolss pipe on %s\n"),
1963 servername);
1964 SAFE_FREE(prt_dn);
1965 ads_destroy(&ads);
1966 talloc_destroy(mem_ctx);
1967 return -1;
1970 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1971 printername))) {
1972 SAFE_FREE(prt_dn);
1973 ads_destroy(&ads);
1974 talloc_destroy(mem_ctx);
1975 return -1;
1978 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1979 if (!ADS_ERR_OK(rc)) {
1980 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1981 SAFE_FREE(prt_dn);
1982 ads_destroy(&ads);
1983 talloc_destroy(mem_ctx);
1984 return -1;
1987 d_printf("published printer\n");
1988 SAFE_FREE(prt_dn);
1989 ads_destroy(&ads);
1990 talloc_destroy(mem_ctx);
1992 return 0;
1995 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1997 ADS_STRUCT *ads;
1998 ADS_STATUS rc;
1999 const char *servername;
2000 char *prt_dn;
2001 LDAPMessage *res = NULL;
2003 if (argc < 1 || c->display_usage) {
2004 d_printf("%s\n%s",
2005 _("Usage:"),
2006 _("net ads printer remove <printername> [servername]\n"
2007 " Remove a printer from the AD\n"
2008 " printername\tName of the printer\n"
2009 " servername\tName of the print server\n"));
2010 return -1;
2013 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2014 return -1;
2017 if (argc > 1) {
2018 servername = argv[1];
2019 } else {
2020 servername = lp_netbios_name();
2023 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
2025 if (!ADS_ERR_OK(rc)) {
2026 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
2027 ads_msgfree(ads, res);
2028 ads_destroy(&ads);
2029 return -1;
2032 if (ads_count_replies(ads, res) == 0) {
2033 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
2034 ads_msgfree(ads, res);
2035 ads_destroy(&ads);
2036 return -1;
2039 prt_dn = ads_get_dn(ads, talloc_tos(), res);
2040 ads_msgfree(ads, res);
2041 rc = ads_del_dn(ads, prt_dn);
2042 TALLOC_FREE(prt_dn);
2044 if (!ADS_ERR_OK(rc)) {
2045 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
2046 ads_destroy(&ads);
2047 return -1;
2050 ads_destroy(&ads);
2051 return 0;
2054 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
2056 struct functable func[] = {
2058 "search",
2059 net_ads_printer_search,
2060 NET_TRANSPORT_ADS,
2061 N_("Search for a printer"),
2062 N_("net ads printer search\n"
2063 " Search for a printer")
2066 "info",
2067 net_ads_printer_info,
2068 NET_TRANSPORT_ADS,
2069 N_("Display printer information"),
2070 N_("net ads printer info\n"
2071 " Display printer information")
2074 "publish",
2075 net_ads_printer_publish,
2076 NET_TRANSPORT_ADS,
2077 N_("Publish a printer"),
2078 N_("net ads printer publish\n"
2079 " Publish a printer")
2082 "remove",
2083 net_ads_printer_remove,
2084 NET_TRANSPORT_ADS,
2085 N_("Delete a printer"),
2086 N_("net ads printer remove\n"
2087 " Delete a printer")
2089 {NULL, NULL, 0, NULL, NULL}
2092 return net_run_function(c, argc, argv, "net ads printer", func);
2096 static int net_ads_password(struct net_context *c, int argc, const char **argv)
2098 ADS_STRUCT *ads;
2099 const char *auth_principal = c->opt_user_name;
2100 const char *auth_password = c->opt_password;
2101 const char *realm = NULL;
2102 const char *new_password = NULL;
2103 char *chr, *prompt;
2104 const char *user;
2105 char pwd[256] = {0};
2106 ADS_STATUS ret;
2108 if (c->display_usage) {
2109 d_printf("%s\n%s",
2110 _("Usage:"),
2111 _("net ads password <username>\n"
2112 " Change password for user\n"
2113 " username\tName of user to change password for\n"));
2114 return 0;
2117 if (c->opt_user_name == NULL || c->opt_password == NULL) {
2118 d_fprintf(stderr, _("You must supply an administrator "
2119 "username/password\n"));
2120 return -1;
2123 if (argc < 1) {
2124 d_fprintf(stderr, _("ERROR: You must say which username to "
2125 "change password for\n"));
2126 return -1;
2129 user = argv[0];
2130 if (!strchr_m(user, '@')) {
2131 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
2132 return -1;
2134 user = chr;
2137 use_in_memory_ccache();
2138 chr = strchr_m(auth_principal, '@');
2139 if (chr) {
2140 realm = ++chr;
2141 } else {
2142 realm = lp_realm();
2145 /* use the realm so we can eventually change passwords for users
2146 in realms other than default */
2147 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
2148 return -1;
2151 /* we don't actually need a full connect, but it's the easy way to
2152 fill in the KDC's addresss */
2153 ads_connect(ads);
2155 if (!ads->config.realm) {
2156 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
2157 ads_destroy(&ads);
2158 return -1;
2161 if (argv[1]) {
2162 new_password = (const char *)argv[1];
2163 } else {
2164 int rc;
2166 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
2167 return -1;
2169 rc = samba_getpass(prompt, pwd, sizeof(pwd), false, true);
2170 if (rc < 0) {
2171 return -1;
2173 new_password = pwd;
2174 free(prompt);
2177 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2178 auth_password, user, new_password, ads->auth.time_offset);
2179 memset(pwd, '\0', sizeof(pwd));
2180 if (!ADS_ERR_OK(ret)) {
2181 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2182 ads_destroy(&ads);
2183 return -1;
2186 d_printf(_("Password change for %s completed.\n"), user);
2187 ads_destroy(&ads);
2189 return 0;
2192 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2194 ADS_STRUCT *ads;
2195 char *host_principal;
2196 fstring my_name;
2197 ADS_STATUS ret;
2199 if (c->display_usage) {
2200 d_printf( "%s\n"
2201 "net ads changetrustpw\n"
2202 " %s\n",
2203 _("Usage:"),
2204 _("Change the machine account's trust password"));
2205 return 0;
2208 if (!secrets_init()) {
2209 DEBUG(1,("Failed to initialise secrets database\n"));
2210 return -1;
2213 net_use_krb_machine_account(c);
2215 use_in_memory_ccache();
2217 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2218 return -1;
2221 fstrcpy(my_name, lp_netbios_name());
2222 if (!strlower_m(my_name)) {
2223 ads_destroy(&ads);
2224 return -1;
2227 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2228 ads_destroy(&ads);
2229 return -1;
2231 d_printf(_("Changing password for principal: %s\n"), host_principal);
2233 ret = ads_change_trust_account_password(ads, host_principal);
2235 if (!ADS_ERR_OK(ret)) {
2236 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2237 ads_destroy(&ads);
2238 SAFE_FREE(host_principal);
2239 return -1;
2242 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2244 if (USE_SYSTEM_KEYTAB) {
2245 d_printf(_("Attempting to update system keytab with new password.\n"));
2246 if (ads_keytab_create_default(ads)) {
2247 d_printf(_("Failed to update system keytab.\n"));
2251 ads_destroy(&ads);
2252 SAFE_FREE(host_principal);
2254 return 0;
2258 help for net ads search
2260 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2262 d_printf(_(
2263 "\nnet ads search <expression> <attributes...>\n"
2264 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2265 "The expression is a standard LDAP search expression, and the\n"
2266 "attributes are a list of LDAP fields to show in the results.\n\n"
2267 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2269 net_common_flags_usage(c, argc, argv);
2270 return -1;
2275 general ADS search function. Useful in diagnosing problems in ADS
2277 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2279 ADS_STRUCT *ads;
2280 ADS_STATUS rc;
2281 const char *ldap_exp;
2282 const char **attrs;
2283 LDAPMessage *res = NULL;
2285 if (argc < 1 || c->display_usage) {
2286 return net_ads_search_usage(c, argc, argv);
2289 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2290 return -1;
2293 ldap_exp = argv[0];
2294 attrs = (argv + 1);
2296 rc = ads_do_search_retry(ads, ads->config.bind_path,
2297 LDAP_SCOPE_SUBTREE,
2298 ldap_exp, attrs, &res);
2299 if (!ADS_ERR_OK(rc)) {
2300 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2301 ads_destroy(&ads);
2302 return -1;
2305 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2307 /* dump the results */
2308 ads_dump(ads, res);
2310 ads_msgfree(ads, res);
2311 ads_destroy(&ads);
2313 return 0;
2318 help for net ads search
2320 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2322 d_printf(_(
2323 "\nnet ads dn <dn> <attributes...>\n"
2324 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2325 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2326 "to show in the results\n\n"
2327 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2328 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2330 net_common_flags_usage(c, argc, argv);
2331 return -1;
2336 general ADS search function. Useful in diagnosing problems in ADS
2338 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2340 ADS_STRUCT *ads;
2341 ADS_STATUS rc;
2342 const char *dn;
2343 const char **attrs;
2344 LDAPMessage *res = NULL;
2346 if (argc < 1 || c->display_usage) {
2347 return net_ads_dn_usage(c, argc, argv);
2350 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2351 return -1;
2354 dn = argv[0];
2355 attrs = (argv + 1);
2357 rc = ads_do_search_all(ads, dn,
2358 LDAP_SCOPE_BASE,
2359 "(objectclass=*)", attrs, &res);
2360 if (!ADS_ERR_OK(rc)) {
2361 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2362 ads_destroy(&ads);
2363 return -1;
2366 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2368 /* dump the results */
2369 ads_dump(ads, res);
2371 ads_msgfree(ads, res);
2372 ads_destroy(&ads);
2374 return 0;
2378 help for net ads sid search
2380 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2382 d_printf(_(
2383 "\nnet ads sid <sid> <attributes...>\n"
2384 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2385 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2386 "to show in the results\n\n"
2387 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2389 net_common_flags_usage(c, argc, argv);
2390 return -1;
2395 general ADS search function. Useful in diagnosing problems in ADS
2397 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2399 ADS_STRUCT *ads;
2400 ADS_STATUS rc;
2401 const char *sid_string;
2402 const char **attrs;
2403 LDAPMessage *res = NULL;
2404 struct dom_sid sid;
2406 if (argc < 1 || c->display_usage) {
2407 return net_ads_sid_usage(c, argc, argv);
2410 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2411 return -1;
2414 sid_string = argv[0];
2415 attrs = (argv + 1);
2417 if (!string_to_sid(&sid, sid_string)) {
2418 d_fprintf(stderr, _("could not convert sid\n"));
2419 ads_destroy(&ads);
2420 return -1;
2423 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2424 if (!ADS_ERR_OK(rc)) {
2425 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2426 ads_destroy(&ads);
2427 return -1;
2430 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2432 /* dump the results */
2433 ads_dump(ads, res);
2435 ads_msgfree(ads, res);
2436 ads_destroy(&ads);
2438 return 0;
2441 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2443 int ret;
2444 ADS_STRUCT *ads;
2446 if (c->display_usage) {
2447 d_printf( "%s\n"
2448 "net ads keytab flush\n"
2449 " %s\n",
2450 _("Usage:"),
2451 _("Delete the whole keytab"));
2452 return 0;
2455 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2456 return -1;
2458 ret = ads_keytab_flush(ads);
2459 ads_destroy(&ads);
2460 return ret;
2463 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2465 int i;
2466 int ret = 0;
2467 ADS_STRUCT *ads;
2469 if (c->display_usage) {
2470 d_printf("%s\n%s",
2471 _("Usage:"),
2472 _("net ads keytab add <principal> [principal ...]\n"
2473 " Add principals to local keytab\n"
2474 " principal\tKerberos principal to add to "
2475 "keytab\n"));
2476 return 0;
2479 d_printf(_("Processing principals to add...\n"));
2480 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2481 return -1;
2483 for (i = 0; i < argc; i++) {
2484 ret |= ads_keytab_add_entry(ads, argv[i]);
2486 ads_destroy(&ads);
2487 return ret;
2490 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2492 ADS_STRUCT *ads;
2493 int ret;
2495 if (c->display_usage) {
2496 d_printf( "%s\n"
2497 "net ads keytab create\n"
2498 " %s\n",
2499 _("Usage:"),
2500 _("Create new default keytab"));
2501 return 0;
2504 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2505 return -1;
2507 ret = ads_keytab_create_default(ads);
2508 ads_destroy(&ads);
2509 return ret;
2512 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2514 const char *keytab = NULL;
2516 if (c->display_usage) {
2517 d_printf("%s\n%s",
2518 _("Usage:"),
2519 _("net ads keytab list [keytab]\n"
2520 " List a local keytab\n"
2521 " keytab\tKeytab to list\n"));
2522 return 0;
2525 if (argc >= 1) {
2526 keytab = argv[0];
2529 return ads_keytab_list(keytab);
2533 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2535 struct functable func[] = {
2537 "add",
2538 net_ads_keytab_add,
2539 NET_TRANSPORT_ADS,
2540 N_("Add a service principal"),
2541 N_("net ads keytab add\n"
2542 " Add a service principal")
2545 "create",
2546 net_ads_keytab_create,
2547 NET_TRANSPORT_ADS,
2548 N_("Create a fresh keytab"),
2549 N_("net ads keytab create\n"
2550 " Create a fresh keytab")
2553 "flush",
2554 net_ads_keytab_flush,
2555 NET_TRANSPORT_ADS,
2556 N_("Remove all keytab entries"),
2557 N_("net ads keytab flush\n"
2558 " Remove all keytab entries")
2561 "list",
2562 net_ads_keytab_list,
2563 NET_TRANSPORT_ADS,
2564 N_("List a keytab"),
2565 N_("net ads keytab list\n"
2566 " List a keytab")
2568 {NULL, NULL, 0, NULL, NULL}
2571 if (!USE_KERBEROS_KEYTAB) {
2572 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2573 "keytab method to use keytab functions.\n"));
2576 return net_run_function(c, argc, argv, "net ads keytab", func);
2579 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2581 int ret = -1;
2583 if (c->display_usage) {
2584 d_printf( "%s\n"
2585 "net ads kerberos renew\n"
2586 " %s\n",
2587 _("Usage:"),
2588 _("Renew TGT from existing credential cache"));
2589 return 0;
2592 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2593 if (ret) {
2594 d_printf(_("failed to renew kerberos ticket: %s\n"),
2595 error_message(ret));
2597 return ret;
2600 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2602 struct PAC_LOGON_INFO *info = NULL;
2603 struct PAC_DATA *pac_data = NULL;
2604 struct PAC_DATA_CTR *pac_data_ctr = NULL;
2605 TALLOC_CTX *mem_ctx = NULL;
2606 NTSTATUS status;
2607 int ret = -1;
2608 const char *impersonate_princ_s = NULL;
2609 const char *local_service = NULL;
2610 int i;
2612 if (c->display_usage) {
2613 d_printf( "%s\n"
2614 "net ads kerberos pac [impersonation_principal]\n"
2615 " %s\n",
2616 _("Usage:"),
2617 _("Dump the Kerberos PAC"));
2618 return 0;
2621 for (i=0; i<argc; i++) {
2622 if (strnequal(argv[i], "impersonate", strlen("impersonate"))) {
2623 impersonate_princ_s = get_string_param(argv[i]);
2624 if (impersonate_princ_s == NULL) {
2625 return -1;
2628 if (strnequal(argv[i], "local_service", strlen("local_service"))) {
2629 local_service = get_string_param(argv[i]);
2630 if (local_service == NULL) {
2631 return -1;
2636 mem_ctx = talloc_init("net_ads_kerberos_pac");
2637 if (!mem_ctx) {
2638 goto out;
2641 if (local_service == NULL) {
2642 local_service = talloc_asprintf(mem_ctx, "%s$@%s",
2643 lp_netbios_name(), lp_realm());
2644 if (local_service == NULL) {
2645 goto out;
2649 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2651 status = kerberos_return_pac(mem_ctx,
2652 c->opt_user_name,
2653 c->opt_password,
2655 NULL,
2656 NULL,
2657 NULL,
2658 true,
2659 true,
2660 2592000, /* one month */
2661 impersonate_princ_s,
2662 local_service,
2663 &pac_data_ctr);
2664 if (!NT_STATUS_IS_OK(status)) {
2665 d_printf(_("failed to query kerberos PAC: %s\n"),
2666 nt_errstr(status));
2667 goto out;
2670 pac_data = pac_data_ctr->pac_data;
2672 for (i=0; i < pac_data->num_buffers; i++) {
2674 if (pac_data->buffers[i].type != PAC_TYPE_LOGON_INFO) {
2675 continue;
2678 info = pac_data->buffers[i].info->logon_info.info;
2679 if (!info) {
2680 goto out;
2683 break;
2686 if (info) {
2687 const char *s;
2688 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2689 d_printf(_("The Pac: %s\n"), s);
2692 ret = 0;
2693 out:
2694 TALLOC_FREE(mem_ctx);
2695 return ret;
2698 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2700 TALLOC_CTX *mem_ctx = NULL;
2701 int ret = -1;
2702 NTSTATUS status;
2704 if (c->display_usage) {
2705 d_printf( "%s\n"
2706 "net ads kerberos kinit\n"
2707 " %s\n",
2708 _("Usage:"),
2709 _("Get Ticket Granting Ticket (TGT) for the user"));
2710 return 0;
2713 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2714 if (!mem_ctx) {
2715 goto out;
2718 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2720 ret = kerberos_kinit_password_ext(c->opt_user_name,
2721 c->opt_password,
2723 NULL,
2724 NULL,
2725 NULL,
2726 true,
2727 true,
2728 2592000, /* one month */
2729 &status);
2730 if (ret) {
2731 d_printf(_("failed to kinit password: %s\n"),
2732 nt_errstr(status));
2734 out:
2735 return ret;
2738 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2740 struct functable func[] = {
2742 "kinit",
2743 net_ads_kerberos_kinit,
2744 NET_TRANSPORT_ADS,
2745 N_("Retrieve Ticket Granting Ticket (TGT)"),
2746 N_("net ads kerberos kinit\n"
2747 " Receive Ticket Granting Ticket (TGT)")
2750 "renew",
2751 net_ads_kerberos_renew,
2752 NET_TRANSPORT_ADS,
2753 N_("Renew Ticket Granting Ticket from credential cache"),
2754 N_("net ads kerberos renew\n"
2755 " Renew Ticket Granting Ticket (TGT) from "
2756 "credential cache")
2759 "pac",
2760 net_ads_kerberos_pac,
2761 NET_TRANSPORT_ADS,
2762 N_("Dump Kerberos PAC"),
2763 N_("net ads kerberos pac\n"
2764 " Dump Kerberos PAC")
2766 {NULL, NULL, 0, NULL, NULL}
2769 return net_run_function(c, argc, argv, "net ads kerberos", func);
2772 int net_ads(struct net_context *c, int argc, const char **argv)
2774 struct functable func[] = {
2776 "info",
2777 net_ads_info,
2778 NET_TRANSPORT_ADS,
2779 N_("Display details on remote ADS server"),
2780 N_("net ads info\n"
2781 " Display details on remote ADS server")
2784 "join",
2785 net_ads_join,
2786 NET_TRANSPORT_ADS,
2787 N_("Join the local machine to ADS realm"),
2788 N_("net ads join\n"
2789 " Join the local machine to ADS realm")
2792 "testjoin",
2793 net_ads_testjoin,
2794 NET_TRANSPORT_ADS,
2795 N_("Validate machine account"),
2796 N_("net ads testjoin\n"
2797 " Validate machine account")
2800 "leave",
2801 net_ads_leave,
2802 NET_TRANSPORT_ADS,
2803 N_("Remove the local machine from ADS"),
2804 N_("net ads leave\n"
2805 " Remove the local machine from ADS")
2808 "status",
2809 net_ads_status,
2810 NET_TRANSPORT_ADS,
2811 N_("Display machine account details"),
2812 N_("net ads status\n"
2813 " Display machine account details")
2816 "user",
2817 net_ads_user,
2818 NET_TRANSPORT_ADS,
2819 N_("List/modify users"),
2820 N_("net ads user\n"
2821 " List/modify users")
2824 "group",
2825 net_ads_group,
2826 NET_TRANSPORT_ADS,
2827 N_("List/modify groups"),
2828 N_("net ads group\n"
2829 " List/modify groups")
2832 "dns",
2833 net_ads_dns,
2834 NET_TRANSPORT_ADS,
2835 N_("Issue dynamic DNS update"),
2836 N_("net ads dns\n"
2837 " Issue dynamic DNS update")
2840 "password",
2841 net_ads_password,
2842 NET_TRANSPORT_ADS,
2843 N_("Change user passwords"),
2844 N_("net ads password\n"
2845 " Change user passwords")
2848 "changetrustpw",
2849 net_ads_changetrustpw,
2850 NET_TRANSPORT_ADS,
2851 N_("Change trust account password"),
2852 N_("net ads changetrustpw\n"
2853 " Change trust account password")
2856 "printer",
2857 net_ads_printer,
2858 NET_TRANSPORT_ADS,
2859 N_("List/modify printer entries"),
2860 N_("net ads printer\n"
2861 " List/modify printer entries")
2864 "search",
2865 net_ads_search,
2866 NET_TRANSPORT_ADS,
2867 N_("Issue LDAP search using filter"),
2868 N_("net ads search\n"
2869 " Issue LDAP search using filter")
2872 "dn",
2873 net_ads_dn,
2874 NET_TRANSPORT_ADS,
2875 N_("Issue LDAP search by DN"),
2876 N_("net ads dn\n"
2877 " Issue LDAP search by DN")
2880 "sid",
2881 net_ads_sid,
2882 NET_TRANSPORT_ADS,
2883 N_("Issue LDAP search by SID"),
2884 N_("net ads sid\n"
2885 " Issue LDAP search by SID")
2888 "workgroup",
2889 net_ads_workgroup,
2890 NET_TRANSPORT_ADS,
2891 N_("Display workgroup name"),
2892 N_("net ads workgroup\n"
2893 " Display the workgroup name")
2896 "lookup",
2897 net_ads_lookup,
2898 NET_TRANSPORT_ADS,
2899 N_("Perfom CLDAP query on DC"),
2900 N_("net ads lookup\n"
2901 " Find the ADS DC using CLDAP lookups")
2904 "keytab",
2905 net_ads_keytab,
2906 NET_TRANSPORT_ADS,
2907 N_("Manage local keytab file"),
2908 N_("net ads keytab\n"
2909 " Manage local keytab file")
2912 "gpo",
2913 net_ads_gpo,
2914 NET_TRANSPORT_ADS,
2915 N_("Manage group policy objects"),
2916 N_("net ads gpo\n"
2917 " Manage group policy objects")
2920 "kerberos",
2921 net_ads_kerberos,
2922 NET_TRANSPORT_ADS,
2923 N_("Manage kerberos keytab"),
2924 N_("net ads kerberos\n"
2925 " Manage kerberos keytab")
2927 {NULL, NULL, 0, NULL, NULL}
2930 return net_run_function(c, argc, argv, "net ads", func);
2933 #else
2935 static int net_ads_noads(void)
2937 d_fprintf(stderr, _("ADS support not compiled in\n"));
2938 return -1;
2941 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2943 return net_ads_noads();
2946 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2948 return net_ads_noads();
2951 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2953 return net_ads_noads();
2956 int net_ads_join(struct net_context *c, int argc, const char **argv)
2958 return net_ads_noads();
2961 int net_ads_user(struct net_context *c, int argc, const char **argv)
2963 return net_ads_noads();
2966 int net_ads_group(struct net_context *c, int argc, const char **argv)
2968 return net_ads_noads();
2971 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
2973 return net_ads_noads();
2976 /* this one shouldn't display a message */
2977 int net_ads_check(struct net_context *c)
2979 return -1;
2982 int net_ads_check_our_domain(struct net_context *c)
2984 return -1;
2987 int net_ads(struct net_context *c, int argc, const char **argv)
2989 return net_ads_noads();
2992 #endif /* HAVE_ADS */