winbind: Keep "force_reauth" in invalidate_cm_connection
[Samba.git] / source3 / utils / net_ads.c
blobc4c1a0d40512f19f52fcb3c8e3b3110559293ad1
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 "\tRuns Active Directory Web Services: %s\n"
104 "\tRuns on Windows 2012 or later: %s\n"),
105 (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
106 (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
107 (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
108 (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
109 (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
110 (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
111 (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
112 (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
113 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
114 (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
115 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
116 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"),
117 (reply.server_type & NBT_SERVER_ADS_WEB_SERVICE) ? _("yes") : _("no"),
118 (reply.server_type & NBT_SERVER_DS_8) ? _("yes") : _("no"));
121 printf(_("Forest:\t\t\t%s\n"), reply.forest);
122 printf(_("Domain:\t\t\t%s\n"), reply.dns_domain);
123 printf(_("Domain Controller:\t%s\n"), reply.pdc_dns_name);
125 printf(_("Pre-Win2k Domain:\t%s\n"), reply.domain_name);
126 printf(_("Pre-Win2k Hostname:\t%s\n"), reply.pdc_name);
128 if (*reply.user_name) printf(_("User name:\t%s\n"), reply.user_name);
130 printf(_("Server Site Name :\t\t%s\n"), reply.server_site);
131 printf(_("Client Site Name :\t\t%s\n"), reply.client_site);
133 d_printf(_("NT Version: %d\n"), reply.nt_version);
134 d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
135 d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
137 return 0;
141 this implements the CLDAP based netlogon lookup requests
142 for finding the domain controller of a ADS domain
144 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
146 ADS_STRUCT *ads;
147 int ret;
149 if (c->display_usage) {
150 d_printf("%s\n"
151 "net ads lookup\n"
152 " %s",
153 _("Usage:"),
154 _("Find the ADS DC using CLDAP lookup.\n"));
155 return 0;
158 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
159 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
160 ads_destroy(&ads);
161 return -1;
164 if (!ads->config.realm) {
165 ads->config.realm = discard_const_p(char, c->opt_target_workgroup);
166 ads->ldap.port = 389;
169 ret = net_ads_cldap_netlogon(c, ads);
170 ads_destroy(&ads);
171 return ret;
176 static int net_ads_info(struct net_context *c, int argc, const char **argv)
178 ADS_STRUCT *ads;
179 char addr[INET6_ADDRSTRLEN];
180 time_t pass_time;
182 if (c->display_usage) {
183 d_printf("%s\n"
184 "net ads info\n"
185 " %s",
186 _("Usage:"),
187 _("Display information about an Active Directory "
188 "server.\n"));
189 return 0;
192 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
193 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
194 return -1;
197 if (!ads || !ads->config.realm) {
198 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
199 ads_destroy(&ads);
200 return -1;
203 /* Try to set the server's current time since we didn't do a full
204 TCP LDAP session initially */
206 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
207 d_fprintf( stderr, _("Failed to get server's current time!\n"));
210 pass_time = secrets_fetch_pass_last_set_time(ads->server.workgroup);
212 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
214 d_printf(_("LDAP server: %s\n"), addr);
215 d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
216 d_printf(_("Realm: %s\n"), ads->config.realm);
217 d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
218 d_printf(_("LDAP port: %d\n"), ads->ldap.port);
219 d_printf(_("Server time: %s\n"),
220 http_timestring(talloc_tos(), ads->config.current_time));
222 d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
223 d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
225 d_printf(_("Last machine account password change: %s\n"),
226 http_timestring(talloc_tos(), pass_time));
228 ads_destroy(&ads);
229 return 0;
232 static void use_in_memory_ccache(void) {
233 /* Use in-memory credentials cache so we do not interfere with
234 * existing credentials */
235 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
238 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
239 uint32_t auth_flags, ADS_STRUCT **ads_ret)
241 ADS_STRUCT *ads = NULL;
242 ADS_STATUS status;
243 bool need_password = false;
244 bool second_time = false;
245 char *cp;
246 const char *realm = NULL;
247 bool tried_closest_dc = false;
249 /* lp_realm() should be handled by a command line param,
250 However, the join requires that realm be set in smb.conf
251 and compares our realm with the remote server's so this is
252 ok until someone needs more flexibility */
254 *ads_ret = NULL;
256 retry_connect:
257 if (only_own_domain) {
258 realm = lp_realm();
259 } else {
260 realm = assume_own_realm(c);
263 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
265 if (!c->opt_user_name) {
266 c->opt_user_name = "administrator";
269 if (c->opt_user_specified) {
270 need_password = true;
273 retry:
274 if (!c->opt_password && need_password && !c->opt_machine_pass) {
275 c->opt_password = net_prompt_pass(c, c->opt_user_name);
276 if (!c->opt_password) {
277 ads_destroy(&ads);
278 return ADS_ERROR(LDAP_NO_MEMORY);
282 if (c->opt_password) {
283 use_in_memory_ccache();
284 SAFE_FREE(ads->auth.password);
285 ads->auth.password = smb_xstrdup(c->opt_password);
288 ads->auth.flags |= auth_flags;
289 SAFE_FREE(ads->auth.user_name);
290 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
293 * If the username is of the form "name@realm",
294 * extract the realm and convert to upper case.
295 * This is only used to establish the connection.
297 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
298 *cp++ = '\0';
299 SAFE_FREE(ads->auth.realm);
300 ads->auth.realm = smb_xstrdup(cp);
301 if (!strupper_m(ads->auth.realm)) {
302 ads_destroy(&ads);
303 return ADS_ERROR(LDAP_NO_MEMORY);
307 status = ads_connect(ads);
309 if (!ADS_ERR_OK(status)) {
311 if (NT_STATUS_EQUAL(ads_ntstatus(status),
312 NT_STATUS_NO_LOGON_SERVERS)) {
313 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
314 ads_destroy(&ads);
315 return status;
318 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
319 need_password = true;
320 second_time = true;
321 goto retry;
322 } else {
323 ads_destroy(&ads);
324 return status;
328 /* when contacting our own domain, make sure we use the closest DC.
329 * This is done by reconnecting to ADS because only the first call to
330 * ads_connect will give us our own sitename */
332 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
334 tried_closest_dc = true; /* avoid loop */
336 if (!ads_closest_dc(ads)) {
338 namecache_delete(ads->server.realm, 0x1C);
339 namecache_delete(ads->server.workgroup, 0x1C);
341 ads_destroy(&ads);
342 ads = NULL;
344 goto retry_connect;
348 *ads_ret = ads;
349 return status;
352 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
354 return ads_startup_int(c, only_own_domain, 0, ads);
357 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
359 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
363 Check to see if connection can be made via ads.
364 ads_startup() stores the password in opt_password if it needs to so
365 that rpc or rap can use it without re-prompting.
367 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
369 ADS_STRUCT *ads;
370 ADS_STATUS status;
372 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
373 return -1;
376 ads->auth.flags |= ADS_AUTH_NO_BIND;
378 status = ads_connect(ads);
379 if ( !ADS_ERR_OK(status) ) {
380 return -1;
383 ads_destroy(&ads);
384 return 0;
387 int net_ads_check_our_domain(struct net_context *c)
389 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
392 int net_ads_check(struct net_context *c)
394 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
398 determine the netbios workgroup name for a domain
400 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
402 ADS_STRUCT *ads;
403 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
405 if (c->display_usage) {
406 d_printf ("%s\n"
407 "net ads workgroup\n"
408 " %s\n",
409 _("Usage:"),
410 _("Print the workgroup name"));
411 return 0;
414 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
415 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
416 return -1;
419 if (!ads->config.realm) {
420 ads->config.realm = discard_const_p(char, c->opt_target_workgroup);
421 ads->ldap.port = 389;
424 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads->ldap.ss, ads->server.realm, &reply ) ) {
425 d_fprintf(stderr, _("CLDAP query failed!\n"));
426 ads_destroy(&ads);
427 return -1;
430 d_printf(_("Workgroup: %s\n"), reply.domain_name);
432 ads_destroy(&ads);
434 return 0;
439 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
441 char **disp_fields = (char **) data_area;
443 if (!field) { /* must be end of record */
444 if (disp_fields[0]) {
445 if (!strchr_m(disp_fields[0], '$')) {
446 if (disp_fields[1])
447 d_printf("%-21.21s %s\n",
448 disp_fields[0], disp_fields[1]);
449 else
450 d_printf("%s\n", disp_fields[0]);
453 SAFE_FREE(disp_fields[0]);
454 SAFE_FREE(disp_fields[1]);
455 return true;
457 if (!values) /* must be new field, indicate string field */
458 return true;
459 if (strcasecmp_m(field, "sAMAccountName") == 0) {
460 disp_fields[0] = SMB_STRDUP((char *) values[0]);
462 if (strcasecmp_m(field, "description") == 0)
463 disp_fields[1] = SMB_STRDUP((char *) values[0]);
464 return true;
467 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
469 return net_user_usage(c, argc, argv);
472 static int ads_user_add(struct net_context *c, int argc, const char **argv)
474 ADS_STRUCT *ads;
475 ADS_STATUS status;
476 char *upn, *userdn;
477 LDAPMessage *res=NULL;
478 int rc = -1;
479 char *ou_str = NULL;
481 if (argc < 1 || c->display_usage)
482 return net_ads_user_usage(c, argc, argv);
484 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
485 return -1;
488 status = ads_find_user_acct(ads, &res, argv[0]);
490 if (!ADS_ERR_OK(status)) {
491 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
492 goto done;
495 if (ads_count_replies(ads, res)) {
496 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
497 argv[0]);
498 goto done;
501 if (c->opt_container) {
502 ou_str = SMB_STRDUP(c->opt_container);
503 } else {
504 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
507 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
509 if (!ADS_ERR_OK(status)) {
510 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
511 ads_errstr(status));
512 goto done;
515 /* if no password is to be set, we're done */
516 if (argc == 1) {
517 d_printf(_("User %s added\n"), argv[0]);
518 rc = 0;
519 goto done;
522 /* try setting the password */
523 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
524 goto done;
526 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
527 ads->auth.time_offset);
528 SAFE_FREE(upn);
529 if (ADS_ERR_OK(status)) {
530 d_printf(_("User %s added\n"), argv[0]);
531 rc = 0;
532 goto done;
535 /* password didn't set, delete account */
536 d_fprintf(stderr, _("Could not add user %s. "
537 "Error setting password %s\n"),
538 argv[0], ads_errstr(status));
539 ads_msgfree(ads, res);
540 status=ads_find_user_acct(ads, &res, argv[0]);
541 if (ADS_ERR_OK(status)) {
542 userdn = ads_get_dn(ads, talloc_tos(), res);
543 ads_del_dn(ads, userdn);
544 TALLOC_FREE(userdn);
547 done:
548 if (res)
549 ads_msgfree(ads, res);
550 ads_destroy(&ads);
551 SAFE_FREE(ou_str);
552 return rc;
555 static int ads_user_info(struct net_context *c, int argc, const char **argv)
557 ADS_STRUCT *ads = NULL;
558 ADS_STATUS rc;
559 LDAPMessage *res = NULL;
560 TALLOC_CTX *frame;
561 int ret = 0;
562 wbcErr wbc_status;
563 const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
564 char *searchstring=NULL;
565 char **grouplist;
566 char *primary_group;
567 char *escaped_user;
568 struct dom_sid primary_group_sid;
569 uint32_t group_rid;
570 enum wbcSidType type;
572 if (argc < 1 || c->display_usage) {
573 return net_ads_user_usage(c, argc, argv);
576 frame = talloc_new(talloc_tos());
577 if (frame == NULL) {
578 return -1;
581 escaped_user = escape_ldap_string(frame, argv[0]);
582 if (!escaped_user) {
583 d_fprintf(stderr,
584 _("ads_user_info: failed to escape user %s\n"),
585 argv[0]);
586 return -1;
589 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
590 ret = -1;
591 goto error;
594 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
595 ret =-1;
596 goto error;
598 rc = ads_search(ads, &res, searchstring, attrs);
599 SAFE_FREE(searchstring);
601 if (!ADS_ERR_OK(rc)) {
602 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(rc));
603 ret = -1;
604 goto error;
607 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
608 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
609 ret = -1;
610 goto error;
613 rc = ads_domain_sid(ads, &primary_group_sid);
614 if (!ADS_ERR_OK(rc)) {
615 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(rc));
616 ret = -1;
617 goto error;
620 sid_append_rid(&primary_group_sid, group_rid);
622 wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
623 NULL, /* don't look up domain */
624 &primary_group,
625 &type);
626 if (!WBC_ERROR_IS_OK(wbc_status)) {
627 d_fprintf(stderr, "wbcLookupSid: %s\n",
628 wbcErrorString(wbc_status));
629 ret = -1;
630 goto error;
633 d_printf("%s\n", primary_group);
635 wbcFreeMemory(primary_group);
637 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
638 (LDAPMessage *)res, "memberOf");
640 if (grouplist) {
641 int i;
642 char **groupname;
643 for (i=0;grouplist[i];i++) {
644 groupname = ldap_explode_dn(grouplist[i], 1);
645 d_printf("%s\n", groupname[0]);
646 ldap_value_free(groupname);
648 ldap_value_free(grouplist);
651 error:
652 if (res) ads_msgfree(ads, res);
653 if (ads) ads_destroy(&ads);
654 TALLOC_FREE(frame);
655 return ret;
658 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
660 ADS_STRUCT *ads;
661 ADS_STATUS rc;
662 LDAPMessage *res = NULL;
663 char *userdn;
665 if (argc < 1) {
666 return net_ads_user_usage(c, argc, argv);
669 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
670 return -1;
673 rc = ads_find_user_acct(ads, &res, argv[0]);
674 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
675 d_printf(_("User %s does not exist.\n"), argv[0]);
676 ads_msgfree(ads, res);
677 ads_destroy(&ads);
678 return -1;
680 userdn = ads_get_dn(ads, talloc_tos(), res);
681 ads_msgfree(ads, res);
682 rc = ads_del_dn(ads, userdn);
683 TALLOC_FREE(userdn);
684 if (ADS_ERR_OK(rc)) {
685 d_printf(_("User %s deleted\n"), argv[0]);
686 ads_destroy(&ads);
687 return 0;
689 d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
690 ads_errstr(rc));
691 ads_destroy(&ads);
692 return -1;
695 int net_ads_user(struct net_context *c, int argc, const char **argv)
697 struct functable func[] = {
699 "add",
700 ads_user_add,
701 NET_TRANSPORT_ADS,
702 N_("Add an AD user"),
703 N_("net ads user add\n"
704 " Add an AD user")
707 "info",
708 ads_user_info,
709 NET_TRANSPORT_ADS,
710 N_("Display information about an AD user"),
711 N_("net ads user info\n"
712 " Display information about an AD user")
715 "delete",
716 ads_user_delete,
717 NET_TRANSPORT_ADS,
718 N_("Delete an AD user"),
719 N_("net ads user delete\n"
720 " Delete an AD user")
722 {NULL, NULL, 0, NULL, NULL}
724 ADS_STRUCT *ads;
725 ADS_STATUS rc;
726 const char *shortattrs[] = {"sAMAccountName", NULL};
727 const char *longattrs[] = {"sAMAccountName", "description", NULL};
728 char *disp_fields[2] = {NULL, NULL};
730 if (argc == 0) {
731 if (c->display_usage) {
732 d_printf( "%s\n"
733 "net ads user\n"
734 " %s\n",
735 _("Usage:"),
736 _("List AD users"));
737 net_display_usage_from_functable(func);
738 return 0;
741 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
742 return -1;
745 if (c->opt_long_list_entries)
746 d_printf(_("\nUser name Comment"
747 "\n-----------------------------\n"));
749 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
750 LDAP_SCOPE_SUBTREE,
751 "(objectCategory=user)",
752 c->opt_long_list_entries ? longattrs :
753 shortattrs, usergrp_display,
754 disp_fields);
755 ads_destroy(&ads);
756 return ADS_ERR_OK(rc) ? 0 : -1;
759 return net_run_function(c, argc, argv, "net ads user", func);
762 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
764 return net_group_usage(c, argc, argv);
767 static int ads_group_add(struct net_context *c, int argc, const char **argv)
769 ADS_STRUCT *ads;
770 ADS_STATUS status;
771 LDAPMessage *res=NULL;
772 int rc = -1;
773 char *ou_str = NULL;
775 if (argc < 1 || c->display_usage) {
776 return net_ads_group_usage(c, argc, argv);
779 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
780 return -1;
783 status = ads_find_user_acct(ads, &res, argv[0]);
785 if (!ADS_ERR_OK(status)) {
786 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
787 goto done;
790 if (ads_count_replies(ads, res)) {
791 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
792 goto done;
795 if (c->opt_container) {
796 ou_str = SMB_STRDUP(c->opt_container);
797 } else {
798 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
801 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
803 if (ADS_ERR_OK(status)) {
804 d_printf(_("Group %s added\n"), argv[0]);
805 rc = 0;
806 } else {
807 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
808 ads_errstr(status));
811 done:
812 if (res)
813 ads_msgfree(ads, res);
814 ads_destroy(&ads);
815 SAFE_FREE(ou_str);
816 return rc;
819 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
821 ADS_STRUCT *ads;
822 ADS_STATUS rc;
823 LDAPMessage *res = NULL;
824 char *groupdn;
826 if (argc < 1 || c->display_usage) {
827 return net_ads_group_usage(c, argc, argv);
830 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
831 return -1;
834 rc = ads_find_user_acct(ads, &res, argv[0]);
835 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
836 d_printf(_("Group %s does not exist.\n"), argv[0]);
837 ads_msgfree(ads, res);
838 ads_destroy(&ads);
839 return -1;
841 groupdn = ads_get_dn(ads, talloc_tos(), res);
842 ads_msgfree(ads, res);
843 rc = ads_del_dn(ads, groupdn);
844 TALLOC_FREE(groupdn);
845 if (ADS_ERR_OK(rc)) {
846 d_printf(_("Group %s deleted\n"), argv[0]);
847 ads_destroy(&ads);
848 return 0;
850 d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
851 ads_errstr(rc));
852 ads_destroy(&ads);
853 return -1;
856 int net_ads_group(struct net_context *c, int argc, const char **argv)
858 struct functable func[] = {
860 "add",
861 ads_group_add,
862 NET_TRANSPORT_ADS,
863 N_("Add an AD group"),
864 N_("net ads group add\n"
865 " Add an AD group")
868 "delete",
869 ads_group_delete,
870 NET_TRANSPORT_ADS,
871 N_("Delete an AD group"),
872 N_("net ads group delete\n"
873 " Delete an AD group")
875 {NULL, NULL, 0, NULL, NULL}
877 ADS_STRUCT *ads;
878 ADS_STATUS rc;
879 const char *shortattrs[] = {"sAMAccountName", NULL};
880 const char *longattrs[] = {"sAMAccountName", "description", NULL};
881 char *disp_fields[2] = {NULL, NULL};
883 if (argc == 0) {
884 if (c->display_usage) {
885 d_printf( "%s\n"
886 "net ads group\n"
887 " %s\n",
888 _("Usage:"),
889 _("List AD groups"));
890 net_display_usage_from_functable(func);
891 return 0;
894 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
895 return -1;
898 if (c->opt_long_list_entries)
899 d_printf(_("\nGroup name Comment"
900 "\n-----------------------------\n"));
901 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
902 LDAP_SCOPE_SUBTREE,
903 "(objectCategory=group)",
904 c->opt_long_list_entries ? longattrs :
905 shortattrs, usergrp_display,
906 disp_fields);
908 ads_destroy(&ads);
909 return ADS_ERR_OK(rc) ? 0 : -1;
911 return net_run_function(c, argc, argv, "net ads group", func);
914 static int net_ads_status(struct net_context *c, int argc, const char **argv)
916 ADS_STRUCT *ads;
917 ADS_STATUS rc;
918 LDAPMessage *res;
920 if (c->display_usage) {
921 d_printf( "%s\n"
922 "net ads status\n"
923 " %s\n",
924 _("Usage:"),
925 _("Display machine account details"));
926 return 0;
929 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
930 return -1;
933 rc = ads_find_machine_acct(ads, &res, lp_netbios_name());
934 if (!ADS_ERR_OK(rc)) {
935 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
936 ads_destroy(&ads);
937 return -1;
940 if (ads_count_replies(ads, res) == 0) {
941 d_fprintf(stderr, _("No machine account for '%s' found\n"), lp_netbios_name());
942 ads_destroy(&ads);
943 return -1;
946 ads_dump(ads, res);
947 ads_destroy(&ads);
948 return 0;
951 /*******************************************************************
952 Leave an AD domain. Windows XP disables the machine account.
953 We'll try the same. The old code would do an LDAP delete.
954 That only worked using the machine creds because added the machine
955 with full control to the computer object's ACL.
956 *******************************************************************/
958 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
960 TALLOC_CTX *ctx;
961 struct libnet_UnjoinCtx *r = NULL;
962 WERROR werr;
964 if (c->display_usage) {
965 d_printf( "%s\n"
966 "net ads leave\n"
967 " %s\n",
968 _("Usage:"),
969 _("Leave an AD domain"));
970 return 0;
973 if (!*lp_realm()) {
974 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
975 return -1;
978 if (!(ctx = talloc_init("net_ads_leave"))) {
979 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
980 return -1;
983 if (!c->opt_kerberos) {
984 use_in_memory_ccache();
987 if (!c->msg_ctx) {
988 d_fprintf(stderr, _("Could not initialise message context. "
989 "Try running as root\n"));
990 return -1;
993 werr = libnet_init_UnjoinCtx(ctx, &r);
994 if (!W_ERROR_IS_OK(werr)) {
995 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
996 return -1;
999 r->in.debug = true;
1000 r->in.use_kerberos = c->opt_kerberos;
1001 r->in.dc_name = c->opt_host;
1002 r->in.domain_name = lp_realm();
1003 r->in.admin_account = c->opt_user_name;
1004 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1005 r->in.modify_config = lp_config_backend_is_registry();
1007 /* Try to delete it, but if that fails, disable it. The
1008 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
1009 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1010 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
1011 r->in.delete_machine_account = true;
1012 r->in.msg_ctx = c->msg_ctx;
1014 werr = libnet_Unjoin(ctx, r);
1015 if (!W_ERROR_IS_OK(werr)) {
1016 d_printf(_("Failed to leave domain: %s\n"),
1017 r->out.error_string ? r->out.error_string :
1018 get_friendly_werror_msg(werr));
1019 goto done;
1022 if (r->out.deleted_machine_account) {
1023 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1024 r->in.machine_name, r->out.dns_domain_name);
1025 goto done;
1028 /* We couldn't delete it - see if the disable succeeded. */
1029 if (r->out.disabled_machine_account) {
1030 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1031 r->in.machine_name, r->out.dns_domain_name);
1032 werr = WERR_OK;
1033 goto done;
1036 /* Based on what we requested, we shouldn't get here, but if
1037 we did, it means the secrets were removed, and therefore
1038 we have left the domain */
1039 d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1040 r->in.machine_name, r->out.dns_domain_name);
1042 done:
1043 TALLOC_FREE(r);
1044 TALLOC_FREE(ctx);
1046 if (W_ERROR_IS_OK(werr)) {
1047 return 0;
1050 return -1;
1053 static NTSTATUS net_ads_join_ok(struct net_context *c)
1055 ADS_STRUCT *ads = NULL;
1056 ADS_STATUS status;
1057 fstring dc_name;
1058 struct sockaddr_storage dcip;
1060 if (!secrets_init()) {
1061 DEBUG(1,("Failed to initialise secrets database\n"));
1062 return NT_STATUS_ACCESS_DENIED;
1065 net_use_krb_machine_account(c);
1067 get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1069 status = ads_startup(c, true, &ads);
1070 if (!ADS_ERR_OK(status)) {
1071 return ads_ntstatus(status);
1074 ads_destroy(&ads);
1075 return NT_STATUS_OK;
1079 check that an existing join is OK
1081 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1083 NTSTATUS status;
1084 use_in_memory_ccache();
1086 if (c->display_usage) {
1087 d_printf( "%s\n"
1088 "net ads testjoin\n"
1089 " %s\n",
1090 _("Usage:"),
1091 _("Test if the existing join is ok"));
1092 return 0;
1095 /* Display success or failure */
1096 status = net_ads_join_ok(c);
1097 if (!NT_STATUS_IS_OK(status)) {
1098 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1099 get_friendly_nt_error_msg(status));
1100 return -1;
1103 printf(_("Join is OK\n"));
1104 return 0;
1107 /*******************************************************************
1108 Simple configu checks before beginning the join
1109 ********************************************************************/
1111 static WERROR check_ads_config( void )
1113 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1114 d_printf(_("Host is not configured as a member server.\n"));
1115 return WERR_INVALID_DOMAIN_ROLE;
1118 if (strlen(lp_netbios_name()) > 15) {
1119 d_printf(_("Our netbios name can be at most 15 chars long, "
1120 "\"%s\" is %u chars long\n"), lp_netbios_name(),
1121 (unsigned int)strlen(lp_netbios_name()));
1122 return WERR_INVALID_COMPUTERNAME;
1125 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1126 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1127 "join to succeed.\n"), get_dyn_CONFIGFILE());
1128 return WERR_INVALID_PARAMETER;
1131 return WERR_OK;
1134 /*******************************************************************
1135 Send a DNS update request
1136 *******************************************************************/
1138 #if defined(WITH_DNS_UPDATES)
1139 #include "../lib/addns/dns.h"
1141 static NTSTATUS net_update_dns_internal(struct net_context *c,
1142 TALLOC_CTX *ctx, ADS_STRUCT *ads,
1143 const char *machine_name,
1144 const struct sockaddr_storage *addrs,
1145 int num_addrs, bool remove_host)
1147 struct dns_rr_ns *nameservers = NULL;
1148 int ns_count = 0, i;
1149 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1150 DNS_ERROR dns_err;
1151 fstring dns_server;
1152 const char *dnsdomain = NULL;
1153 char *root_domain = NULL;
1155 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1156 d_printf(_("No DNS domain configured for %s. "
1157 "Unable to perform DNS Update.\n"), machine_name);
1158 status = NT_STATUS_INVALID_PARAMETER;
1159 goto done;
1161 dnsdomain++;
1163 status = ads_dns_lookup_ns(ctx,
1164 dnsdomain,
1165 &nameservers,
1166 &ns_count);
1167 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1168 /* Child domains often do not have NS records. Look
1169 for the NS record for the forest root domain
1170 (rootDomainNamingContext in therootDSE) */
1172 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1173 LDAPMessage *msg = NULL;
1174 char *root_dn;
1175 ADS_STATUS ads_status;
1177 if ( !ads->ldap.ld ) {
1178 ads_status = ads_connect( ads );
1179 if ( !ADS_ERR_OK(ads_status) ) {
1180 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1181 goto done;
1185 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1186 "(objectclass=*)", rootname_attrs, &msg);
1187 if (!ADS_ERR_OK(ads_status)) {
1188 goto done;
1191 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1192 if ( !root_dn ) {
1193 ads_msgfree( ads, msg );
1194 goto done;
1197 root_domain = ads_build_domain( root_dn );
1199 /* cleanup */
1200 ads_msgfree( ads, msg );
1202 /* try again for NS servers */
1204 status = ads_dns_lookup_ns(ctx,
1205 root_domain,
1206 &nameservers,
1207 &ns_count);
1209 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1210 DEBUG(3,("net_update_dns_internal: Failed to find name server for the %s "
1211 "realm\n", ads->config.realm));
1212 if (ns_count == 0) {
1213 status = NT_STATUS_UNSUCCESSFUL;
1215 goto done;
1218 dnsdomain = root_domain;
1222 for (i=0; i < ns_count; i++) {
1224 uint32_t flags = DNS_UPDATE_SIGNED |
1225 DNS_UPDATE_UNSIGNED |
1226 DNS_UPDATE_UNSIGNED_SUFFICIENT |
1227 DNS_UPDATE_PROBE |
1228 DNS_UPDATE_PROBE_SUFFICIENT;
1230 if (c->opt_force) {
1231 flags &= ~DNS_UPDATE_PROBE_SUFFICIENT;
1232 flags &= ~DNS_UPDATE_UNSIGNED_SUFFICIENT;
1236 * Do not return after PROBE completion if this function
1237 * is called for DNS removal.
1239 if (remove_host) {
1240 flags &= ~DNS_UPDATE_PROBE_SUFFICIENT;
1243 status = NT_STATUS_UNSUCCESSFUL;
1245 /* Now perform the dns update - we'll try non-secure and if we fail,
1246 we'll follow it up with a secure update */
1248 fstrcpy( dns_server, nameservers[i].hostname );
1250 dns_err = DoDNSUpdate(dns_server,
1251 dnsdomain,
1252 machine_name,
1253 addrs,
1254 num_addrs,
1255 flags,
1256 remove_host);
1257 if (ERR_DNS_IS_OK(dns_err)) {
1258 status = NT_STATUS_OK;
1259 goto done;
1262 if (ERR_DNS_EQUAL(dns_err, ERROR_DNS_INVALID_NAME_SERVER) ||
1263 ERR_DNS_EQUAL(dns_err, ERROR_DNS_CONNECTION_FAILED) ||
1264 ERR_DNS_EQUAL(dns_err, ERROR_DNS_SOCKET_ERROR)) {
1265 DEBUG(1,("retrying DNS update with next nameserver after receiving %s\n",
1266 dns_errstr(dns_err)));
1267 continue;
1270 d_printf(_("DNS Update for %s failed: %s\n"),
1271 machine_name, dns_errstr(dns_err));
1272 status = NT_STATUS_UNSUCCESSFUL;
1273 goto done;
1276 done:
1278 SAFE_FREE( root_domain );
1280 return status;
1283 static NTSTATUS net_update_dns_ext(struct net_context *c,
1284 TALLOC_CTX *mem_ctx, ADS_STRUCT *ads,
1285 const char *hostname,
1286 struct sockaddr_storage *iplist,
1287 int num_addrs, bool remove_host)
1289 struct sockaddr_storage *iplist_alloc = NULL;
1290 fstring machine_name;
1291 NTSTATUS status;
1293 if (hostname) {
1294 fstrcpy(machine_name, hostname);
1295 } else {
1296 name_to_fqdn( machine_name, lp_netbios_name() );
1298 if (!strlower_m( machine_name )) {
1299 return NT_STATUS_INVALID_PARAMETER;
1303 * If remove_host is true, then remove all IP addresses associated with
1304 * this hostname from the AD server.
1306 if (!remove_host && (num_addrs == 0 || iplist == NULL)) {
1308 * Get our ip address
1309 * (not the 127.0.0.x address but a real ip address)
1311 num_addrs = get_my_ip_address(&iplist_alloc);
1312 if ( num_addrs <= 0 ) {
1313 DEBUG(4, ("net_update_dns_ext: Failed to find my "
1314 "non-loopback IP addresses!\n"));
1315 return NT_STATUS_INVALID_PARAMETER;
1317 iplist = iplist_alloc;
1320 status = net_update_dns_internal(c, mem_ctx, ads, machine_name,
1321 iplist, num_addrs, remove_host);
1323 SAFE_FREE(iplist_alloc);
1324 return status;
1327 static NTSTATUS net_update_dns(struct net_context *c, TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, const char *hostname)
1329 NTSTATUS status;
1331 status = net_update_dns_ext(c, mem_ctx, ads, hostname, NULL, 0, false);
1332 return status;
1334 #endif
1337 /*******************************************************************
1338 ********************************************************************/
1340 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1342 d_printf(_("net ads join [--no-dns-updates] [options]\n"
1343 "Valid options:\n"));
1344 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1345 " The default UPN is in the form host/netbiosname@REALM.\n"));
1346 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1347 " The OU string read from top to bottom without RDNs\n"
1348 " and delimited by a '/'.\n"
1349 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1350 " NB: A backslash '\\' is used as escape at multiple\n"
1351 " levels and may need to be doubled or even\n"
1352 " quadrupled. It is not used as a separator.\n"));
1353 d_printf(_(" machinepass=PASS Set the machine password to a specific value during\n"
1354 " the join. The default password is random.\n"));
1355 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1356 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during join.\n"
1357 " NB: osName and osVer must be specified together for\n"
1358 " either to take effect. The operatingSystemService\n"
1359 " attribute is then also set along with the two\n"
1360 " other attributes.\n"));
1361 d_printf(_(" osServicePack=string Set the operatingSystemServicePack attribute\n"
1362 " during the join.\n"
1363 " NB: If not specified then by default the samba\n"
1364 " version string is used instead.\n"));
1365 return -1;
1369 static void _net_ads_join_dns_updates(struct net_context *c, TALLOC_CTX *ctx, struct libnet_JoinCtx *r)
1371 #if defined(WITH_DNS_UPDATES)
1372 ADS_STRUCT *ads_dns = NULL;
1373 int ret;
1374 NTSTATUS status;
1377 * In a clustered environment, don't do dynamic dns updates:
1378 * Registering the set of ip addresses that are assigned to
1379 * the interfaces of the node that performs the join does usually
1380 * not have the desired effect, since the local interfaces do not
1381 * carry the complete set of the cluster's public IP addresses.
1382 * And it can also contain internal addresses that should not
1383 * be visible to the outside at all.
1384 * In order to do dns updates in a clustererd setup, use
1385 * net ads dns register.
1387 if (lp_clustering()) {
1388 d_fprintf(stderr, _("Not doing automatic DNS update in a "
1389 "clustered setup.\n"));
1390 return;
1393 if (!r->out.domain_is_ad) {
1394 return;
1398 * We enter this block with user creds.
1399 * kinit with the machine password to do dns update.
1402 ads_dns = ads_init(lp_realm(), NULL, r->in.dc_name);
1404 if (ads_dns == NULL) {
1405 d_fprintf(stderr, _("DNS update failed: out of memory!\n"));
1406 goto done;
1409 use_in_memory_ccache();
1411 ret = asprintf(&ads_dns->auth.user_name, "%s$", lp_netbios_name());
1412 if (ret == -1) {
1413 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1414 goto done;
1417 ads_dns->auth.password = secrets_fetch_machine_password(
1418 r->out.netbios_domain_name, NULL, NULL);
1419 if (ads_dns->auth.password == NULL) {
1420 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1421 goto done;
1424 ads_dns->auth.realm = SMB_STRDUP(r->out.dns_domain_name);
1425 if (ads_dns->auth.realm == NULL) {
1426 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1427 goto done;
1430 if (!strupper_m(ads_dns->auth.realm)) {
1431 d_fprintf(stderr, _("strupper_m %s failed\n"), ads_dns->auth.realm);
1432 goto done;
1435 ret = ads_kinit_password(ads_dns);
1436 if (ret != 0) {
1437 d_fprintf(stderr,
1438 _("DNS update failed: kinit failed: %s\n"),
1439 error_message(ret));
1440 goto done;
1443 status = net_update_dns(c, ctx, ads_dns, NULL);
1444 if (!NT_STATUS_IS_OK(status)) {
1445 d_fprintf( stderr, _("DNS update failed: %s\n"),
1446 nt_errstr(status));
1449 done:
1450 ads_destroy(&ads_dns);
1451 #endif
1453 return;
1457 int net_ads_join(struct net_context *c, int argc, const char **argv)
1459 TALLOC_CTX *ctx = NULL;
1460 struct libnet_JoinCtx *r = NULL;
1461 const char *domain = lp_realm();
1462 WERROR werr = WERR_NERR_SETUPNOTJOINED;
1463 bool createupn = false;
1464 const char *machineupn = NULL;
1465 const char *machine_password = NULL;
1466 const char *create_in_ou = NULL;
1467 int i;
1468 const char *os_name = NULL;
1469 const char *os_version = NULL;
1470 const char *os_servicepack = NULL;
1471 bool modify_config = lp_config_backend_is_registry();
1472 enum libnetjoin_JoinDomNameType domain_name_type = JoinDomNameTypeDNS;
1474 if (c->display_usage)
1475 return net_ads_join_usage(c, argc, argv);
1477 if (!modify_config) {
1479 werr = check_ads_config();
1480 if (!W_ERROR_IS_OK(werr)) {
1481 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1482 goto fail;
1486 if (!(ctx = talloc_init("net_ads_join"))) {
1487 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1488 werr = WERR_NOT_ENOUGH_MEMORY;
1489 goto fail;
1492 if (!c->opt_kerberos) {
1493 use_in_memory_ccache();
1496 werr = libnet_init_JoinCtx(ctx, &r);
1497 if (!W_ERROR_IS_OK(werr)) {
1498 goto fail;
1501 /* process additional command line args */
1503 for ( i=0; i<argc; i++ ) {
1504 if ( !strncasecmp_m(argv[i], "createupn", strlen("createupn")) ) {
1505 createupn = true;
1506 machineupn = get_string_param(argv[i]);
1508 else if ( !strncasecmp_m(argv[i], "createcomputer", strlen("createcomputer")) ) {
1509 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1510 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1511 werr = WERR_INVALID_PARAMETER;
1512 goto fail;
1515 else if ( !strncasecmp_m(argv[i], "osName", strlen("osName")) ) {
1516 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1517 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1518 werr = WERR_INVALID_PARAMETER;
1519 goto fail;
1522 else if ( !strncasecmp_m(argv[i], "osVer", strlen("osVer")) ) {
1523 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1524 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1525 werr = WERR_INVALID_PARAMETER;
1526 goto fail;
1529 else if ( !strncasecmp_m(argv[i], "osServicePack", strlen("osServicePack")) ) {
1530 if ( (os_servicepack = get_string_param(argv[i])) == NULL ) {
1531 d_fprintf(stderr, _("Please supply a valid servicepack identifier.\n"));
1532 werr = WERR_INVALID_PARAMETER;
1533 goto fail;
1536 else if ( !strncasecmp_m(argv[i], "machinepass", strlen("machinepass")) ) {
1537 if ( (machine_password = get_string_param(argv[i])) == NULL ) {
1538 d_fprintf(stderr, _("Please supply a valid password to set as trust account password.\n"));
1539 werr = WERR_INVALID_PARAMETER;
1540 goto fail;
1543 else {
1544 domain = argv[i];
1545 if (strchr(domain, '.') == NULL) {
1546 domain_name_type = JoinDomNameTypeUnknown;
1547 } else {
1548 domain_name_type = JoinDomNameTypeDNS;
1553 if (!*domain) {
1554 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1555 werr = WERR_INVALID_PARAMETER;
1556 goto fail;
1559 if (!c->msg_ctx) {
1560 d_fprintf(stderr, _("Could not initialise message context. "
1561 "Try running as root\n"));
1562 werr = WERR_ACCESS_DENIED;
1563 goto fail;
1566 /* Do the domain join here */
1568 r->in.domain_name = domain;
1569 r->in.domain_name_type = domain_name_type;
1570 r->in.create_upn = createupn;
1571 r->in.upn = machineupn;
1572 r->in.account_ou = create_in_ou;
1573 r->in.os_name = os_name;
1574 r->in.os_version = os_version;
1575 r->in.os_servicepack = os_servicepack;
1576 r->in.dc_name = c->opt_host;
1577 r->in.admin_account = c->opt_user_name;
1578 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1579 r->in.machine_password = machine_password;
1580 r->in.debug = true;
1581 r->in.use_kerberos = c->opt_kerberos;
1582 r->in.modify_config = modify_config;
1583 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1584 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1585 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1586 r->in.msg_ctx = c->msg_ctx;
1588 werr = libnet_Join(ctx, r);
1589 if (W_ERROR_EQUAL(werr, WERR_NERR_DCNOTFOUND) &&
1590 strequal(domain, lp_realm())) {
1591 r->in.domain_name = lp_workgroup();
1592 r->in.domain_name_type = JoinDomNameTypeNBT;
1593 werr = libnet_Join(ctx, r);
1595 if (!W_ERROR_IS_OK(werr)) {
1596 goto fail;
1599 /* Check the short name of the domain */
1601 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1602 d_printf(_("The workgroup in %s does not match the short\n"
1603 "domain name obtained from the server.\n"
1604 "Using the name [%s] from the server.\n"
1605 "You should set \"workgroup = %s\" in %s.\n"),
1606 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1607 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1610 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1612 if (r->out.dns_domain_name) {
1613 d_printf(_("Joined '%s' to dns domain '%s'\n"), r->in.machine_name,
1614 r->out.dns_domain_name);
1615 } else {
1616 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1617 r->out.netbios_domain_name);
1620 /* print out informative error string in case there is one */
1621 if (r->out.error_string != NULL) {
1622 d_printf("%s\n", r->out.error_string);
1626 * We try doing the dns update (if it was compiled in
1627 * and if it was not disabled on the command line).
1628 * If the dns update fails, we still consider the join
1629 * operation as succeeded if we came this far.
1631 if (!c->opt_no_dns_updates) {
1632 _net_ads_join_dns_updates(c, ctx, r);
1635 TALLOC_FREE(r);
1636 TALLOC_FREE( ctx );
1638 return 0;
1640 fail:
1641 /* issue an overall failure message at the end. */
1642 d_printf(_("Failed to join domain: %s\n"),
1643 r && r->out.error_string ? r->out.error_string :
1644 get_friendly_werror_msg(werr));
1645 TALLOC_FREE( ctx );
1647 return -1;
1650 /*******************************************************************
1651 ********************************************************************/
1653 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1655 #if defined(WITH_DNS_UPDATES)
1656 ADS_STRUCT *ads;
1657 ADS_STATUS status;
1658 NTSTATUS ntstatus;
1659 TALLOC_CTX *ctx;
1660 const char *hostname = NULL;
1661 const char **addrs_list = NULL;
1662 struct sockaddr_storage *addrs = NULL;
1663 int num_addrs = 0;
1664 int count;
1666 #ifdef DEVELOPER
1667 talloc_enable_leak_report();
1668 #endif
1670 if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
1671 d_fprintf(stderr, _("Refusing DNS updates with automatic "
1672 "detection of addresses in a clustered "
1673 "setup.\n"));
1674 c->display_usage = true;
1677 if (c->display_usage) {
1678 d_printf( "%s\n"
1679 "net ads dns register [hostname [IP [IP...]]]\n"
1680 " %s\n",
1681 _("Usage:"),
1682 _("Register hostname with DNS\n"));
1683 return -1;
1686 if (!(ctx = talloc_init("net_ads_dns"))) {
1687 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1688 return -1;
1691 if (argc >= 1) {
1692 hostname = argv[0];
1695 if (argc > 1) {
1696 num_addrs = argc - 1;
1697 addrs_list = &argv[1];
1698 } else if (lp_clustering()) {
1699 addrs_list = lp_cluster_addresses();
1700 num_addrs = str_list_length(addrs_list);
1703 if (num_addrs > 0) {
1704 addrs = talloc_zero_array(ctx, struct sockaddr_storage, num_addrs);
1705 if (addrs == NULL) {
1706 d_fprintf(stderr, _("Error allocating memory!\n"));
1707 talloc_free(ctx);
1708 return -1;
1712 for (count = 0; count < num_addrs; count++) {
1713 if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
1714 d_fprintf(stderr, "%s '%s'.\n",
1715 _("Cannot interpret address"),
1716 addrs_list[count]);
1717 talloc_free(ctx);
1718 return -1;
1722 status = ads_startup(c, true, &ads);
1723 if ( !ADS_ERR_OK(status) ) {
1724 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1725 TALLOC_FREE(ctx);
1726 return -1;
1729 ntstatus = net_update_dns_ext(c, ctx, ads, hostname, addrs, num_addrs, false);
1730 if (!NT_STATUS_IS_OK(ntstatus)) {
1731 d_fprintf( stderr, _("DNS update failed!\n") );
1732 ads_destroy( &ads );
1733 TALLOC_FREE( ctx );
1734 return -1;
1737 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1739 ads_destroy(&ads);
1740 TALLOC_FREE( ctx );
1742 return 0;
1743 #else
1744 d_fprintf(stderr,
1745 _("DNS update support not enabled at compile time!\n"));
1746 return -1;
1747 #endif
1750 static int net_ads_dns_unregister(struct net_context *c,
1751 int argc,
1752 const char **argv)
1754 #if defined(WITH_DNS_UPDATES)
1755 ADS_STRUCT *ads;
1756 ADS_STATUS status;
1757 NTSTATUS ntstatus;
1758 TALLOC_CTX *ctx;
1759 const char *hostname = NULL;
1761 #ifdef DEVELOPER
1762 talloc_enable_leak_report();
1763 #endif
1765 if (argc != 1) {
1766 c->display_usage = true;
1769 if (c->display_usage) {
1770 d_printf( "%s\n"
1771 "net ads dns unregister [hostname]\n"
1772 " %s\n",
1773 _("Usage:"),
1774 _("Register hostname with DNS\n"));
1775 return -1;
1778 if (!(ctx = talloc_init("net_ads_dns"))) {
1779 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1780 return -1;
1783 /* Get the hostname for un-registering */
1784 hostname = argv[0];
1786 status = ads_startup(c, true, &ads);
1787 if ( !ADS_ERR_OK(status) ) {
1788 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1789 TALLOC_FREE(ctx);
1790 return -1;
1793 ntstatus = net_update_dns_ext(c, ctx, ads, hostname, NULL, 0, true);
1794 if (!NT_STATUS_IS_OK(ntstatus)) {
1795 d_fprintf( stderr, _("DNS update failed!\n") );
1796 ads_destroy( &ads );
1797 TALLOC_FREE( ctx );
1798 return -1;
1801 d_fprintf( stderr, _("Successfully un-registered hostname from DNS\n"));
1803 ads_destroy(&ads);
1804 TALLOC_FREE( ctx );
1806 return 0;
1807 #else
1808 d_fprintf(stderr,
1809 _("DNS update support not enabled at compile time!\n"));
1810 return -1;
1811 #endif
1814 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1816 #if defined(WITH_DNS_UPDATES)
1817 DNS_ERROR err;
1819 #ifdef DEVELOPER
1820 talloc_enable_leak_report();
1821 #endif
1823 if (argc != 2 || c->display_usage) {
1824 d_printf( "%s\n"
1825 " %s\n"
1826 " %s\n",
1827 _("Usage:"),
1828 _("net ads dns gethostbyname <server> <name>\n"),
1829 _(" Look up hostname from the AD\n"
1830 " server\tName server to use\n"
1831 " name\tName to look up\n"));
1832 return -1;
1835 err = do_gethostbyname(argv[0], argv[1]);
1836 if (!ERR_DNS_IS_OK(err)) {
1837 d_printf(_("do_gethostbyname returned %s (%d)\n"),
1838 dns_errstr(err), ERROR_DNS_V(err));
1840 #endif
1841 return 0;
1844 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1846 struct functable func[] = {
1848 "register",
1849 net_ads_dns_register,
1850 NET_TRANSPORT_ADS,
1851 N_("Add host dns entry to AD"),
1852 N_("net ads dns register\n"
1853 " Add host dns entry to AD")
1856 "unregister",
1857 net_ads_dns_unregister,
1858 NET_TRANSPORT_ADS,
1859 N_("Remove host dns entry from AD"),
1860 N_("net ads dns unregister\n"
1861 " Remove host dns entry from AD")
1864 "gethostbyname",
1865 net_ads_dns_gethostbyname,
1866 NET_TRANSPORT_ADS,
1867 N_("Look up host"),
1868 N_("net ads dns gethostbyname\n"
1869 " Look up host")
1871 {NULL, NULL, 0, NULL, NULL}
1874 return net_run_function(c, argc, argv, "net ads dns", func);
1877 /*******************************************************************
1878 ********************************************************************/
1880 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1882 d_printf(_(
1883 "\nnet ads printer search <printer>"
1884 "\n\tsearch for a printer in the directory\n"
1885 "\nnet ads printer info <printer> <server>"
1886 "\n\tlookup info in directory for printer on server"
1887 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1888 "\nnet ads printer publish <printername>"
1889 "\n\tpublish printer in directory"
1890 "\n\t(note: printer name is required)\n"
1891 "\nnet ads printer remove <printername>"
1892 "\n\tremove printer from directory"
1893 "\n\t(note: printer name is required)\n"));
1894 return -1;
1897 /*******************************************************************
1898 ********************************************************************/
1900 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1902 ADS_STRUCT *ads;
1903 ADS_STATUS rc;
1904 LDAPMessage *res = NULL;
1906 if (c->display_usage) {
1907 d_printf( "%s\n"
1908 "net ads printer search\n"
1909 " %s\n",
1910 _("Usage:"),
1911 _("List printers in the AD"));
1912 return 0;
1915 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1916 return -1;
1919 rc = ads_find_printers(ads, &res);
1921 if (!ADS_ERR_OK(rc)) {
1922 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
1923 ads_msgfree(ads, res);
1924 ads_destroy(&ads);
1925 return -1;
1928 if (ads_count_replies(ads, res) == 0) {
1929 d_fprintf(stderr, _("No results found\n"));
1930 ads_msgfree(ads, res);
1931 ads_destroy(&ads);
1932 return -1;
1935 ads_dump(ads, res);
1936 ads_msgfree(ads, res);
1937 ads_destroy(&ads);
1938 return 0;
1941 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1943 ADS_STRUCT *ads;
1944 ADS_STATUS rc;
1945 const char *servername, *printername;
1946 LDAPMessage *res = NULL;
1948 if (c->display_usage) {
1949 d_printf("%s\n%s",
1950 _("Usage:"),
1951 _("net ads printer info [printername [servername]]\n"
1952 " Display printer info from AD\n"
1953 " printername\tPrinter name or wildcard\n"
1954 " servername\tName of the print server\n"));
1955 return 0;
1958 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1959 return -1;
1962 if (argc > 0) {
1963 printername = argv[0];
1964 } else {
1965 printername = "*";
1968 if (argc > 1) {
1969 servername = argv[1];
1970 } else {
1971 servername = lp_netbios_name();
1974 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1976 if (!ADS_ERR_OK(rc)) {
1977 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
1978 servername, ads_errstr(rc));
1979 ads_msgfree(ads, res);
1980 ads_destroy(&ads);
1981 return -1;
1984 if (ads_count_replies(ads, res) == 0) {
1985 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
1986 ads_msgfree(ads, res);
1987 ads_destroy(&ads);
1988 return -1;
1991 ads_dump(ads, res);
1992 ads_msgfree(ads, res);
1993 ads_destroy(&ads);
1995 return 0;
1998 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
2000 ADS_STRUCT *ads;
2001 ADS_STATUS rc;
2002 const char *servername, *printername;
2003 struct cli_state *cli = NULL;
2004 struct rpc_pipe_client *pipe_hnd = NULL;
2005 struct sockaddr_storage server_ss;
2006 NTSTATUS nt_status;
2007 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
2008 ADS_MODLIST mods = ads_init_mods(mem_ctx);
2009 char *prt_dn, *srv_dn, **srv_cn;
2010 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
2011 LDAPMessage *res = NULL;
2012 bool ok;
2014 if (argc < 1 || c->display_usage) {
2015 d_printf("%s\n%s",
2016 _("Usage:"),
2017 _("net ads printer publish <printername> [servername]\n"
2018 " Publish printer in AD\n"
2019 " printername\tName of the printer\n"
2020 " servername\tName of the print server\n"));
2021 talloc_destroy(mem_ctx);
2022 return -1;
2025 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2026 talloc_destroy(mem_ctx);
2027 return -1;
2030 printername = argv[0];
2032 if (argc == 2) {
2033 servername = argv[1];
2034 } else {
2035 servername = lp_netbios_name();
2038 /* Get printer data from SPOOLSS */
2040 ok = resolve_name(servername, &server_ss, 0x20, false);
2041 if (!ok) {
2042 d_fprintf(stderr, _("Could not find server %s\n"),
2043 servername);
2044 ads_destroy(&ads);
2045 talloc_destroy(mem_ctx);
2046 return -1;
2049 nt_status = cli_full_connection(&cli, lp_netbios_name(), servername,
2050 &server_ss, 0,
2051 "IPC$", "IPC",
2052 c->opt_user_name, c->opt_workgroup,
2053 c->opt_password ? c->opt_password : "",
2054 CLI_FULL_CONNECTION_USE_KERBEROS,
2055 SMB_SIGNING_IPC_DEFAULT);
2057 if (NT_STATUS_IS_ERR(nt_status)) {
2058 d_fprintf(stderr, _("Unable to open a connection to %s to "
2059 "obtain data for %s\n"),
2060 servername, printername);
2061 ads_destroy(&ads);
2062 talloc_destroy(mem_ctx);
2063 return -1;
2066 /* Publish on AD server */
2068 ads_find_machine_acct(ads, &res, servername);
2070 if (ads_count_replies(ads, res) == 0) {
2071 d_fprintf(stderr, _("Could not find machine account for server "
2072 "%s\n"),
2073 servername);
2074 ads_destroy(&ads);
2075 talloc_destroy(mem_ctx);
2076 return -1;
2079 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
2080 srv_cn = ldap_explode_dn(srv_dn, 1);
2082 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
2083 printername_escaped = escape_rdn_val_string_alloc(printername);
2084 if (!srv_cn_escaped || !printername_escaped) {
2085 SAFE_FREE(srv_cn_escaped);
2086 SAFE_FREE(printername_escaped);
2087 d_fprintf(stderr, _("Internal error, out of memory!"));
2088 ads_destroy(&ads);
2089 talloc_destroy(mem_ctx);
2090 return -1;
2093 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
2094 SAFE_FREE(srv_cn_escaped);
2095 SAFE_FREE(printername_escaped);
2096 d_fprintf(stderr, _("Internal error, out of memory!"));
2097 ads_destroy(&ads);
2098 talloc_destroy(mem_ctx);
2099 return -1;
2102 SAFE_FREE(srv_cn_escaped);
2103 SAFE_FREE(printername_escaped);
2105 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss, &pipe_hnd);
2106 if (!NT_STATUS_IS_OK(nt_status)) {
2107 d_fprintf(stderr, _("Unable to open a connection to the spoolss pipe on %s\n"),
2108 servername);
2109 SAFE_FREE(prt_dn);
2110 ads_destroy(&ads);
2111 talloc_destroy(mem_ctx);
2112 return -1;
2115 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
2116 printername))) {
2117 SAFE_FREE(prt_dn);
2118 ads_destroy(&ads);
2119 talloc_destroy(mem_ctx);
2120 return -1;
2123 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
2124 if (!ADS_ERR_OK(rc)) {
2125 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
2126 SAFE_FREE(prt_dn);
2127 ads_destroy(&ads);
2128 talloc_destroy(mem_ctx);
2129 return -1;
2132 d_printf("published printer\n");
2133 SAFE_FREE(prt_dn);
2134 ads_destroy(&ads);
2135 talloc_destroy(mem_ctx);
2137 return 0;
2140 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
2142 ADS_STRUCT *ads;
2143 ADS_STATUS rc;
2144 const char *servername;
2145 char *prt_dn;
2146 LDAPMessage *res = NULL;
2148 if (argc < 1 || c->display_usage) {
2149 d_printf("%s\n%s",
2150 _("Usage:"),
2151 _("net ads printer remove <printername> [servername]\n"
2152 " Remove a printer from the AD\n"
2153 " printername\tName of the printer\n"
2154 " servername\tName of the print server\n"));
2155 return -1;
2158 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2159 return -1;
2162 if (argc > 1) {
2163 servername = argv[1];
2164 } else {
2165 servername = lp_netbios_name();
2168 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
2170 if (!ADS_ERR_OK(rc)) {
2171 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
2172 ads_msgfree(ads, res);
2173 ads_destroy(&ads);
2174 return -1;
2177 if (ads_count_replies(ads, res) == 0) {
2178 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
2179 ads_msgfree(ads, res);
2180 ads_destroy(&ads);
2181 return -1;
2184 prt_dn = ads_get_dn(ads, talloc_tos(), res);
2185 ads_msgfree(ads, res);
2186 rc = ads_del_dn(ads, prt_dn);
2187 TALLOC_FREE(prt_dn);
2189 if (!ADS_ERR_OK(rc)) {
2190 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
2191 ads_destroy(&ads);
2192 return -1;
2195 ads_destroy(&ads);
2196 return 0;
2199 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
2201 struct functable func[] = {
2203 "search",
2204 net_ads_printer_search,
2205 NET_TRANSPORT_ADS,
2206 N_("Search for a printer"),
2207 N_("net ads printer search\n"
2208 " Search for a printer")
2211 "info",
2212 net_ads_printer_info,
2213 NET_TRANSPORT_ADS,
2214 N_("Display printer information"),
2215 N_("net ads printer info\n"
2216 " Display printer information")
2219 "publish",
2220 net_ads_printer_publish,
2221 NET_TRANSPORT_ADS,
2222 N_("Publish a printer"),
2223 N_("net ads printer publish\n"
2224 " Publish a printer")
2227 "remove",
2228 net_ads_printer_remove,
2229 NET_TRANSPORT_ADS,
2230 N_("Delete a printer"),
2231 N_("net ads printer remove\n"
2232 " Delete a printer")
2234 {NULL, NULL, 0, NULL, NULL}
2237 return net_run_function(c, argc, argv, "net ads printer", func);
2241 static int net_ads_password(struct net_context *c, int argc, const char **argv)
2243 ADS_STRUCT *ads;
2244 const char *auth_principal = c->opt_user_name;
2245 const char *auth_password = c->opt_password;
2246 const char *realm = NULL;
2247 const char *new_password = NULL;
2248 char *chr, *prompt;
2249 const char *user;
2250 char pwd[256] = {0};
2251 ADS_STATUS ret;
2253 if (c->display_usage) {
2254 d_printf("%s\n%s",
2255 _("Usage:"),
2256 _("net ads password <username>\n"
2257 " Change password for user\n"
2258 " username\tName of user to change password for\n"));
2259 return 0;
2262 if (c->opt_user_name == NULL || c->opt_password == NULL) {
2263 d_fprintf(stderr, _("You must supply an administrator "
2264 "username/password\n"));
2265 return -1;
2268 if (argc < 1) {
2269 d_fprintf(stderr, _("ERROR: You must say which username to "
2270 "change password for\n"));
2271 return -1;
2274 user = argv[0];
2275 if (!strchr_m(user, '@')) {
2276 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
2277 return -1;
2279 user = chr;
2282 use_in_memory_ccache();
2283 chr = strchr_m(auth_principal, '@');
2284 if (chr) {
2285 realm = ++chr;
2286 } else {
2287 realm = lp_realm();
2290 /* use the realm so we can eventually change passwords for users
2291 in realms other than default */
2292 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
2293 return -1;
2296 /* we don't actually need a full connect, but it's the easy way to
2297 fill in the KDC's addresss */
2298 ads_connect(ads);
2300 if (!ads->config.realm) {
2301 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
2302 ads_destroy(&ads);
2303 return -1;
2306 if (argv[1]) {
2307 new_password = (const char *)argv[1];
2308 } else {
2309 int rc;
2311 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
2312 return -1;
2314 rc = samba_getpass(prompt, pwd, sizeof(pwd), false, true);
2315 if (rc < 0) {
2316 return -1;
2318 new_password = pwd;
2319 free(prompt);
2322 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2323 auth_password, user, new_password, ads->auth.time_offset);
2324 memset(pwd, '\0', sizeof(pwd));
2325 if (!ADS_ERR_OK(ret)) {
2326 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2327 ads_destroy(&ads);
2328 return -1;
2331 d_printf(_("Password change for %s completed.\n"), user);
2332 ads_destroy(&ads);
2334 return 0;
2337 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2339 ADS_STRUCT *ads;
2340 char *host_principal;
2341 fstring my_name;
2342 ADS_STATUS ret;
2344 if (c->display_usage) {
2345 d_printf( "%s\n"
2346 "net ads changetrustpw\n"
2347 " %s\n",
2348 _("Usage:"),
2349 _("Change the machine account's trust password"));
2350 return 0;
2353 if (!secrets_init()) {
2354 DEBUG(1,("Failed to initialise secrets database\n"));
2355 return -1;
2358 net_use_krb_machine_account(c);
2360 use_in_memory_ccache();
2362 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2363 return -1;
2366 fstrcpy(my_name, lp_netbios_name());
2367 if (!strlower_m(my_name)) {
2368 ads_destroy(&ads);
2369 return -1;
2372 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2373 ads_destroy(&ads);
2374 return -1;
2376 d_printf(_("Changing password for principal: %s\n"), host_principal);
2378 ret = ads_change_trust_account_password(ads, host_principal);
2380 if (!ADS_ERR_OK(ret)) {
2381 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2382 ads_destroy(&ads);
2383 SAFE_FREE(host_principal);
2384 return -1;
2387 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2389 if (USE_SYSTEM_KEYTAB) {
2390 d_printf(_("Attempting to update system keytab with new password.\n"));
2391 if (ads_keytab_create_default(ads)) {
2392 d_printf(_("Failed to update system keytab.\n"));
2396 ads_destroy(&ads);
2397 SAFE_FREE(host_principal);
2399 return 0;
2403 help for net ads search
2405 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2407 d_printf(_(
2408 "\nnet ads search <expression> <attributes...>\n"
2409 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2410 "The expression is a standard LDAP search expression, and the\n"
2411 "attributes are a list of LDAP fields to show in the results.\n\n"
2412 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2414 net_common_flags_usage(c, argc, argv);
2415 return -1;
2420 general ADS search function. Useful in diagnosing problems in ADS
2422 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2424 ADS_STRUCT *ads;
2425 ADS_STATUS rc;
2426 const char *ldap_exp;
2427 const char **attrs;
2428 LDAPMessage *res = NULL;
2430 if (argc < 1 || c->display_usage) {
2431 return net_ads_search_usage(c, argc, argv);
2434 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2435 return -1;
2438 ldap_exp = argv[0];
2439 attrs = (argv + 1);
2441 rc = ads_do_search_retry(ads, ads->config.bind_path,
2442 LDAP_SCOPE_SUBTREE,
2443 ldap_exp, attrs, &res);
2444 if (!ADS_ERR_OK(rc)) {
2445 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2446 ads_destroy(&ads);
2447 return -1;
2450 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2452 /* dump the results */
2453 ads_dump(ads, res);
2455 ads_msgfree(ads, res);
2456 ads_destroy(&ads);
2458 return 0;
2463 help for net ads search
2465 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2467 d_printf(_(
2468 "\nnet ads dn <dn> <attributes...>\n"
2469 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2470 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2471 "to show in the results\n\n"
2472 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2473 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2475 net_common_flags_usage(c, argc, argv);
2476 return -1;
2481 general ADS search function. Useful in diagnosing problems in ADS
2483 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2485 ADS_STRUCT *ads;
2486 ADS_STATUS rc;
2487 const char *dn;
2488 const char **attrs;
2489 LDAPMessage *res = NULL;
2491 if (argc < 1 || c->display_usage) {
2492 return net_ads_dn_usage(c, argc, argv);
2495 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2496 return -1;
2499 dn = argv[0];
2500 attrs = (argv + 1);
2502 rc = ads_do_search_all(ads, dn,
2503 LDAP_SCOPE_BASE,
2504 "(objectclass=*)", attrs, &res);
2505 if (!ADS_ERR_OK(rc)) {
2506 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2507 ads_destroy(&ads);
2508 return -1;
2511 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2513 /* dump the results */
2514 ads_dump(ads, res);
2516 ads_msgfree(ads, res);
2517 ads_destroy(&ads);
2519 return 0;
2523 help for net ads sid search
2525 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2527 d_printf(_(
2528 "\nnet ads sid <sid> <attributes...>\n"
2529 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2530 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2531 "to show in the results\n\n"
2532 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2534 net_common_flags_usage(c, argc, argv);
2535 return -1;
2540 general ADS search function. Useful in diagnosing problems in ADS
2542 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2544 ADS_STRUCT *ads;
2545 ADS_STATUS rc;
2546 const char *sid_string;
2547 const char **attrs;
2548 LDAPMessage *res = NULL;
2549 struct dom_sid sid;
2551 if (argc < 1 || c->display_usage) {
2552 return net_ads_sid_usage(c, argc, argv);
2555 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2556 return -1;
2559 sid_string = argv[0];
2560 attrs = (argv + 1);
2562 if (!string_to_sid(&sid, sid_string)) {
2563 d_fprintf(stderr, _("could not convert sid\n"));
2564 ads_destroy(&ads);
2565 return -1;
2568 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2569 if (!ADS_ERR_OK(rc)) {
2570 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2571 ads_destroy(&ads);
2572 return -1;
2575 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2577 /* dump the results */
2578 ads_dump(ads, res);
2580 ads_msgfree(ads, res);
2581 ads_destroy(&ads);
2583 return 0;
2586 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2588 int ret;
2589 ADS_STRUCT *ads;
2591 if (c->display_usage) {
2592 d_printf( "%s\n"
2593 "net ads keytab flush\n"
2594 " %s\n",
2595 _("Usage:"),
2596 _("Delete the whole keytab"));
2597 return 0;
2600 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2601 return -1;
2603 ret = ads_keytab_flush(ads);
2604 ads_destroy(&ads);
2605 return ret;
2608 static int net_ads_keytab_add(struct net_context *c,
2609 int argc,
2610 const char **argv,
2611 bool update_ads)
2613 int i;
2614 int ret = 0;
2615 ADS_STRUCT *ads;
2617 if (c->display_usage) {
2618 d_printf("%s\n%s",
2619 _("Usage:"),
2620 _("net ads keytab add <principal> [principal ...]\n"
2621 " Add principals to local keytab\n"
2622 " principal\tKerberos principal to add to "
2623 "keytab\n"));
2624 return 0;
2627 d_printf(_("Processing principals to add...\n"));
2628 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2629 return -1;
2631 for (i = 0; i < argc; i++) {
2632 ret |= ads_keytab_add_entry(ads, argv[i], update_ads);
2634 ads_destroy(&ads);
2635 return ret;
2638 static int net_ads_keytab_add_default(struct net_context *c,
2639 int argc,
2640 const char **argv)
2642 return net_ads_keytab_add(c, argc, argv, false);
2645 static int net_ads_keytab_add_update_ads(struct net_context *c,
2646 int argc,
2647 const char **argv)
2649 return net_ads_keytab_add(c, argc, argv, true);
2652 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2654 ADS_STRUCT *ads;
2655 int ret;
2657 if (c->display_usage) {
2658 d_printf( "%s\n"
2659 "net ads keytab create\n"
2660 " %s\n",
2661 _("Usage:"),
2662 _("Create new default keytab"));
2663 return 0;
2666 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2667 return -1;
2669 ret = ads_keytab_create_default(ads);
2670 ads_destroy(&ads);
2671 return ret;
2674 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2676 const char *keytab = NULL;
2678 if (c->display_usage) {
2679 d_printf("%s\n%s",
2680 _("Usage:"),
2681 _("net ads keytab list [keytab]\n"
2682 " List a local keytab\n"
2683 " keytab\tKeytab to list\n"));
2684 return 0;
2687 if (argc >= 1) {
2688 keytab = argv[0];
2691 return ads_keytab_list(keytab);
2695 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2697 struct functable func[] = {
2699 "add",
2700 net_ads_keytab_add_default,
2701 NET_TRANSPORT_ADS,
2702 N_("Add a service principal"),
2703 N_("net ads keytab add\n"
2704 " Add a service principal, updates keytab file only.")
2707 "add_update_ads",
2708 net_ads_keytab_add_update_ads,
2709 NET_TRANSPORT_ADS,
2710 N_("Add a service principal"),
2711 N_("net ads keytab add_update_ads\n"
2712 " Add a service principal, depending on the param passed may update ADS computer object in addition to the keytab file.")
2715 "create",
2716 net_ads_keytab_create,
2717 NET_TRANSPORT_ADS,
2718 N_("Create a fresh keytab"),
2719 N_("net ads keytab create\n"
2720 " Create a fresh keytab or update exising one.")
2723 "flush",
2724 net_ads_keytab_flush,
2725 NET_TRANSPORT_ADS,
2726 N_("Remove all keytab entries"),
2727 N_("net ads keytab flush\n"
2728 " Remove all keytab entries")
2731 "list",
2732 net_ads_keytab_list,
2733 NET_TRANSPORT_ADS,
2734 N_("List a keytab"),
2735 N_("net ads keytab list\n"
2736 " List a keytab")
2738 {NULL, NULL, 0, NULL, NULL}
2741 if (!USE_KERBEROS_KEYTAB) {
2742 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2743 "keytab method to use keytab functions.\n"));
2746 return net_run_function(c, argc, argv, "net ads keytab", func);
2749 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2751 int ret = -1;
2753 if (c->display_usage) {
2754 d_printf( "%s\n"
2755 "net ads kerberos renew\n"
2756 " %s\n",
2757 _("Usage:"),
2758 _("Renew TGT from existing credential cache"));
2759 return 0;
2762 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2763 if (ret) {
2764 d_printf(_("failed to renew kerberos ticket: %s\n"),
2765 error_message(ret));
2767 return ret;
2770 static int net_ads_kerberos_pac_common(struct net_context *c, int argc, const char **argv,
2771 struct PAC_DATA_CTR **pac_data_ctr)
2773 NTSTATUS status;
2774 int ret = -1;
2775 const char *impersonate_princ_s = NULL;
2776 const char *local_service = NULL;
2777 int i;
2779 for (i=0; i<argc; i++) {
2780 if (strnequal(argv[i], "impersonate", strlen("impersonate"))) {
2781 impersonate_princ_s = get_string_param(argv[i]);
2782 if (impersonate_princ_s == NULL) {
2783 return -1;
2786 if (strnequal(argv[i], "local_service", strlen("local_service"))) {
2787 local_service = get_string_param(argv[i]);
2788 if (local_service == NULL) {
2789 return -1;
2794 if (local_service == NULL) {
2795 local_service = talloc_asprintf(c, "%s$@%s",
2796 lp_netbios_name(), lp_realm());
2797 if (local_service == NULL) {
2798 goto out;
2802 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2804 status = kerberos_return_pac(c,
2805 c->opt_user_name,
2806 c->opt_password,
2808 NULL,
2809 NULL,
2810 NULL,
2811 true,
2812 true,
2813 2592000, /* one month */
2814 impersonate_princ_s,
2815 local_service,
2816 pac_data_ctr);
2817 if (!NT_STATUS_IS_OK(status)) {
2818 d_printf(_("failed to query kerberos PAC: %s\n"),
2819 nt_errstr(status));
2820 goto out;
2823 ret = 0;
2824 out:
2825 return ret;
2828 static int net_ads_kerberos_pac_dump(struct net_context *c, int argc, const char **argv)
2830 struct PAC_DATA_CTR *pac_data_ctr = NULL;
2831 int i;
2832 int ret = -1;
2833 enum PAC_TYPE type = 0;
2835 if (c->display_usage) {
2836 d_printf( "%s\n"
2837 "net ads kerberos pac dump [impersonate=string] [local_service=string] [pac_buffer_type=int]\n"
2838 " %s\n",
2839 _("Usage:"),
2840 _("Dump the Kerberos PAC"));
2841 return -1;
2844 for (i=0; i<argc; i++) {
2845 if (strnequal(argv[i], "pac_buffer_type", strlen("pac_buffer_type"))) {
2846 type = get_int_param(argv[i]);
2850 ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
2851 if (ret) {
2852 return ret;
2855 if (type == 0) {
2857 char *s = NULL;
2859 s = NDR_PRINT_STRUCT_STRING(c, PAC_DATA,
2860 pac_data_ctr->pac_data);
2861 if (s != NULL) {
2862 d_printf(_("The Pac: %s\n"), s);
2863 talloc_free(s);
2866 return 0;
2869 for (i=0; i < pac_data_ctr->pac_data->num_buffers; i++) {
2871 char *s = NULL;
2873 if (pac_data_ctr->pac_data->buffers[i].type != type) {
2874 continue;
2877 s = NDR_PRINT_UNION_STRING(c, PAC_INFO, type,
2878 pac_data_ctr->pac_data->buffers[i].info);
2879 if (s != NULL) {
2880 d_printf(_("The Pac: %s\n"), s);
2881 talloc_free(s);
2883 break;
2886 return 0;
2889 static int net_ads_kerberos_pac_save(struct net_context *c, int argc, const char **argv)
2891 struct PAC_DATA_CTR *pac_data_ctr = NULL;
2892 char *filename = NULL;
2893 int ret = -1;
2894 int i;
2896 if (c->display_usage) {
2897 d_printf( "%s\n"
2898 "net ads kerberos pac save [impersonate=string] [local_service=string] [filename=string]\n"
2899 " %s\n",
2900 _("Usage:"),
2901 _("Save the Kerberos PAC"));
2902 return -1;
2905 for (i=0; i<argc; i++) {
2906 if (strnequal(argv[i], "filename", strlen("filename"))) {
2907 filename = get_string_param(argv[i]);
2908 if (filename == NULL) {
2909 return -1;
2914 ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
2915 if (ret) {
2916 return ret;
2919 if (filename == NULL) {
2920 d_printf(_("please define \"filename=<filename>\" to save the PAC\n"));
2921 return -1;
2924 /* save the raw format */
2925 if (!file_save(filename, pac_data_ctr->pac_blob.data, pac_data_ctr->pac_blob.length)) {
2926 d_printf(_("failed to save PAC in %s\n"), filename);
2927 return -1;
2930 return 0;
2933 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2935 struct functable func[] = {
2937 "dump",
2938 net_ads_kerberos_pac_dump,
2939 NET_TRANSPORT_ADS,
2940 N_("Dump Kerberos PAC"),
2941 N_("net ads kerberos pac dump\n"
2942 " Dump a Kerberos PAC to stdout")
2945 "save",
2946 net_ads_kerberos_pac_save,
2947 NET_TRANSPORT_ADS,
2948 N_("Save Kerberos PAC"),
2949 N_("net ads kerberos pac save\n"
2950 " Save a Kerberos PAC in a file")
2953 {NULL, NULL, 0, NULL, NULL}
2956 return net_run_function(c, argc, argv, "net ads kerberos pac", func);
2959 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2961 TALLOC_CTX *mem_ctx = NULL;
2962 int ret = -1;
2963 NTSTATUS status;
2965 if (c->display_usage) {
2966 d_printf( "%s\n"
2967 "net ads kerberos kinit\n"
2968 " %s\n",
2969 _("Usage:"),
2970 _("Get Ticket Granting Ticket (TGT) for the user"));
2971 return 0;
2974 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2975 if (!mem_ctx) {
2976 goto out;
2979 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2981 ret = kerberos_kinit_password_ext(c->opt_user_name,
2982 c->opt_password,
2984 NULL,
2985 NULL,
2986 NULL,
2987 true,
2988 true,
2989 2592000, /* one month */
2990 &status);
2991 if (ret) {
2992 d_printf(_("failed to kinit password: %s\n"),
2993 nt_errstr(status));
2995 out:
2996 return ret;
2999 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3001 struct functable func[] = {
3003 "kinit",
3004 net_ads_kerberos_kinit,
3005 NET_TRANSPORT_ADS,
3006 N_("Retrieve Ticket Granting Ticket (TGT)"),
3007 N_("net ads kerberos kinit\n"
3008 " Receive Ticket Granting Ticket (TGT)")
3011 "renew",
3012 net_ads_kerberos_renew,
3013 NET_TRANSPORT_ADS,
3014 N_("Renew Ticket Granting Ticket from credential cache"),
3015 N_("net ads kerberos renew\n"
3016 " Renew Ticket Granting Ticket (TGT) from "
3017 "credential cache")
3020 "pac",
3021 net_ads_kerberos_pac,
3022 NET_TRANSPORT_ADS,
3023 N_("Dump Kerberos PAC"),
3024 N_("net ads kerberos pac\n"
3025 " Dump Kerberos PAC")
3027 {NULL, NULL, 0, NULL, NULL}
3030 return net_run_function(c, argc, argv, "net ads kerberos", func);
3033 static int net_ads_setspn_list(struct net_context *c, int argc, const char **argv)
3035 int ret = 0;
3036 bool ok = false;
3037 ADS_STRUCT *ads = NULL;
3038 if (c->display_usage) {
3039 d_printf("%s\n%s",
3040 _("Usage:"),
3041 _("net ads setspn list <machinename>\n"));
3042 ret = 0;
3043 goto done;
3045 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3046 ret = -1;
3047 goto done;
3049 if (argc) {
3050 ok = ads_setspn_list(ads, argv[0]);
3051 } else {
3052 ok = ads_setspn_list(ads, lp_netbios_name());
3054 if (!ok) {
3055 ret = -1;
3057 done:
3058 if (ads) {
3059 ads_destroy(&ads);
3061 return ret;
3064 static int net_ads_setspn_add(struct net_context *c, int argc, const char **argv)
3066 int ret = 0;
3067 bool ok = false;
3068 ADS_STRUCT *ads = NULL;
3069 if (c->display_usage || argc < 1) {
3070 d_printf("%s\n%s",
3071 _("Usage:"),
3072 _("net ads setspn add <machinename> SPN\n"));
3073 ret = 0;
3074 goto done;
3076 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3077 ret = -1;
3078 goto done;
3080 if (argc > 1) {
3081 ok = ads_setspn_add(ads, argv[0], argv[1]);
3082 } else {
3083 ok = ads_setspn_add(ads, lp_netbios_name(), argv[0]);
3085 if (!ok) {
3086 ret = -1;
3088 done:
3089 if (ads) {
3090 ads_destroy(&ads);
3092 return ret;
3095 static int net_ads_setspn_delete(struct net_context *c, int argc, const char **argv)
3097 int ret = 0;
3098 bool ok = false;
3099 ADS_STRUCT *ads = NULL;
3100 if (c->display_usage || argc < 1) {
3101 d_printf("%s\n%s",
3102 _("Usage:"),
3103 _("net ads setspn delete <machinename> SPN\n"));
3104 ret = 0;
3105 goto done;
3107 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3108 ret = -1;
3109 goto done;
3111 if (argc > 1) {
3112 ok = ads_setspn_delete(ads, argv[0], argv[1]);
3113 } else {
3114 ok = ads_setspn_delete(ads, lp_netbios_name(), argv[0]);
3116 if (!ok) {
3117 ret = -1;
3119 done:
3120 if (ads) {
3121 ads_destroy(&ads);
3123 return ret;
3126 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
3128 struct functable func[] = {
3130 "list",
3131 net_ads_setspn_list,
3132 NET_TRANSPORT_ADS,
3133 N_("List Service Principal Names (SPN)"),
3134 N_("net ads setspn list machine\n"
3135 " List Service Principal Names (SPN)")
3138 "add",
3139 net_ads_setspn_add,
3140 NET_TRANSPORT_ADS,
3141 N_("Add Service Principal Names (SPN)"),
3142 N_("net ads setspn add machine spn\n"
3143 " Add Service Principal Names (SPN)")
3146 "delete",
3147 net_ads_setspn_delete,
3148 NET_TRANSPORT_ADS,
3149 N_("Delete Service Principal Names (SPN)"),
3150 N_("net ads setspn delete machine spn\n"
3151 " Delete Service Principal Names (SPN)")
3153 {NULL, NULL, 0, NULL, NULL}
3156 return net_run_function(c, argc, argv, "net ads setspn", func);
3159 static int net_ads_enctype_lookup_account(struct net_context *c,
3160 ADS_STRUCT *ads,
3161 const char *account,
3162 LDAPMessage **res,
3163 const char **enctype_str)
3165 const char *filter;
3166 const char *attrs[] = {
3167 "msDS-SupportedEncryptionTypes",
3168 NULL
3170 int count;
3171 int ret = -1;
3172 ADS_STATUS status;
3174 filter = talloc_asprintf(c, "(&(objectclass=user)(sAMAccountName=%s))",
3175 account);
3176 if (filter == NULL) {
3177 goto done;
3180 status = ads_search(ads, res, filter, attrs);
3181 if (!ADS_ERR_OK(status)) {
3182 d_printf(_("no account found with filter: %s\n"), filter);
3183 goto done;
3186 count = ads_count_replies(ads, *res);
3187 switch (count) {
3188 case 1:
3189 break;
3190 case 0:
3191 d_printf(_("no account found with filter: %s\n"), filter);
3192 goto done;
3193 default:
3194 d_printf(_("multiple accounts found with filter: %s\n"), filter);
3195 goto done;
3198 if (enctype_str) {
3199 *enctype_str = ads_pull_string(ads, c, *res,
3200 "msDS-SupportedEncryptionTypes");
3201 if (*enctype_str == NULL) {
3202 d_printf(_("no msDS-SupportedEncryptionTypes attribute found\n"));
3203 goto done;
3207 ret = 0;
3208 done:
3209 return ret;
3212 static void net_ads_enctype_dump_enctypes(const char *username,
3213 const char *enctype_str)
3215 int enctypes = atoi(enctype_str);
3217 d_printf(_("'%s' uses \"msDS-SupportedEncryptionTypes\": %d (0x%08x)\n"),
3218 username, enctypes, enctypes);
3220 printf("[%s] 0x%08x DES-CBC-CRC\n",
3221 enctypes & ENC_CRC32 ? "X" : " ",
3222 ENC_CRC32);
3223 printf("[%s] 0x%08x DES-CBC-MD5\n",
3224 enctypes & ENC_RSA_MD5 ? "X" : " ",
3225 ENC_RSA_MD5);
3226 printf("[%s] 0x%08x RC4-HMAC\n",
3227 enctypes & ENC_RC4_HMAC_MD5 ? "X" : " ",
3228 ENC_RC4_HMAC_MD5);
3229 printf("[%s] 0x%08x AES128-CTS-HMAC-SHA1-96\n",
3230 enctypes & ENC_HMAC_SHA1_96_AES128 ? "X" : " ",
3231 ENC_HMAC_SHA1_96_AES128);
3232 printf("[%s] 0x%08x AES256-CTS-HMAC-SHA1-96\n",
3233 enctypes & ENC_HMAC_SHA1_96_AES256 ? "X" : " ",
3234 ENC_HMAC_SHA1_96_AES256);
3237 static int net_ads_enctypes_list(struct net_context *c, int argc, const char **argv)
3239 int ret = -1;
3240 ADS_STATUS status;
3241 ADS_STRUCT *ads = NULL;
3242 LDAPMessage *res = NULL;
3243 const char *str = NULL;
3245 if (c->display_usage || (argc < 1)) {
3246 d_printf( "%s\n"
3247 "net ads enctypes list\n"
3248 " %s\n",
3249 _("Usage:"),
3250 _("List supported enctypes"));
3251 return 0;
3254 status = ads_startup(c, false, &ads);
3255 if (!ADS_ERR_OK(status)) {
3256 printf("startup failed\n");
3257 return ret;
3260 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3261 if (ret) {
3262 goto done;
3265 net_ads_enctype_dump_enctypes(argv[0], str);
3267 ret = 0;
3268 done:
3269 ads_msgfree(ads, res);
3270 ads_destroy(&ads);
3272 return ret;
3275 static int net_ads_enctypes_set(struct net_context *c, int argc, const char **argv)
3277 int ret = -1;
3278 ADS_STATUS status;
3279 ADS_STRUCT *ads;
3280 LDAPMessage *res = NULL;
3281 const char *etype_list_str;
3282 const char *dn;
3283 ADS_MODLIST mods;
3284 uint32_t etype_list;
3285 const char *str;
3287 if (c->display_usage || argc < 1) {
3288 d_printf( "%s\n"
3289 "net ads enctypes set <sAMAccountName> [enctypes]\n"
3290 " %s\n",
3291 _("Usage:"),
3292 _("Set supported enctypes"));
3293 return 0;
3296 status = ads_startup(c, false, &ads);
3297 if (!ADS_ERR_OK(status)) {
3298 printf("startup failed\n");
3299 return ret;
3302 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3303 if (ret) {
3304 goto done;
3307 dn = ads_get_dn(ads, c, res);
3308 if (dn == NULL) {
3309 goto done;
3312 etype_list = ENC_CRC32 | ENC_RSA_MD5 | ENC_RC4_HMAC_MD5;
3313 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
3314 etype_list |= ENC_HMAC_SHA1_96_AES128;
3315 #endif
3316 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
3317 etype_list |= ENC_HMAC_SHA1_96_AES256;
3318 #endif
3320 if (argv[1] != NULL) {
3321 sscanf(argv[1], "%i", &etype_list);
3324 etype_list_str = talloc_asprintf(c, "%d", etype_list);
3325 if (!etype_list_str) {
3326 goto done;
3329 mods = ads_init_mods(c);
3330 if (!mods) {
3331 goto done;
3334 status = ads_mod_str(c, &mods, "msDS-SupportedEncryptionTypes",
3335 etype_list_str);
3336 if (!ADS_ERR_OK(status)) {
3337 goto done;
3340 status = ads_gen_mod(ads, dn, mods);
3341 if (!ADS_ERR_OK(status)) {
3342 d_printf(_("failed to add msDS-SupportedEncryptionTypes: %s\n"),
3343 ads_errstr(status));
3344 goto done;
3347 ads_msgfree(ads, res);
3349 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3350 if (ret) {
3351 goto done;
3354 net_ads_enctype_dump_enctypes(argv[0], str);
3356 ret = 0;
3357 done:
3358 ads_msgfree(ads, res);
3359 ads_destroy(&ads);
3361 return ret;
3364 static int net_ads_enctypes_delete(struct net_context *c, int argc, const char **argv)
3366 int ret = -1;
3367 ADS_STATUS status;
3368 ADS_STRUCT *ads;
3369 LDAPMessage *res = NULL;
3370 const char *dn;
3371 ADS_MODLIST mods;
3373 if (c->display_usage || argc < 1) {
3374 d_printf( "%s\n"
3375 "net ads enctypes delete <sAMAccountName>\n"
3376 " %s\n",
3377 _("Usage:"),
3378 _("Delete supported enctypes"));
3379 return 0;
3382 status = ads_startup(c, false, &ads);
3383 if (!ADS_ERR_OK(status)) {
3384 printf("startup failed\n");
3385 return ret;
3388 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3389 if (ret) {
3390 goto done;
3393 dn = ads_get_dn(ads, c, res);
3394 if (dn == NULL) {
3395 goto done;
3398 mods = ads_init_mods(c);
3399 if (!mods) {
3400 goto done;
3403 status = ads_mod_str(c, &mods, "msDS-SupportedEncryptionTypes", NULL);
3404 if (!ADS_ERR_OK(status)) {
3405 goto done;
3408 status = ads_gen_mod(ads, dn, mods);
3409 if (!ADS_ERR_OK(status)) {
3410 d_printf(_("failed to remove msDS-SupportedEncryptionTypes: %s\n"),
3411 ads_errstr(status));
3412 goto done;
3415 ret = 0;
3417 done:
3418 ads_msgfree(ads, res);
3419 ads_destroy(&ads);
3420 return ret;
3423 static int net_ads_enctypes(struct net_context *c, int argc, const char **argv)
3425 struct functable func[] = {
3427 "list",
3428 net_ads_enctypes_list,
3429 NET_TRANSPORT_ADS,
3430 N_("List the supported encryption types"),
3431 N_("net ads enctypes list\n"
3432 " List the supported encryption types")
3435 "set",
3436 net_ads_enctypes_set,
3437 NET_TRANSPORT_ADS,
3438 N_("Set the supported encryption types"),
3439 N_("net ads enctypes set\n"
3440 " Set the supported encryption types")
3443 "delete",
3444 net_ads_enctypes_delete,
3445 NET_TRANSPORT_ADS,
3446 N_("Delete the supported encryption types"),
3447 N_("net ads enctypes delete\n"
3448 " Delete the supported encryption types")
3451 {NULL, NULL, 0, NULL, NULL}
3454 return net_run_function(c, argc, argv, "net ads enctypes", func);
3458 int net_ads(struct net_context *c, int argc, const char **argv)
3460 struct functable func[] = {
3462 "info",
3463 net_ads_info,
3464 NET_TRANSPORT_ADS,
3465 N_("Display details on remote ADS server"),
3466 N_("net ads info\n"
3467 " Display details on remote ADS server")
3470 "join",
3471 net_ads_join,
3472 NET_TRANSPORT_ADS,
3473 N_("Join the local machine to ADS realm"),
3474 N_("net ads join\n"
3475 " Join the local machine to ADS realm")
3478 "testjoin",
3479 net_ads_testjoin,
3480 NET_TRANSPORT_ADS,
3481 N_("Validate machine account"),
3482 N_("net ads testjoin\n"
3483 " Validate machine account")
3486 "leave",
3487 net_ads_leave,
3488 NET_TRANSPORT_ADS,
3489 N_("Remove the local machine from ADS"),
3490 N_("net ads leave\n"
3491 " Remove the local machine from ADS")
3494 "status",
3495 net_ads_status,
3496 NET_TRANSPORT_ADS,
3497 N_("Display machine account details"),
3498 N_("net ads status\n"
3499 " Display machine account details")
3502 "user",
3503 net_ads_user,
3504 NET_TRANSPORT_ADS,
3505 N_("List/modify users"),
3506 N_("net ads user\n"
3507 " List/modify users")
3510 "group",
3511 net_ads_group,
3512 NET_TRANSPORT_ADS,
3513 N_("List/modify groups"),
3514 N_("net ads group\n"
3515 " List/modify groups")
3518 "dns",
3519 net_ads_dns,
3520 NET_TRANSPORT_ADS,
3521 N_("Issue dynamic DNS update"),
3522 N_("net ads dns\n"
3523 " Issue dynamic DNS update")
3526 "password",
3527 net_ads_password,
3528 NET_TRANSPORT_ADS,
3529 N_("Change user passwords"),
3530 N_("net ads password\n"
3531 " Change user passwords")
3534 "changetrustpw",
3535 net_ads_changetrustpw,
3536 NET_TRANSPORT_ADS,
3537 N_("Change trust account password"),
3538 N_("net ads changetrustpw\n"
3539 " Change trust account password")
3542 "printer",
3543 net_ads_printer,
3544 NET_TRANSPORT_ADS,
3545 N_("List/modify printer entries"),
3546 N_("net ads printer\n"
3547 " List/modify printer entries")
3550 "search",
3551 net_ads_search,
3552 NET_TRANSPORT_ADS,
3553 N_("Issue LDAP search using filter"),
3554 N_("net ads search\n"
3555 " Issue LDAP search using filter")
3558 "dn",
3559 net_ads_dn,
3560 NET_TRANSPORT_ADS,
3561 N_("Issue LDAP search by DN"),
3562 N_("net ads dn\n"
3563 " Issue LDAP search by DN")
3566 "sid",
3567 net_ads_sid,
3568 NET_TRANSPORT_ADS,
3569 N_("Issue LDAP search by SID"),
3570 N_("net ads sid\n"
3571 " Issue LDAP search by SID")
3574 "workgroup",
3575 net_ads_workgroup,
3576 NET_TRANSPORT_ADS,
3577 N_("Display workgroup name"),
3578 N_("net ads workgroup\n"
3579 " Display the workgroup name")
3582 "lookup",
3583 net_ads_lookup,
3584 NET_TRANSPORT_ADS,
3585 N_("Perform CLDAP query on DC"),
3586 N_("net ads lookup\n"
3587 " Find the ADS DC using CLDAP lookups")
3590 "keytab",
3591 net_ads_keytab,
3592 NET_TRANSPORT_ADS,
3593 N_("Manage local keytab file"),
3594 N_("net ads keytab\n"
3595 " Manage local keytab file")
3598 "setspn",
3599 net_ads_setspn,
3600 NET_TRANSPORT_ADS,
3601 N_("Manage Service Principal Names (SPN)s"),
3602 N_("net ads spnset\n"
3603 " Manage Service Principal Names (SPN)s")
3606 "gpo",
3607 net_ads_gpo,
3608 NET_TRANSPORT_ADS,
3609 N_("Manage group policy objects"),
3610 N_("net ads gpo\n"
3611 " Manage group policy objects")
3614 "kerberos",
3615 net_ads_kerberos,
3616 NET_TRANSPORT_ADS,
3617 N_("Manage kerberos keytab"),
3618 N_("net ads kerberos\n"
3619 " Manage kerberos keytab")
3622 "enctypes",
3623 net_ads_enctypes,
3624 NET_TRANSPORT_ADS,
3625 N_("List/modify supported encryption types"),
3626 N_("net ads enctypes\n"
3627 " List/modify enctypes")
3629 {NULL, NULL, 0, NULL, NULL}
3632 return net_run_function(c, argc, argv, "net ads", func);
3635 #else
3637 static int net_ads_noads(void)
3639 d_fprintf(stderr, _("ADS support not compiled in\n"));
3640 return -1;
3643 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
3645 return net_ads_noads();
3648 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3650 return net_ads_noads();
3653 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
3655 return net_ads_noads();
3658 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
3660 return net_ads_noads();
3663 int net_ads_join(struct net_context *c, int argc, const char **argv)
3665 return net_ads_noads();
3668 int net_ads_user(struct net_context *c, int argc, const char **argv)
3670 return net_ads_noads();
3673 int net_ads_group(struct net_context *c, int argc, const char **argv)
3675 return net_ads_noads();
3678 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
3680 return net_ads_noads();
3683 /* this one shouldn't display a message */
3684 int net_ads_check(struct net_context *c)
3686 return -1;
3689 int net_ads_check_our_domain(struct net_context *c)
3691 return -1;
3694 int net_ads(struct net_context *c, int argc, const char **argv)
3696 return net_ads_noads();
3699 #endif /* HAVE_ADS */