s3: net: implement json output for ads info
[Samba.git] / source3 / utils / net_ads.c
blob416a7b8d9273a5a13474ca1ee15b6796ef1da63a
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 "libsmb/namequery.h"
26 #include "rpc_client/cli_pipe.h"
27 #include "librpc/gen_ndr/ndr_krb5pac.h"
28 #include "../librpc/gen_ndr/ndr_spoolss.h"
29 #include "nsswitch/libwbclient/wbclient.h"
30 #include "ads.h"
31 #include "libads/cldap.h"
32 #include "../lib/addns/dnsquery.h"
33 #include "../libds/common/flags.h"
34 #include "librpc/gen_ndr/libnet_join.h"
35 #include "libnet/libnet_join.h"
36 #include "smb_krb5.h"
37 #include "secrets.h"
38 #include "krb5_env.h"
39 #include "../libcli/security/security.h"
40 #include "libsmb/libsmb.h"
41 #include "lib/param/loadparm.h"
42 #include "utils/net_dns.h"
44 #ifdef HAVE_ADS
46 /* when we do not have sufficient input parameters to contact a remote domain
47 * we always fall back to our own realm - Guenther*/
49 static const char *assume_own_realm(struct net_context *c)
51 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
52 return lp_realm();
55 return NULL;
59 do a cldap netlogon query
61 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
63 char addr[INET6_ADDRSTRLEN];
64 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
66 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
68 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads->ldap.ss, ads->server.realm, &reply ) ) {
69 d_fprintf(stderr, _("CLDAP query failed!\n"));
70 return -1;
73 d_printf(_("Information for Domain Controller: %s\n\n"),
74 addr);
76 d_printf(_("Response Type: "));
77 switch (reply.command) {
78 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
79 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
80 break;
81 case LOGON_SAM_LOGON_RESPONSE_EX:
82 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
83 break;
84 default:
85 d_printf("0x%x\n", reply.command);
86 break;
89 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
91 d_printf(_("Flags:\n"
92 "\tIs a PDC: %s\n"
93 "\tIs a GC of the forest: %s\n"
94 "\tIs an LDAP server: %s\n"
95 "\tSupports DS: %s\n"
96 "\tIs running a KDC: %s\n"
97 "\tIs running time services: %s\n"
98 "\tIs the closest DC: %s\n"
99 "\tIs writable: %s\n"
100 "\tHas a hardware clock: %s\n"
101 "\tIs a non-domain NC serviced by LDAP server: %s\n"
102 "\tIs NT6 DC that has some secrets: %s\n"
103 "\tIs NT6 DC that has all secrets: %s\n"
104 "\tRuns Active Directory Web Services: %s\n"
105 "\tRuns on Windows 2012 or later: %s\n"),
106 (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
107 (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
108 (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
109 (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
110 (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
111 (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
112 (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
113 (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
114 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
115 (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
116 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
117 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"),
118 (reply.server_type & NBT_SERVER_ADS_WEB_SERVICE) ? _("yes") : _("no"),
119 (reply.server_type & NBT_SERVER_DS_8) ? _("yes") : _("no"));
122 printf(_("Forest:\t\t\t%s\n"), reply.forest);
123 printf(_("Domain:\t\t\t%s\n"), reply.dns_domain);
124 printf(_("Domain Controller:\t%s\n"), reply.pdc_dns_name);
126 printf(_("Pre-Win2k Domain:\t%s\n"), reply.domain_name);
127 printf(_("Pre-Win2k Hostname:\t%s\n"), reply.pdc_name);
129 if (*reply.user_name) printf(_("User name:\t%s\n"), reply.user_name);
131 printf(_("Server Site Name :\t\t%s\n"), reply.server_site);
132 printf(_("Client Site Name :\t\t%s\n"), reply.client_site);
134 d_printf(_("NT Version: %d\n"), reply.nt_version);
135 d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
136 d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
138 return 0;
142 this implements the CLDAP based netlogon lookup requests
143 for finding the domain controller of a ADS domain
145 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
147 ADS_STRUCT *ads;
148 int ret;
150 if (c->display_usage) {
151 d_printf("%s\n"
152 "net ads lookup\n"
153 " %s",
154 _("Usage:"),
155 _("Find the ADS DC using CLDAP lookup.\n"));
156 return 0;
159 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
160 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
161 ads_destroy(&ads);
162 return -1;
165 if (!ads->config.realm) {
166 ads->config.realm = discard_const_p(char, c->opt_target_workgroup);
167 ads->ldap.port = 389;
170 ret = net_ads_cldap_netlogon(c, ads);
171 ads_destroy(&ads);
172 return ret;
176 #ifdef HAVE_JANSSON
177 #include <jansson.h>
178 #include "audit_logging.h" /* various JSON helpers */
179 #include "auth/common_auth.h"
182 * note: JSON output deliberately bypasses gettext so as to provide the same
183 * output irrespective of the locale.
186 static int net_ads_info_json(ADS_STRUCT *ads)
188 int ret = 0;
189 char addr[INET6_ADDRSTRLEN];
190 time_t pass_time;
191 struct json_object jsobj = json_new_object();
192 TALLOC_CTX *ctx = NULL;
193 char *json = NULL;
195 if (json_is_invalid(&jsobj)) {
196 d_fprintf(stderr, _("error setting up JSON value\n"));
198 goto failure;
201 pass_time = secrets_fetch_pass_last_set_time(ads->server.workgroup);
203 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
205 ret = json_add_string (&jsobj, "LDAP server", addr);
206 if (ret != 0) {
207 goto failure;
210 ret = json_add_string (&jsobj, "LDAP server name",
211 ads->config.ldap_server_name);
212 if (ret != 0) {
213 goto failure;
216 ret = json_add_string (&jsobj, "Realm", ads->config.realm);
217 if (ret != 0) {
218 goto failure;
221 ret = json_add_string (&jsobj, "Bind Path", ads->config.bind_path);
222 if (ret != 0) {
223 goto failure;
226 ret = json_add_int (&jsobj, "LDAP port", ads->ldap.port);
227 if (ret != 0) {
228 goto failure;
231 ret = json_add_int (&jsobj, "Server time", ads->config.current_time);
232 if (ret != 0) {
233 goto failure;
236 ret = json_add_string (&jsobj, "KDC server", ads->auth.kdc_server);
237 if (ret != 0) {
238 goto failure;
241 ret = json_add_int (&jsobj, "Server time offset",
242 ads->auth.time_offset);
243 if (ret != 0) {
244 goto failure;
247 ret = json_add_int (&jsobj, "Last machine account password change",
248 pass_time);
249 if (ret != 0) {
250 goto failure;
253 if (json_is_invalid(&jsobj)) {
254 ret = -1;
255 goto failure;
258 ctx = talloc_new(NULL);
259 if (ctx == NULL) {
260 ret = -1;
261 d_fprintf(stderr, _("Out of memory\n"));
263 goto failure;
266 json = json_to_string(ctx, &jsobj);
267 if (json) {
268 d_printf("%s\n", json);
269 } else {
270 ret = -1;
271 d_fprintf(stderr, _("error encoding to JSON\n"));
274 TALLOC_FREE(ctx);
275 failure:
276 ads_destroy(&ads);
278 return ret;
281 #else /* [HAVE_JANSSON] */
283 static int net_ads_info_json(ADS_STRUCT *)
285 d_fprintf(stderr, _("JSON support not available\n"));
287 return -1;
290 #endif /* [HAVE_JANSSON] */
294 static int net_ads_info(struct net_context *c, int argc, const char **argv)
296 ADS_STRUCT *ads;
297 char addr[INET6_ADDRSTRLEN];
298 time_t pass_time;
300 if (c->display_usage) {
301 d_printf("%s\n"
302 "net ads info\n"
303 " %s",
304 _("Usage:"),
305 _("Display information about an Active Directory "
306 "server.\n"));
307 return 0;
310 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
311 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
312 return -1;
315 if (!ads || !ads->config.realm) {
316 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
317 ads_destroy(&ads);
318 return -1;
321 /* Try to set the server's current time since we didn't do a full
322 TCP LDAP session initially */
324 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
325 d_fprintf( stderr, _("Failed to get server's current time!\n"));
328 if (c->opt_json) {
329 return net_ads_info_json(ads);
332 pass_time = secrets_fetch_pass_last_set_time(ads->server.workgroup);
334 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
336 d_printf(_("LDAP server: %s\n"), addr);
337 d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
338 d_printf(_("Realm: %s\n"), ads->config.realm);
339 d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
340 d_printf(_("LDAP port: %d\n"), ads->ldap.port);
341 d_printf(_("Server time: %s\n"),
342 http_timestring(talloc_tos(), ads->config.current_time));
344 d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
345 d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
347 d_printf(_("Last machine account password change: %s\n"),
348 http_timestring(talloc_tos(), pass_time));
350 ads_destroy(&ads);
351 return 0;
354 static void use_in_memory_ccache(void) {
355 /* Use in-memory credentials cache so we do not interfere with
356 * existing credentials */
357 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
360 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
361 uint32_t auth_flags, ADS_STRUCT **ads_ret)
363 ADS_STRUCT *ads = NULL;
364 ADS_STATUS status;
365 bool need_password = false;
366 bool second_time = false;
367 char *cp;
368 const char *realm = NULL;
369 bool tried_closest_dc = false;
371 /* lp_realm() should be handled by a command line param,
372 However, the join requires that realm be set in smb.conf
373 and compares our realm with the remote server's so this is
374 ok until someone needs more flexibility */
376 *ads_ret = NULL;
378 retry_connect:
379 if (only_own_domain) {
380 realm = lp_realm();
381 } else {
382 realm = assume_own_realm(c);
385 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
387 if (!c->opt_user_name) {
388 c->opt_user_name = "administrator";
391 if (c->opt_user_specified) {
392 need_password = true;
395 retry:
396 if (!c->opt_password && need_password && !c->opt_machine_pass) {
397 c->opt_password = net_prompt_pass(c, c->opt_user_name);
398 if (!c->opt_password) {
399 ads_destroy(&ads);
400 return ADS_ERROR(LDAP_NO_MEMORY);
404 if (c->opt_password) {
405 use_in_memory_ccache();
406 SAFE_FREE(ads->auth.password);
407 ads->auth.password = smb_xstrdup(c->opt_password);
410 ads->auth.flags |= auth_flags;
411 SAFE_FREE(ads->auth.user_name);
412 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
415 * If the username is of the form "name@realm",
416 * extract the realm and convert to upper case.
417 * This is only used to establish the connection.
419 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
420 *cp++ = '\0';
421 SAFE_FREE(ads->auth.realm);
422 ads->auth.realm = smb_xstrdup(cp);
423 if (!strupper_m(ads->auth.realm)) {
424 ads_destroy(&ads);
425 return ADS_ERROR(LDAP_NO_MEMORY);
429 status = ads_connect(ads);
431 if (!ADS_ERR_OK(status)) {
433 if (NT_STATUS_EQUAL(ads_ntstatus(status),
434 NT_STATUS_NO_LOGON_SERVERS)) {
435 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
436 ads_destroy(&ads);
437 return status;
440 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
441 need_password = true;
442 second_time = true;
443 goto retry;
444 } else {
445 ads_destroy(&ads);
446 return status;
450 /* when contacting our own domain, make sure we use the closest DC.
451 * This is done by reconnecting to ADS because only the first call to
452 * ads_connect will give us our own sitename */
454 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
456 tried_closest_dc = true; /* avoid loop */
458 if (!ads_closest_dc(ads)) {
460 namecache_delete(ads->server.realm, 0x1C);
461 namecache_delete(ads->server.workgroup, 0x1C);
463 ads_destroy(&ads);
464 ads = NULL;
466 goto retry_connect;
470 *ads_ret = ads;
471 return status;
474 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
476 return ads_startup_int(c, only_own_domain, 0, ads);
479 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
481 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
485 Check to see if connection can be made via ads.
486 ads_startup() stores the password in opt_password if it needs to so
487 that rpc or rap can use it without re-prompting.
489 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
491 ADS_STRUCT *ads;
492 ADS_STATUS status;
494 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
495 return -1;
498 ads->auth.flags |= ADS_AUTH_NO_BIND;
500 status = ads_connect(ads);
501 if ( !ADS_ERR_OK(status) ) {
502 return -1;
505 ads_destroy(&ads);
506 return 0;
509 int net_ads_check_our_domain(struct net_context *c)
511 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
514 int net_ads_check(struct net_context *c)
516 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
520 determine the netbios workgroup name for a domain
522 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
524 ADS_STRUCT *ads;
525 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
527 if (c->display_usage) {
528 d_printf ("%s\n"
529 "net ads workgroup\n"
530 " %s\n",
531 _("Usage:"),
532 _("Print the workgroup name"));
533 return 0;
536 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
537 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
538 return -1;
541 if (!ads->config.realm) {
542 ads->config.realm = discard_const_p(char, c->opt_target_workgroup);
543 ads->ldap.port = 389;
546 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads->ldap.ss, ads->server.realm, &reply ) ) {
547 d_fprintf(stderr, _("CLDAP query failed!\n"));
548 ads_destroy(&ads);
549 return -1;
552 d_printf(_("Workgroup: %s\n"), reply.domain_name);
554 ads_destroy(&ads);
556 return 0;
561 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
563 char **disp_fields = (char **) data_area;
565 if (!field) { /* must be end of record */
566 if (disp_fields[0]) {
567 if (!strchr_m(disp_fields[0], '$')) {
568 if (disp_fields[1])
569 d_printf("%-21.21s %s\n",
570 disp_fields[0], disp_fields[1]);
571 else
572 d_printf("%s\n", disp_fields[0]);
575 SAFE_FREE(disp_fields[0]);
576 SAFE_FREE(disp_fields[1]);
577 return true;
579 if (!values) /* must be new field, indicate string field */
580 return true;
581 if (strcasecmp_m(field, "sAMAccountName") == 0) {
582 disp_fields[0] = SMB_STRDUP((char *) values[0]);
584 if (strcasecmp_m(field, "description") == 0)
585 disp_fields[1] = SMB_STRDUP((char *) values[0]);
586 return true;
589 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
591 return net_user_usage(c, argc, argv);
594 static int ads_user_add(struct net_context *c, int argc, const char **argv)
596 ADS_STRUCT *ads;
597 ADS_STATUS status;
598 char *upn, *userdn;
599 LDAPMessage *res=NULL;
600 int rc = -1;
601 char *ou_str = NULL;
603 if (argc < 1 || c->display_usage)
604 return net_ads_user_usage(c, argc, argv);
606 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
607 return -1;
610 status = ads_find_user_acct(ads, &res, argv[0]);
612 if (!ADS_ERR_OK(status)) {
613 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
614 goto done;
617 if (ads_count_replies(ads, res)) {
618 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
619 argv[0]);
620 goto done;
623 if (c->opt_container) {
624 ou_str = SMB_STRDUP(c->opt_container);
625 } else {
626 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
629 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
631 if (!ADS_ERR_OK(status)) {
632 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
633 ads_errstr(status));
634 goto done;
637 /* if no password is to be set, we're done */
638 if (argc == 1) {
639 d_printf(_("User %s added\n"), argv[0]);
640 rc = 0;
641 goto done;
644 /* try setting the password */
645 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
646 goto done;
648 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
649 ads->auth.time_offset);
650 SAFE_FREE(upn);
651 if (ADS_ERR_OK(status)) {
652 d_printf(_("User %s added\n"), argv[0]);
653 rc = 0;
654 goto done;
657 /* password didn't set, delete account */
658 d_fprintf(stderr, _("Could not add user %s. "
659 "Error setting password %s\n"),
660 argv[0], ads_errstr(status));
661 ads_msgfree(ads, res);
662 status=ads_find_user_acct(ads, &res, argv[0]);
663 if (ADS_ERR_OK(status)) {
664 userdn = ads_get_dn(ads, talloc_tos(), res);
665 ads_del_dn(ads, userdn);
666 TALLOC_FREE(userdn);
669 done:
670 if (res)
671 ads_msgfree(ads, res);
672 ads_destroy(&ads);
673 SAFE_FREE(ou_str);
674 return rc;
677 static int ads_user_info(struct net_context *c, int argc, const char **argv)
679 ADS_STRUCT *ads = NULL;
680 ADS_STATUS rc;
681 LDAPMessage *res = NULL;
682 TALLOC_CTX *frame;
683 int ret = 0;
684 wbcErr wbc_status;
685 const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
686 char *searchstring=NULL;
687 char **grouplist;
688 char *primary_group;
689 char *escaped_user;
690 struct dom_sid primary_group_sid;
691 uint32_t group_rid;
692 enum wbcSidType type;
694 if (argc < 1 || c->display_usage) {
695 return net_ads_user_usage(c, argc, argv);
698 frame = talloc_new(talloc_tos());
699 if (frame == NULL) {
700 return -1;
703 escaped_user = escape_ldap_string(frame, argv[0]);
704 if (!escaped_user) {
705 d_fprintf(stderr,
706 _("ads_user_info: failed to escape user %s\n"),
707 argv[0]);
708 return -1;
711 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
712 ret = -1;
713 goto error;
716 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
717 ret =-1;
718 goto error;
720 rc = ads_search(ads, &res, searchstring, attrs);
721 SAFE_FREE(searchstring);
723 if (!ADS_ERR_OK(rc)) {
724 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(rc));
725 ret = -1;
726 goto error;
729 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
730 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
731 ret = -1;
732 goto error;
735 rc = ads_domain_sid(ads, &primary_group_sid);
736 if (!ADS_ERR_OK(rc)) {
737 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(rc));
738 ret = -1;
739 goto error;
742 sid_append_rid(&primary_group_sid, group_rid);
744 wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
745 NULL, /* don't look up domain */
746 &primary_group,
747 &type);
748 if (!WBC_ERROR_IS_OK(wbc_status)) {
749 d_fprintf(stderr, "wbcLookupSid: %s\n",
750 wbcErrorString(wbc_status));
751 ret = -1;
752 goto error;
755 d_printf("%s\n", primary_group);
757 wbcFreeMemory(primary_group);
759 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
760 (LDAPMessage *)res, "memberOf");
762 if (grouplist) {
763 int i;
764 char **groupname;
765 for (i=0;grouplist[i];i++) {
766 groupname = ldap_explode_dn(grouplist[i], 1);
767 d_printf("%s\n", groupname[0]);
768 ldap_value_free(groupname);
770 ldap_value_free(grouplist);
773 error:
774 if (res) ads_msgfree(ads, res);
775 if (ads) ads_destroy(&ads);
776 TALLOC_FREE(frame);
777 return ret;
780 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
782 ADS_STRUCT *ads;
783 ADS_STATUS rc;
784 LDAPMessage *res = NULL;
785 char *userdn;
787 if (argc < 1) {
788 return net_ads_user_usage(c, argc, argv);
791 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
792 return -1;
795 rc = ads_find_user_acct(ads, &res, argv[0]);
796 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
797 d_printf(_("User %s does not exist.\n"), argv[0]);
798 ads_msgfree(ads, res);
799 ads_destroy(&ads);
800 return -1;
802 userdn = ads_get_dn(ads, talloc_tos(), res);
803 ads_msgfree(ads, res);
804 rc = ads_del_dn(ads, userdn);
805 TALLOC_FREE(userdn);
806 if (ADS_ERR_OK(rc)) {
807 d_printf(_("User %s deleted\n"), argv[0]);
808 ads_destroy(&ads);
809 return 0;
811 d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
812 ads_errstr(rc));
813 ads_destroy(&ads);
814 return -1;
817 int net_ads_user(struct net_context *c, int argc, const char **argv)
819 struct functable func[] = {
821 "add",
822 ads_user_add,
823 NET_TRANSPORT_ADS,
824 N_("Add an AD user"),
825 N_("net ads user add\n"
826 " Add an AD user")
829 "info",
830 ads_user_info,
831 NET_TRANSPORT_ADS,
832 N_("Display information about an AD user"),
833 N_("net ads user info\n"
834 " Display information about an AD user")
837 "delete",
838 ads_user_delete,
839 NET_TRANSPORT_ADS,
840 N_("Delete an AD user"),
841 N_("net ads user delete\n"
842 " Delete an AD user")
844 {NULL, NULL, 0, NULL, NULL}
846 ADS_STRUCT *ads;
847 ADS_STATUS rc;
848 const char *shortattrs[] = {"sAMAccountName", NULL};
849 const char *longattrs[] = {"sAMAccountName", "description", NULL};
850 char *disp_fields[2] = {NULL, NULL};
852 if (argc == 0) {
853 if (c->display_usage) {
854 d_printf( "%s\n"
855 "net ads user\n"
856 " %s\n",
857 _("Usage:"),
858 _("List AD users"));
859 net_display_usage_from_functable(func);
860 return 0;
863 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
864 return -1;
867 if (c->opt_long_list_entries)
868 d_printf(_("\nUser name Comment"
869 "\n-----------------------------\n"));
871 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
872 LDAP_SCOPE_SUBTREE,
873 "(objectCategory=user)",
874 c->opt_long_list_entries ? longattrs :
875 shortattrs, usergrp_display,
876 disp_fields);
877 ads_destroy(&ads);
878 return ADS_ERR_OK(rc) ? 0 : -1;
881 return net_run_function(c, argc, argv, "net ads user", func);
884 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
886 return net_group_usage(c, argc, argv);
889 static int ads_group_add(struct net_context *c, int argc, const char **argv)
891 ADS_STRUCT *ads;
892 ADS_STATUS status;
893 LDAPMessage *res=NULL;
894 int rc = -1;
895 char *ou_str = NULL;
897 if (argc < 1 || c->display_usage) {
898 return net_ads_group_usage(c, argc, argv);
901 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
902 return -1;
905 status = ads_find_user_acct(ads, &res, argv[0]);
907 if (!ADS_ERR_OK(status)) {
908 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
909 goto done;
912 if (ads_count_replies(ads, res)) {
913 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
914 goto done;
917 if (c->opt_container) {
918 ou_str = SMB_STRDUP(c->opt_container);
919 } else {
920 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
923 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
925 if (ADS_ERR_OK(status)) {
926 d_printf(_("Group %s added\n"), argv[0]);
927 rc = 0;
928 } else {
929 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
930 ads_errstr(status));
933 done:
934 if (res)
935 ads_msgfree(ads, res);
936 ads_destroy(&ads);
937 SAFE_FREE(ou_str);
938 return rc;
941 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
943 ADS_STRUCT *ads;
944 ADS_STATUS rc;
945 LDAPMessage *res = NULL;
946 char *groupdn;
948 if (argc < 1 || c->display_usage) {
949 return net_ads_group_usage(c, argc, argv);
952 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
953 return -1;
956 rc = ads_find_user_acct(ads, &res, argv[0]);
957 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
958 d_printf(_("Group %s does not exist.\n"), argv[0]);
959 ads_msgfree(ads, res);
960 ads_destroy(&ads);
961 return -1;
963 groupdn = ads_get_dn(ads, talloc_tos(), res);
964 ads_msgfree(ads, res);
965 rc = ads_del_dn(ads, groupdn);
966 TALLOC_FREE(groupdn);
967 if (ADS_ERR_OK(rc)) {
968 d_printf(_("Group %s deleted\n"), argv[0]);
969 ads_destroy(&ads);
970 return 0;
972 d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
973 ads_errstr(rc));
974 ads_destroy(&ads);
975 return -1;
978 int net_ads_group(struct net_context *c, int argc, const char **argv)
980 struct functable func[] = {
982 "add",
983 ads_group_add,
984 NET_TRANSPORT_ADS,
985 N_("Add an AD group"),
986 N_("net ads group add\n"
987 " Add an AD group")
990 "delete",
991 ads_group_delete,
992 NET_TRANSPORT_ADS,
993 N_("Delete an AD group"),
994 N_("net ads group delete\n"
995 " Delete an AD group")
997 {NULL, NULL, 0, NULL, NULL}
999 ADS_STRUCT *ads;
1000 ADS_STATUS rc;
1001 const char *shortattrs[] = {"sAMAccountName", NULL};
1002 const char *longattrs[] = {"sAMAccountName", "description", NULL};
1003 char *disp_fields[2] = {NULL, NULL};
1005 if (argc == 0) {
1006 if (c->display_usage) {
1007 d_printf( "%s\n"
1008 "net ads group\n"
1009 " %s\n",
1010 _("Usage:"),
1011 _("List AD groups"));
1012 net_display_usage_from_functable(func);
1013 return 0;
1016 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1017 return -1;
1020 if (c->opt_long_list_entries)
1021 d_printf(_("\nGroup name Comment"
1022 "\n-----------------------------\n"));
1023 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
1024 LDAP_SCOPE_SUBTREE,
1025 "(objectCategory=group)",
1026 c->opt_long_list_entries ? longattrs :
1027 shortattrs, usergrp_display,
1028 disp_fields);
1030 ads_destroy(&ads);
1031 return ADS_ERR_OK(rc) ? 0 : -1;
1033 return net_run_function(c, argc, argv, "net ads group", func);
1036 static int net_ads_status(struct net_context *c, int argc, const char **argv)
1038 ADS_STRUCT *ads;
1039 ADS_STATUS rc;
1040 LDAPMessage *res;
1042 if (c->display_usage) {
1043 d_printf( "%s\n"
1044 "net ads status\n"
1045 " %s\n",
1046 _("Usage:"),
1047 _("Display machine account details"));
1048 return 0;
1051 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1052 return -1;
1055 rc = ads_find_machine_acct(ads, &res, lp_netbios_name());
1056 if (!ADS_ERR_OK(rc)) {
1057 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
1058 ads_destroy(&ads);
1059 return -1;
1062 if (ads_count_replies(ads, res) == 0) {
1063 d_fprintf(stderr, _("No machine account for '%s' found\n"), lp_netbios_name());
1064 ads_destroy(&ads);
1065 return -1;
1068 ads_dump(ads, res);
1069 ads_destroy(&ads);
1070 return 0;
1073 /*******************************************************************
1074 Leave an AD domain. Windows XP disables the machine account.
1075 We'll try the same. The old code would do an LDAP delete.
1076 That only worked using the machine creds because added the machine
1077 with full control to the computer object's ACL.
1078 *******************************************************************/
1080 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
1082 TALLOC_CTX *ctx;
1083 struct libnet_UnjoinCtx *r = NULL;
1084 WERROR werr;
1086 if (c->display_usage) {
1087 d_printf( "%s\n"
1088 "net ads leave [--keep-account]\n"
1089 " %s\n",
1090 _("Usage:"),
1091 _("Leave an AD domain"));
1092 return 0;
1095 if (!*lp_realm()) {
1096 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
1097 return -1;
1100 if (!(ctx = talloc_init("net_ads_leave"))) {
1101 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1102 return -1;
1105 if (!c->opt_kerberos) {
1106 use_in_memory_ccache();
1109 if (!c->msg_ctx) {
1110 d_fprintf(stderr, _("Could not initialise message context. "
1111 "Try running as root\n"));
1112 return -1;
1115 werr = libnet_init_UnjoinCtx(ctx, &r);
1116 if (!W_ERROR_IS_OK(werr)) {
1117 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
1118 return -1;
1121 r->in.debug = true;
1122 r->in.use_kerberos = c->opt_kerberos;
1123 r->in.dc_name = c->opt_host;
1124 r->in.domain_name = lp_realm();
1125 r->in.admin_account = c->opt_user_name;
1126 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1127 r->in.modify_config = lp_config_backend_is_registry();
1129 /* Try to delete it, but if that fails, disable it. The
1130 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
1131 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1132 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
1133 if (c->opt_keep_account) {
1134 r->in.delete_machine_account = false;
1135 } else {
1136 r->in.delete_machine_account = true;
1139 r->in.msg_ctx = c->msg_ctx;
1141 werr = libnet_Unjoin(ctx, r);
1142 if (!W_ERROR_IS_OK(werr)) {
1143 d_printf(_("Failed to leave domain: %s\n"),
1144 r->out.error_string ? r->out.error_string :
1145 get_friendly_werror_msg(werr));
1146 goto done;
1149 if (r->out.deleted_machine_account) {
1150 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1151 r->in.machine_name, r->out.dns_domain_name);
1152 goto done;
1155 /* We couldn't delete it - see if the disable succeeded. */
1156 if (r->out.disabled_machine_account) {
1157 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1158 r->in.machine_name, r->out.dns_domain_name);
1159 werr = WERR_OK;
1160 goto done;
1163 /* Based on what we requested, we shouldn't get here, but if
1164 we did, it means the secrets were removed, and therefore
1165 we have left the domain */
1166 d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1167 r->in.machine_name, r->out.dns_domain_name);
1169 done:
1170 TALLOC_FREE(r);
1171 TALLOC_FREE(ctx);
1173 if (W_ERROR_IS_OK(werr)) {
1174 return 0;
1177 return -1;
1180 static NTSTATUS net_ads_join_ok(struct net_context *c)
1182 ADS_STRUCT *ads = NULL;
1183 ADS_STATUS status;
1184 fstring dc_name;
1185 struct sockaddr_storage dcip;
1187 if (!secrets_init()) {
1188 DEBUG(1,("Failed to initialise secrets database\n"));
1189 return NT_STATUS_ACCESS_DENIED;
1192 net_use_krb_machine_account(c);
1194 get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1196 status = ads_startup(c, true, &ads);
1197 if (!ADS_ERR_OK(status)) {
1198 return ads_ntstatus(status);
1201 ads_destroy(&ads);
1202 return NT_STATUS_OK;
1206 check that an existing join is OK
1208 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1210 NTSTATUS status;
1211 use_in_memory_ccache();
1213 if (c->display_usage) {
1214 d_printf( "%s\n"
1215 "net ads testjoin\n"
1216 " %s\n",
1217 _("Usage:"),
1218 _("Test if the existing join is ok"));
1219 return 0;
1222 /* Display success or failure */
1223 status = net_ads_join_ok(c);
1224 if (!NT_STATUS_IS_OK(status)) {
1225 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1226 get_friendly_nt_error_msg(status));
1227 return -1;
1230 printf(_("Join is OK\n"));
1231 return 0;
1234 /*******************************************************************
1235 Simple configu checks before beginning the join
1236 ********************************************************************/
1238 static WERROR check_ads_config( void )
1240 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1241 d_printf(_("Host is not configured as a member server.\n"));
1242 return WERR_INVALID_DOMAIN_ROLE;
1245 if (strlen(lp_netbios_name()) > 15) {
1246 d_printf(_("Our netbios name can be at most 15 chars long, "
1247 "\"%s\" is %u chars long\n"), lp_netbios_name(),
1248 (unsigned int)strlen(lp_netbios_name()));
1249 return WERR_INVALID_COMPUTERNAME;
1252 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1253 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1254 "join to succeed.\n"), get_dyn_CONFIGFILE());
1255 return WERR_INVALID_PARAMETER;
1258 return WERR_OK;
1261 /*******************************************************************
1262 Send a DNS update request
1263 *******************************************************************/
1265 #if defined(WITH_DNS_UPDATES)
1266 #include "../lib/addns/dns.h"
1268 static NTSTATUS net_update_dns_internal(struct net_context *c,
1269 TALLOC_CTX *ctx, ADS_STRUCT *ads,
1270 const char *machine_name,
1271 const struct sockaddr_storage *addrs,
1272 int num_addrs, bool remove_host)
1274 struct dns_rr_ns *nameservers = NULL;
1275 int ns_count = 0, i;
1276 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1277 DNS_ERROR dns_err;
1278 fstring dns_server;
1279 const char *dnsdomain = NULL;
1280 char *root_domain = NULL;
1282 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1283 d_printf(_("No DNS domain configured for %s. "
1284 "Unable to perform DNS Update.\n"), machine_name);
1285 status = NT_STATUS_INVALID_PARAMETER;
1286 goto done;
1288 dnsdomain++;
1290 status = ads_dns_lookup_ns(ctx,
1291 dnsdomain,
1292 &nameservers,
1293 &ns_count);
1294 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1295 /* Child domains often do not have NS records. Look
1296 for the NS record for the forest root domain
1297 (rootDomainNamingContext in therootDSE) */
1299 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1300 LDAPMessage *msg = NULL;
1301 char *root_dn;
1302 ADS_STATUS ads_status;
1304 if ( !ads->ldap.ld ) {
1305 ads_status = ads_connect( ads );
1306 if ( !ADS_ERR_OK(ads_status) ) {
1307 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1308 goto done;
1312 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1313 "(objectclass=*)", rootname_attrs, &msg);
1314 if (!ADS_ERR_OK(ads_status)) {
1315 goto done;
1318 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1319 if ( !root_dn ) {
1320 ads_msgfree( ads, msg );
1321 goto done;
1324 root_domain = ads_build_domain( root_dn );
1326 /* cleanup */
1327 ads_msgfree( ads, msg );
1329 /* try again for NS servers */
1331 status = ads_dns_lookup_ns(ctx,
1332 root_domain,
1333 &nameservers,
1334 &ns_count);
1336 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1337 DEBUG(3,("net_update_dns_internal: Failed to find name server for the %s "
1338 "realm\n", ads->config.realm));
1339 if (ns_count == 0) {
1340 status = NT_STATUS_UNSUCCESSFUL;
1342 goto done;
1345 dnsdomain = root_domain;
1349 for (i=0; i < ns_count; i++) {
1351 uint32_t flags = DNS_UPDATE_SIGNED |
1352 DNS_UPDATE_UNSIGNED |
1353 DNS_UPDATE_UNSIGNED_SUFFICIENT |
1354 DNS_UPDATE_PROBE |
1355 DNS_UPDATE_PROBE_SUFFICIENT;
1357 if (c->opt_force) {
1358 flags &= ~DNS_UPDATE_PROBE_SUFFICIENT;
1359 flags &= ~DNS_UPDATE_UNSIGNED_SUFFICIENT;
1363 * Do not return after PROBE completion if this function
1364 * is called for DNS removal.
1366 if (remove_host) {
1367 flags &= ~DNS_UPDATE_PROBE_SUFFICIENT;
1370 status = NT_STATUS_UNSUCCESSFUL;
1372 /* Now perform the dns update - we'll try non-secure and if we fail,
1373 we'll follow it up with a secure update */
1375 fstrcpy( dns_server, nameservers[i].hostname );
1377 dns_err = DoDNSUpdate(dns_server,
1378 dnsdomain,
1379 machine_name,
1380 addrs,
1381 num_addrs,
1382 flags,
1383 remove_host);
1384 if (ERR_DNS_IS_OK(dns_err)) {
1385 status = NT_STATUS_OK;
1386 goto done;
1389 if (ERR_DNS_EQUAL(dns_err, ERROR_DNS_INVALID_NAME_SERVER) ||
1390 ERR_DNS_EQUAL(dns_err, ERROR_DNS_CONNECTION_FAILED) ||
1391 ERR_DNS_EQUAL(dns_err, ERROR_DNS_SOCKET_ERROR)) {
1392 DEBUG(1,("retrying DNS update with next nameserver after receiving %s\n",
1393 dns_errstr(dns_err)));
1394 continue;
1397 d_printf(_("DNS Update for %s failed: %s\n"),
1398 machine_name, dns_errstr(dns_err));
1399 status = NT_STATUS_UNSUCCESSFUL;
1400 goto done;
1403 done:
1405 SAFE_FREE( root_domain );
1407 return status;
1410 static NTSTATUS net_update_dns_ext(struct net_context *c,
1411 TALLOC_CTX *mem_ctx, ADS_STRUCT *ads,
1412 const char *hostname,
1413 struct sockaddr_storage *iplist,
1414 int num_addrs, bool remove_host)
1416 struct sockaddr_storage *iplist_alloc = NULL;
1417 fstring machine_name;
1418 NTSTATUS status;
1420 if (hostname) {
1421 fstrcpy(machine_name, hostname);
1422 } else {
1423 name_to_fqdn( machine_name, lp_netbios_name() );
1425 if (!strlower_m( machine_name )) {
1426 return NT_STATUS_INVALID_PARAMETER;
1430 * If remove_host is true, then remove all IP addresses associated with
1431 * this hostname from the AD server.
1433 if (!remove_host && (num_addrs == 0 || iplist == NULL)) {
1435 * Get our ip address
1436 * (not the 127.0.0.x address but a real ip address)
1438 num_addrs = get_my_ip_address(&iplist_alloc);
1439 if ( num_addrs <= 0 ) {
1440 DEBUG(4, ("net_update_dns_ext: Failed to find my "
1441 "non-loopback IP addresses!\n"));
1442 return NT_STATUS_INVALID_PARAMETER;
1444 iplist = iplist_alloc;
1447 status = net_update_dns_internal(c, mem_ctx, ads, machine_name,
1448 iplist, num_addrs, remove_host);
1450 SAFE_FREE(iplist_alloc);
1451 return status;
1454 static NTSTATUS net_update_dns(struct net_context *c, TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, const char *hostname)
1456 NTSTATUS status;
1458 status = net_update_dns_ext(c, mem_ctx, ads, hostname, NULL, 0, false);
1459 return status;
1461 #endif
1464 /*******************************************************************
1465 ********************************************************************/
1467 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1469 d_printf(_("net ads join [--no-dns-updates] [options]\n"
1470 "Valid options:\n"));
1471 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1472 " The default UPN is in the form host/netbiosname@REALM.\n"));
1473 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1474 " The OU string read from top to bottom without RDNs\n"
1475 " and delimited by a '/'.\n"
1476 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1477 " NB: A backslash '\\' is used as escape at multiple\n"
1478 " levels and may need to be doubled or even\n"
1479 " quadrupled. It is not used as a separator.\n"));
1480 d_printf(_(" machinepass=PASS Set the machine password to a specific value during\n"
1481 " the join. The default password is random.\n"));
1482 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1483 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during join.\n"
1484 " NB: osName and osVer must be specified together for\n"
1485 " either to take effect. The operatingSystemService\n"
1486 " attribute is then also set along with the two\n"
1487 " other attributes.\n"));
1488 d_printf(_(" osServicePack=string Set the operatingSystemServicePack attribute\n"
1489 " during the join.\n"
1490 " NB: If not specified then by default the samba\n"
1491 " version string is used instead.\n"));
1492 return -1;
1496 static void _net_ads_join_dns_updates(struct net_context *c, TALLOC_CTX *ctx, struct libnet_JoinCtx *r)
1498 #if defined(WITH_DNS_UPDATES)
1499 ADS_STRUCT *ads_dns = NULL;
1500 int ret;
1501 NTSTATUS status;
1504 * In a clustered environment, don't do dynamic dns updates:
1505 * Registering the set of ip addresses that are assigned to
1506 * the interfaces of the node that performs the join does usually
1507 * not have the desired effect, since the local interfaces do not
1508 * carry the complete set of the cluster's public IP addresses.
1509 * And it can also contain internal addresses that should not
1510 * be visible to the outside at all.
1511 * In order to do dns updates in a clustererd setup, use
1512 * net ads dns register.
1514 if (lp_clustering()) {
1515 d_fprintf(stderr, _("Not doing automatic DNS update in a "
1516 "clustered setup.\n"));
1517 return;
1520 if (!r->out.domain_is_ad) {
1521 return;
1525 * We enter this block with user creds.
1526 * kinit with the machine password to do dns update.
1529 ads_dns = ads_init(lp_realm(), NULL, r->in.dc_name);
1531 if (ads_dns == NULL) {
1532 d_fprintf(stderr, _("DNS update failed: out of memory!\n"));
1533 goto done;
1536 use_in_memory_ccache();
1538 ret = asprintf(&ads_dns->auth.user_name, "%s$", lp_netbios_name());
1539 if (ret == -1) {
1540 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1541 goto done;
1544 ads_dns->auth.password = secrets_fetch_machine_password(
1545 r->out.netbios_domain_name, NULL, NULL);
1546 if (ads_dns->auth.password == NULL) {
1547 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1548 goto done;
1551 ads_dns->auth.realm = SMB_STRDUP(r->out.dns_domain_name);
1552 if (ads_dns->auth.realm == NULL) {
1553 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1554 goto done;
1557 if (!strupper_m(ads_dns->auth.realm)) {
1558 d_fprintf(stderr, _("strupper_m %s failed\n"), ads_dns->auth.realm);
1559 goto done;
1562 ret = ads_kinit_password(ads_dns);
1563 if (ret != 0) {
1564 d_fprintf(stderr,
1565 _("DNS update failed: kinit failed: %s\n"),
1566 error_message(ret));
1567 goto done;
1570 status = net_update_dns(c, ctx, ads_dns, NULL);
1571 if (!NT_STATUS_IS_OK(status)) {
1572 d_fprintf( stderr, _("DNS update failed: %s\n"),
1573 nt_errstr(status));
1576 done:
1577 ads_destroy(&ads_dns);
1578 #endif
1580 return;
1584 int net_ads_join(struct net_context *c, int argc, const char **argv)
1586 TALLOC_CTX *ctx = NULL;
1587 struct libnet_JoinCtx *r = NULL;
1588 const char *domain = lp_realm();
1589 WERROR werr = WERR_NERR_SETUPNOTJOINED;
1590 bool createupn = false;
1591 const char *machineupn = NULL;
1592 const char *machine_password = NULL;
1593 const char *create_in_ou = NULL;
1594 int i;
1595 const char *os_name = NULL;
1596 const char *os_version = NULL;
1597 const char *os_servicepack = NULL;
1598 bool modify_config = lp_config_backend_is_registry();
1599 enum libnetjoin_JoinDomNameType domain_name_type = JoinDomNameTypeDNS;
1601 if (c->display_usage)
1602 return net_ads_join_usage(c, argc, argv);
1604 if (!modify_config) {
1606 werr = check_ads_config();
1607 if (!W_ERROR_IS_OK(werr)) {
1608 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1609 goto fail;
1613 if (!(ctx = talloc_init("net_ads_join"))) {
1614 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1615 werr = WERR_NOT_ENOUGH_MEMORY;
1616 goto fail;
1619 if (!c->opt_kerberos) {
1620 use_in_memory_ccache();
1623 werr = libnet_init_JoinCtx(ctx, &r);
1624 if (!W_ERROR_IS_OK(werr)) {
1625 goto fail;
1628 /* process additional command line args */
1630 for ( i=0; i<argc; i++ ) {
1631 if ( !strncasecmp_m(argv[i], "createupn", strlen("createupn")) ) {
1632 createupn = true;
1633 machineupn = get_string_param(argv[i]);
1635 else if ( !strncasecmp_m(argv[i], "createcomputer", strlen("createcomputer")) ) {
1636 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1637 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1638 werr = WERR_INVALID_PARAMETER;
1639 goto fail;
1642 else if ( !strncasecmp_m(argv[i], "osName", strlen("osName")) ) {
1643 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1644 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1645 werr = WERR_INVALID_PARAMETER;
1646 goto fail;
1649 else if ( !strncasecmp_m(argv[i], "osVer", strlen("osVer")) ) {
1650 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1651 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1652 werr = WERR_INVALID_PARAMETER;
1653 goto fail;
1656 else if ( !strncasecmp_m(argv[i], "osServicePack", strlen("osServicePack")) ) {
1657 if ( (os_servicepack = get_string_param(argv[i])) == NULL ) {
1658 d_fprintf(stderr, _("Please supply a valid servicepack identifier.\n"));
1659 werr = WERR_INVALID_PARAMETER;
1660 goto fail;
1663 else if ( !strncasecmp_m(argv[i], "machinepass", strlen("machinepass")) ) {
1664 if ( (machine_password = get_string_param(argv[i])) == NULL ) {
1665 d_fprintf(stderr, _("Please supply a valid password to set as trust account password.\n"));
1666 werr = WERR_INVALID_PARAMETER;
1667 goto fail;
1670 else {
1671 domain = argv[i];
1672 if (strchr(domain, '.') == NULL) {
1673 domain_name_type = JoinDomNameTypeUnknown;
1674 } else {
1675 domain_name_type = JoinDomNameTypeDNS;
1680 if (!*domain) {
1681 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1682 werr = WERR_INVALID_PARAMETER;
1683 goto fail;
1686 if (!c->msg_ctx) {
1687 d_fprintf(stderr, _("Could not initialise message context. "
1688 "Try running as root\n"));
1689 werr = WERR_ACCESS_DENIED;
1690 goto fail;
1693 /* Do the domain join here */
1695 r->in.domain_name = domain;
1696 r->in.domain_name_type = domain_name_type;
1697 r->in.create_upn = createupn;
1698 r->in.upn = machineupn;
1699 r->in.account_ou = create_in_ou;
1700 r->in.os_name = os_name;
1701 r->in.os_version = os_version;
1702 r->in.os_servicepack = os_servicepack;
1703 r->in.dc_name = c->opt_host;
1704 r->in.admin_account = c->opt_user_name;
1705 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1706 r->in.machine_password = machine_password;
1707 r->in.debug = true;
1708 r->in.use_kerberos = c->opt_kerberos;
1709 r->in.modify_config = modify_config;
1710 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1711 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1712 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1713 r->in.msg_ctx = c->msg_ctx;
1715 werr = libnet_Join(ctx, r);
1716 if (W_ERROR_EQUAL(werr, WERR_NERR_DCNOTFOUND) &&
1717 strequal(domain, lp_realm())) {
1718 r->in.domain_name = lp_workgroup();
1719 r->in.domain_name_type = JoinDomNameTypeNBT;
1720 werr = libnet_Join(ctx, r);
1722 if (!W_ERROR_IS_OK(werr)) {
1723 goto fail;
1726 /* Check the short name of the domain */
1728 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1729 d_printf(_("The workgroup in %s does not match the short\n"
1730 "domain name obtained from the server.\n"
1731 "Using the name [%s] from the server.\n"
1732 "You should set \"workgroup = %s\" in %s.\n"),
1733 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1734 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1737 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1739 if (r->out.dns_domain_name) {
1740 d_printf(_("Joined '%s' to dns domain '%s'\n"), r->in.machine_name,
1741 r->out.dns_domain_name);
1742 } else {
1743 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1744 r->out.netbios_domain_name);
1747 /* print out informative error string in case there is one */
1748 if (r->out.error_string != NULL) {
1749 d_printf("%s\n", r->out.error_string);
1753 * We try doing the dns update (if it was compiled in
1754 * and if it was not disabled on the command line).
1755 * If the dns update fails, we still consider the join
1756 * operation as succeeded if we came this far.
1758 if (!c->opt_no_dns_updates) {
1759 _net_ads_join_dns_updates(c, ctx, r);
1762 TALLOC_FREE(r);
1763 TALLOC_FREE( ctx );
1765 return 0;
1767 fail:
1768 /* issue an overall failure message at the end. */
1769 d_printf(_("Failed to join domain: %s\n"),
1770 r && r->out.error_string ? r->out.error_string :
1771 get_friendly_werror_msg(werr));
1772 TALLOC_FREE( ctx );
1774 return -1;
1777 /*******************************************************************
1778 ********************************************************************/
1780 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1782 #if defined(WITH_DNS_UPDATES)
1783 ADS_STRUCT *ads;
1784 ADS_STATUS status;
1785 NTSTATUS ntstatus;
1786 TALLOC_CTX *ctx;
1787 const char *hostname = NULL;
1788 const char **addrs_list = NULL;
1789 struct sockaddr_storage *addrs = NULL;
1790 int num_addrs = 0;
1791 int count;
1793 #ifdef DEVELOPER
1794 talloc_enable_leak_report();
1795 #endif
1797 if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
1798 d_fprintf(stderr, _("Refusing DNS updates with automatic "
1799 "detection of addresses in a clustered "
1800 "setup.\n"));
1801 c->display_usage = true;
1804 if (c->display_usage) {
1805 d_printf( "%s\n"
1806 "net ads dns register [hostname [IP [IP...]]]\n"
1807 " %s\n",
1808 _("Usage:"),
1809 _("Register hostname with DNS\n"));
1810 return -1;
1813 if (!(ctx = talloc_init("net_ads_dns"))) {
1814 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1815 return -1;
1818 if (argc >= 1) {
1819 hostname = argv[0];
1822 if (argc > 1) {
1823 num_addrs = argc - 1;
1824 addrs_list = &argv[1];
1825 } else if (lp_clustering()) {
1826 addrs_list = lp_cluster_addresses();
1827 num_addrs = str_list_length(addrs_list);
1830 if (num_addrs > 0) {
1831 addrs = talloc_zero_array(ctx, struct sockaddr_storage, num_addrs);
1832 if (addrs == NULL) {
1833 d_fprintf(stderr, _("Error allocating memory!\n"));
1834 talloc_free(ctx);
1835 return -1;
1839 for (count = 0; count < num_addrs; count++) {
1840 if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
1841 d_fprintf(stderr, "%s '%s'.\n",
1842 _("Cannot interpret address"),
1843 addrs_list[count]);
1844 talloc_free(ctx);
1845 return -1;
1849 status = ads_startup(c, true, &ads);
1850 if ( !ADS_ERR_OK(status) ) {
1851 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1852 TALLOC_FREE(ctx);
1853 return -1;
1856 ntstatus = net_update_dns_ext(c, ctx, ads, hostname, addrs, num_addrs, false);
1857 if (!NT_STATUS_IS_OK(ntstatus)) {
1858 d_fprintf( stderr, _("DNS update failed!\n") );
1859 ads_destroy( &ads );
1860 TALLOC_FREE( ctx );
1861 return -1;
1864 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1866 ads_destroy(&ads);
1867 TALLOC_FREE( ctx );
1869 return 0;
1870 #else
1871 d_fprintf(stderr,
1872 _("DNS update support not enabled at compile time!\n"));
1873 return -1;
1874 #endif
1877 static int net_ads_dns_unregister(struct net_context *c,
1878 int argc,
1879 const char **argv)
1881 #if defined(WITH_DNS_UPDATES)
1882 ADS_STRUCT *ads;
1883 ADS_STATUS status;
1884 NTSTATUS ntstatus;
1885 TALLOC_CTX *ctx;
1886 const char *hostname = NULL;
1888 #ifdef DEVELOPER
1889 talloc_enable_leak_report();
1890 #endif
1892 if (argc != 1) {
1893 c->display_usage = true;
1896 if (c->display_usage) {
1897 d_printf( "%s\n"
1898 "net ads dns unregister [hostname]\n"
1899 " %s\n",
1900 _("Usage:"),
1901 _("Register hostname with DNS\n"));
1902 return -1;
1905 if (!(ctx = talloc_init("net_ads_dns"))) {
1906 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1907 return -1;
1910 /* Get the hostname for un-registering */
1911 hostname = argv[0];
1913 status = ads_startup(c, true, &ads);
1914 if ( !ADS_ERR_OK(status) ) {
1915 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1916 TALLOC_FREE(ctx);
1917 return -1;
1920 ntstatus = net_update_dns_ext(c, ctx, ads, hostname, NULL, 0, true);
1921 if (!NT_STATUS_IS_OK(ntstatus)) {
1922 d_fprintf( stderr, _("DNS update failed!\n") );
1923 ads_destroy( &ads );
1924 TALLOC_FREE( ctx );
1925 return -1;
1928 d_fprintf( stderr, _("Successfully un-registered hostname from DNS\n"));
1930 ads_destroy(&ads);
1931 TALLOC_FREE( ctx );
1933 return 0;
1934 #else
1935 d_fprintf(stderr,
1936 _("DNS update support not enabled at compile time!\n"));
1937 return -1;
1938 #endif
1941 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1943 #if defined(WITH_DNS_UPDATES)
1944 DNS_ERROR err;
1946 #ifdef DEVELOPER
1947 talloc_enable_leak_report();
1948 #endif
1950 if (argc != 2 || c->display_usage) {
1951 d_printf( "%s\n"
1952 " %s\n"
1953 " %s\n",
1954 _("Usage:"),
1955 _("net ads dns gethostbyname <server> <name>\n"),
1956 _(" Look up hostname from the AD\n"
1957 " server\tName server to use\n"
1958 " name\tName to look up\n"));
1959 return -1;
1962 err = do_gethostbyname(argv[0], argv[1]);
1963 if (!ERR_DNS_IS_OK(err)) {
1964 d_printf(_("do_gethostbyname returned %s (%d)\n"),
1965 dns_errstr(err), ERROR_DNS_V(err));
1967 #endif
1968 return 0;
1971 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1973 struct functable func[] = {
1975 "register",
1976 net_ads_dns_register,
1977 NET_TRANSPORT_ADS,
1978 N_("Add host dns entry to AD"),
1979 N_("net ads dns register\n"
1980 " Add host dns entry to AD")
1983 "unregister",
1984 net_ads_dns_unregister,
1985 NET_TRANSPORT_ADS,
1986 N_("Remove host dns entry from AD"),
1987 N_("net ads dns unregister\n"
1988 " Remove host dns entry from AD")
1991 "gethostbyname",
1992 net_ads_dns_gethostbyname,
1993 NET_TRANSPORT_ADS,
1994 N_("Look up host"),
1995 N_("net ads dns gethostbyname\n"
1996 " Look up host")
1998 {NULL, NULL, 0, NULL, NULL}
2001 return net_run_function(c, argc, argv, "net ads dns", func);
2004 /*******************************************************************
2005 ********************************************************************/
2007 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
2009 d_printf(_(
2010 "\nnet ads printer search <printer>"
2011 "\n\tsearch for a printer in the directory\n"
2012 "\nnet ads printer info <printer> <server>"
2013 "\n\tlookup info in directory for printer on server"
2014 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
2015 "\nnet ads printer publish <printername>"
2016 "\n\tpublish printer in directory"
2017 "\n\t(note: printer name is required)\n"
2018 "\nnet ads printer remove <printername>"
2019 "\n\tremove printer from directory"
2020 "\n\t(note: printer name is required)\n"));
2021 return -1;
2024 /*******************************************************************
2025 ********************************************************************/
2027 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
2029 ADS_STRUCT *ads;
2030 ADS_STATUS rc;
2031 LDAPMessage *res = NULL;
2033 if (c->display_usage) {
2034 d_printf( "%s\n"
2035 "net ads printer search\n"
2036 " %s\n",
2037 _("Usage:"),
2038 _("List printers in the AD"));
2039 return 0;
2042 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2043 return -1;
2046 rc = ads_find_printers(ads, &res);
2048 if (!ADS_ERR_OK(rc)) {
2049 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
2050 ads_msgfree(ads, res);
2051 ads_destroy(&ads);
2052 return -1;
2055 if (ads_count_replies(ads, res) == 0) {
2056 d_fprintf(stderr, _("No results found\n"));
2057 ads_msgfree(ads, res);
2058 ads_destroy(&ads);
2059 return -1;
2062 ads_dump(ads, res);
2063 ads_msgfree(ads, res);
2064 ads_destroy(&ads);
2065 return 0;
2068 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
2070 ADS_STRUCT *ads;
2071 ADS_STATUS rc;
2072 const char *servername, *printername;
2073 LDAPMessage *res = NULL;
2075 if (c->display_usage) {
2076 d_printf("%s\n%s",
2077 _("Usage:"),
2078 _("net ads printer info [printername [servername]]\n"
2079 " Display printer info from AD\n"
2080 " printername\tPrinter name or wildcard\n"
2081 " servername\tName of the print server\n"));
2082 return 0;
2085 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2086 return -1;
2089 if (argc > 0) {
2090 printername = argv[0];
2091 } else {
2092 printername = "*";
2095 if (argc > 1) {
2096 servername = argv[1];
2097 } else {
2098 servername = lp_netbios_name();
2101 rc = ads_find_printer_on_server(ads, &res, printername, servername);
2103 if (!ADS_ERR_OK(rc)) {
2104 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
2105 servername, ads_errstr(rc));
2106 ads_msgfree(ads, res);
2107 ads_destroy(&ads);
2108 return -1;
2111 if (ads_count_replies(ads, res) == 0) {
2112 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
2113 ads_msgfree(ads, res);
2114 ads_destroy(&ads);
2115 return -1;
2118 ads_dump(ads, res);
2119 ads_msgfree(ads, res);
2120 ads_destroy(&ads);
2122 return 0;
2125 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
2127 ADS_STRUCT *ads;
2128 ADS_STATUS rc;
2129 const char *servername, *printername;
2130 struct cli_state *cli = NULL;
2131 struct rpc_pipe_client *pipe_hnd = NULL;
2132 struct sockaddr_storage server_ss;
2133 NTSTATUS nt_status;
2134 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
2135 ADS_MODLIST mods = ads_init_mods(mem_ctx);
2136 char *prt_dn, *srv_dn, **srv_cn;
2137 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
2138 LDAPMessage *res = NULL;
2139 bool ok;
2141 if (argc < 1 || c->display_usage) {
2142 d_printf("%s\n%s",
2143 _("Usage:"),
2144 _("net ads printer publish <printername> [servername]\n"
2145 " Publish printer in AD\n"
2146 " printername\tName of the printer\n"
2147 " servername\tName of the print server\n"));
2148 talloc_destroy(mem_ctx);
2149 return -1;
2152 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2153 talloc_destroy(mem_ctx);
2154 return -1;
2157 printername = argv[0];
2159 if (argc == 2) {
2160 servername = argv[1];
2161 } else {
2162 servername = lp_netbios_name();
2165 /* Get printer data from SPOOLSS */
2167 ok = resolve_name(servername, &server_ss, 0x20, false);
2168 if (!ok) {
2169 d_fprintf(stderr, _("Could not find server %s\n"),
2170 servername);
2171 ads_destroy(&ads);
2172 talloc_destroy(mem_ctx);
2173 return -1;
2176 nt_status = cli_full_connection(&cli, lp_netbios_name(), servername,
2177 &server_ss, 0,
2178 "IPC$", "IPC",
2179 c->opt_user_name, c->opt_workgroup,
2180 c->opt_password ? c->opt_password : "",
2181 CLI_FULL_CONNECTION_USE_KERBEROS,
2182 SMB_SIGNING_IPC_DEFAULT);
2184 if (NT_STATUS_IS_ERR(nt_status)) {
2185 d_fprintf(stderr, _("Unable to open a connection to %s to "
2186 "obtain data for %s\n"),
2187 servername, printername);
2188 ads_destroy(&ads);
2189 talloc_destroy(mem_ctx);
2190 return -1;
2193 /* Publish on AD server */
2195 ads_find_machine_acct(ads, &res, servername);
2197 if (ads_count_replies(ads, res) == 0) {
2198 d_fprintf(stderr, _("Could not find machine account for server "
2199 "%s\n"),
2200 servername);
2201 ads_destroy(&ads);
2202 talloc_destroy(mem_ctx);
2203 return -1;
2206 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
2207 srv_cn = ldap_explode_dn(srv_dn, 1);
2209 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
2210 printername_escaped = escape_rdn_val_string_alloc(printername);
2211 if (!srv_cn_escaped || !printername_escaped) {
2212 SAFE_FREE(srv_cn_escaped);
2213 SAFE_FREE(printername_escaped);
2214 d_fprintf(stderr, _("Internal error, out of memory!"));
2215 ads_destroy(&ads);
2216 talloc_destroy(mem_ctx);
2217 return -1;
2220 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
2221 SAFE_FREE(srv_cn_escaped);
2222 SAFE_FREE(printername_escaped);
2223 d_fprintf(stderr, _("Internal error, out of memory!"));
2224 ads_destroy(&ads);
2225 talloc_destroy(mem_ctx);
2226 return -1;
2229 SAFE_FREE(srv_cn_escaped);
2230 SAFE_FREE(printername_escaped);
2232 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss, &pipe_hnd);
2233 if (!NT_STATUS_IS_OK(nt_status)) {
2234 d_fprintf(stderr, _("Unable to open a connection to the spoolss pipe on %s\n"),
2235 servername);
2236 SAFE_FREE(prt_dn);
2237 ads_destroy(&ads);
2238 talloc_destroy(mem_ctx);
2239 return -1;
2242 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
2243 printername))) {
2244 SAFE_FREE(prt_dn);
2245 ads_destroy(&ads);
2246 talloc_destroy(mem_ctx);
2247 return -1;
2250 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
2251 if (!ADS_ERR_OK(rc)) {
2252 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
2253 SAFE_FREE(prt_dn);
2254 ads_destroy(&ads);
2255 talloc_destroy(mem_ctx);
2256 return -1;
2259 d_printf("published printer\n");
2260 SAFE_FREE(prt_dn);
2261 ads_destroy(&ads);
2262 talloc_destroy(mem_ctx);
2264 return 0;
2267 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
2269 ADS_STRUCT *ads;
2270 ADS_STATUS rc;
2271 const char *servername;
2272 char *prt_dn;
2273 LDAPMessage *res = NULL;
2275 if (argc < 1 || c->display_usage) {
2276 d_printf("%s\n%s",
2277 _("Usage:"),
2278 _("net ads printer remove <printername> [servername]\n"
2279 " Remove a printer from the AD\n"
2280 " printername\tName of the printer\n"
2281 " servername\tName of the print server\n"));
2282 return -1;
2285 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2286 return -1;
2289 if (argc > 1) {
2290 servername = argv[1];
2291 } else {
2292 servername = lp_netbios_name();
2295 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
2297 if (!ADS_ERR_OK(rc)) {
2298 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
2299 ads_msgfree(ads, res);
2300 ads_destroy(&ads);
2301 return -1;
2304 if (ads_count_replies(ads, res) == 0) {
2305 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
2306 ads_msgfree(ads, res);
2307 ads_destroy(&ads);
2308 return -1;
2311 prt_dn = ads_get_dn(ads, talloc_tos(), res);
2312 ads_msgfree(ads, res);
2313 rc = ads_del_dn(ads, prt_dn);
2314 TALLOC_FREE(prt_dn);
2316 if (!ADS_ERR_OK(rc)) {
2317 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
2318 ads_destroy(&ads);
2319 return -1;
2322 ads_destroy(&ads);
2323 return 0;
2326 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
2328 struct functable func[] = {
2330 "search",
2331 net_ads_printer_search,
2332 NET_TRANSPORT_ADS,
2333 N_("Search for a printer"),
2334 N_("net ads printer search\n"
2335 " Search for a printer")
2338 "info",
2339 net_ads_printer_info,
2340 NET_TRANSPORT_ADS,
2341 N_("Display printer information"),
2342 N_("net ads printer info\n"
2343 " Display printer information")
2346 "publish",
2347 net_ads_printer_publish,
2348 NET_TRANSPORT_ADS,
2349 N_("Publish a printer"),
2350 N_("net ads printer publish\n"
2351 " Publish a printer")
2354 "remove",
2355 net_ads_printer_remove,
2356 NET_TRANSPORT_ADS,
2357 N_("Delete a printer"),
2358 N_("net ads printer remove\n"
2359 " Delete a printer")
2361 {NULL, NULL, 0, NULL, NULL}
2364 return net_run_function(c, argc, argv, "net ads printer", func);
2368 static int net_ads_password(struct net_context *c, int argc, const char **argv)
2370 ADS_STRUCT *ads;
2371 const char *auth_principal = c->opt_user_name;
2372 const char *auth_password = c->opt_password;
2373 const char *realm = NULL;
2374 const char *new_password = NULL;
2375 char *chr, *prompt;
2376 const char *user;
2377 char pwd[256] = {0};
2378 ADS_STATUS ret;
2380 if (c->display_usage) {
2381 d_printf("%s\n%s",
2382 _("Usage:"),
2383 _("net ads password <username>\n"
2384 " Change password for user\n"
2385 " username\tName of user to change password for\n"));
2386 return 0;
2389 if (c->opt_user_name == NULL || c->opt_password == NULL) {
2390 d_fprintf(stderr, _("You must supply an administrator "
2391 "username/password\n"));
2392 return -1;
2395 if (argc < 1) {
2396 d_fprintf(stderr, _("ERROR: You must say which username to "
2397 "change password for\n"));
2398 return -1;
2401 user = argv[0];
2402 if (!strchr_m(user, '@')) {
2403 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
2404 return -1;
2406 user = chr;
2409 use_in_memory_ccache();
2410 chr = strchr_m(auth_principal, '@');
2411 if (chr) {
2412 realm = ++chr;
2413 } else {
2414 realm = lp_realm();
2417 /* use the realm so we can eventually change passwords for users
2418 in realms other than default */
2419 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
2420 return -1;
2423 /* we don't actually need a full connect, but it's the easy way to
2424 fill in the KDC's addresss */
2425 ads_connect(ads);
2427 if (!ads->config.realm) {
2428 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
2429 ads_destroy(&ads);
2430 return -1;
2433 if (argv[1]) {
2434 new_password = (const char *)argv[1];
2435 } else {
2436 int rc;
2438 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
2439 return -1;
2441 rc = samba_getpass(prompt, pwd, sizeof(pwd), false, true);
2442 if (rc < 0) {
2443 return -1;
2445 new_password = pwd;
2446 free(prompt);
2449 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2450 auth_password, user, new_password, ads->auth.time_offset);
2451 memset(pwd, '\0', sizeof(pwd));
2452 if (!ADS_ERR_OK(ret)) {
2453 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2454 ads_destroy(&ads);
2455 return -1;
2458 d_printf(_("Password change for %s completed.\n"), user);
2459 ads_destroy(&ads);
2461 return 0;
2464 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2466 ADS_STRUCT *ads;
2467 char *host_principal;
2468 fstring my_name;
2469 ADS_STATUS ret;
2471 if (c->display_usage) {
2472 d_printf( "%s\n"
2473 "net ads changetrustpw\n"
2474 " %s\n",
2475 _("Usage:"),
2476 _("Change the machine account's trust password"));
2477 return 0;
2480 if (!secrets_init()) {
2481 DEBUG(1,("Failed to initialise secrets database\n"));
2482 return -1;
2485 net_use_krb_machine_account(c);
2487 use_in_memory_ccache();
2489 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2490 return -1;
2493 fstrcpy(my_name, lp_netbios_name());
2494 if (!strlower_m(my_name)) {
2495 ads_destroy(&ads);
2496 return -1;
2499 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2500 ads_destroy(&ads);
2501 return -1;
2503 d_printf(_("Changing password for principal: %s\n"), host_principal);
2505 ret = ads_change_trust_account_password(ads, host_principal);
2507 if (!ADS_ERR_OK(ret)) {
2508 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2509 ads_destroy(&ads);
2510 SAFE_FREE(host_principal);
2511 return -1;
2514 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2516 if (USE_SYSTEM_KEYTAB) {
2517 d_printf(_("Attempting to update system keytab with new password.\n"));
2518 if (ads_keytab_create_default(ads)) {
2519 d_printf(_("Failed to update system keytab.\n"));
2523 ads_destroy(&ads);
2524 SAFE_FREE(host_principal);
2526 return 0;
2530 help for net ads search
2532 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2534 d_printf(_(
2535 "\nnet ads search <expression> <attributes...>\n"
2536 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2537 "The expression is a standard LDAP search expression, and the\n"
2538 "attributes are a list of LDAP fields to show in the results.\n\n"
2539 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2541 net_common_flags_usage(c, argc, argv);
2542 return -1;
2547 general ADS search function. Useful in diagnosing problems in ADS
2549 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2551 ADS_STRUCT *ads;
2552 ADS_STATUS rc;
2553 const char *ldap_exp;
2554 const char **attrs;
2555 LDAPMessage *res = NULL;
2557 if (argc < 1 || c->display_usage) {
2558 return net_ads_search_usage(c, argc, argv);
2561 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2562 return -1;
2565 ldap_exp = argv[0];
2566 attrs = (argv + 1);
2568 rc = ads_do_search_retry(ads, ads->config.bind_path,
2569 LDAP_SCOPE_SUBTREE,
2570 ldap_exp, attrs, &res);
2571 if (!ADS_ERR_OK(rc)) {
2572 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2573 ads_destroy(&ads);
2574 return -1;
2577 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2579 /* dump the results */
2580 ads_dump(ads, res);
2582 ads_msgfree(ads, res);
2583 ads_destroy(&ads);
2585 return 0;
2590 help for net ads search
2592 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2594 d_printf(_(
2595 "\nnet ads dn <dn> <attributes...>\n"
2596 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2597 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2598 "to show in the results\n\n"
2599 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2600 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2602 net_common_flags_usage(c, argc, argv);
2603 return -1;
2608 general ADS search function. Useful in diagnosing problems in ADS
2610 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2612 ADS_STRUCT *ads;
2613 ADS_STATUS rc;
2614 const char *dn;
2615 const char **attrs;
2616 LDAPMessage *res = NULL;
2618 if (argc < 1 || c->display_usage) {
2619 return net_ads_dn_usage(c, argc, argv);
2622 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2623 return -1;
2626 dn = argv[0];
2627 attrs = (argv + 1);
2629 rc = ads_do_search_all(ads, dn,
2630 LDAP_SCOPE_BASE,
2631 "(objectclass=*)", attrs, &res);
2632 if (!ADS_ERR_OK(rc)) {
2633 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2634 ads_destroy(&ads);
2635 return -1;
2638 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2640 /* dump the results */
2641 ads_dump(ads, res);
2643 ads_msgfree(ads, res);
2644 ads_destroy(&ads);
2646 return 0;
2650 help for net ads sid search
2652 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2654 d_printf(_(
2655 "\nnet ads sid <sid> <attributes...>\n"
2656 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2657 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2658 "to show in the results\n\n"
2659 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2661 net_common_flags_usage(c, argc, argv);
2662 return -1;
2667 general ADS search function. Useful in diagnosing problems in ADS
2669 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2671 ADS_STRUCT *ads;
2672 ADS_STATUS rc;
2673 const char *sid_string;
2674 const char **attrs;
2675 LDAPMessage *res = NULL;
2676 struct dom_sid sid;
2678 if (argc < 1 || c->display_usage) {
2679 return net_ads_sid_usage(c, argc, argv);
2682 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2683 return -1;
2686 sid_string = argv[0];
2687 attrs = (argv + 1);
2689 if (!string_to_sid(&sid, sid_string)) {
2690 d_fprintf(stderr, _("could not convert sid\n"));
2691 ads_destroy(&ads);
2692 return -1;
2695 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2696 if (!ADS_ERR_OK(rc)) {
2697 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2698 ads_destroy(&ads);
2699 return -1;
2702 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2704 /* dump the results */
2705 ads_dump(ads, res);
2707 ads_msgfree(ads, res);
2708 ads_destroy(&ads);
2710 return 0;
2713 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2715 int ret;
2716 ADS_STRUCT *ads;
2718 if (c->display_usage) {
2719 d_printf( "%s\n"
2720 "net ads keytab flush\n"
2721 " %s\n",
2722 _("Usage:"),
2723 _("Delete the whole keytab"));
2724 return 0;
2727 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2728 return -1;
2730 ret = ads_keytab_flush(ads);
2731 ads_destroy(&ads);
2732 return ret;
2735 static int net_ads_keytab_add(struct net_context *c,
2736 int argc,
2737 const char **argv,
2738 bool update_ads)
2740 int i;
2741 int ret = 0;
2742 ADS_STRUCT *ads;
2744 if (c->display_usage) {
2745 d_printf("%s\n%s",
2746 _("Usage:"),
2747 _("net ads keytab add <principal> [principal ...]\n"
2748 " Add principals to local keytab\n"
2749 " principal\tKerberos principal to add to "
2750 "keytab\n"));
2751 return 0;
2754 d_printf(_("Processing principals to add...\n"));
2755 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2756 return -1;
2758 for (i = 0; i < argc; i++) {
2759 ret |= ads_keytab_add_entry(ads, argv[i], update_ads);
2761 ads_destroy(&ads);
2762 return ret;
2765 static int net_ads_keytab_add_default(struct net_context *c,
2766 int argc,
2767 const char **argv)
2769 return net_ads_keytab_add(c, argc, argv, false);
2772 static int net_ads_keytab_add_update_ads(struct net_context *c,
2773 int argc,
2774 const char **argv)
2776 return net_ads_keytab_add(c, argc, argv, true);
2779 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2781 ADS_STRUCT *ads;
2782 int ret;
2784 if (c->display_usage) {
2785 d_printf( "%s\n"
2786 "net ads keytab create\n"
2787 " %s\n",
2788 _("Usage:"),
2789 _("Create new default keytab"));
2790 return 0;
2793 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2794 return -1;
2796 ret = ads_keytab_create_default(ads);
2797 ads_destroy(&ads);
2798 return ret;
2801 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2803 const char *keytab = NULL;
2805 if (c->display_usage) {
2806 d_printf("%s\n%s",
2807 _("Usage:"),
2808 _("net ads keytab list [keytab]\n"
2809 " List a local keytab\n"
2810 " keytab\tKeytab to list\n"));
2811 return 0;
2814 if (argc >= 1) {
2815 keytab = argv[0];
2818 return ads_keytab_list(keytab);
2822 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2824 struct functable func[] = {
2826 "add",
2827 net_ads_keytab_add_default,
2828 NET_TRANSPORT_ADS,
2829 N_("Add a service principal"),
2830 N_("net ads keytab add\n"
2831 " Add a service principal, updates keytab file only.")
2834 "add_update_ads",
2835 net_ads_keytab_add_update_ads,
2836 NET_TRANSPORT_ADS,
2837 N_("Add a service principal"),
2838 N_("net ads keytab add_update_ads\n"
2839 " Add a service principal, depending on the param passed may update ADS computer object in addition to the keytab file.")
2842 "create",
2843 net_ads_keytab_create,
2844 NET_TRANSPORT_ADS,
2845 N_("Create a fresh keytab"),
2846 N_("net ads keytab create\n"
2847 " Create a fresh keytab or update exising one.")
2850 "flush",
2851 net_ads_keytab_flush,
2852 NET_TRANSPORT_ADS,
2853 N_("Remove all keytab entries"),
2854 N_("net ads keytab flush\n"
2855 " Remove all keytab entries")
2858 "list",
2859 net_ads_keytab_list,
2860 NET_TRANSPORT_ADS,
2861 N_("List a keytab"),
2862 N_("net ads keytab list\n"
2863 " List a keytab")
2865 {NULL, NULL, 0, NULL, NULL}
2868 if (!USE_KERBEROS_KEYTAB) {
2869 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2870 "keytab method to use keytab functions.\n"));
2873 return net_run_function(c, argc, argv, "net ads keytab", func);
2876 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2878 int ret = -1;
2880 if (c->display_usage) {
2881 d_printf( "%s\n"
2882 "net ads kerberos renew\n"
2883 " %s\n",
2884 _("Usage:"),
2885 _("Renew TGT from existing credential cache"));
2886 return 0;
2889 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2890 if (ret) {
2891 d_printf(_("failed to renew kerberos ticket: %s\n"),
2892 error_message(ret));
2894 return ret;
2897 static int net_ads_kerberos_pac_common(struct net_context *c, int argc, const char **argv,
2898 struct PAC_DATA_CTR **pac_data_ctr)
2900 NTSTATUS status;
2901 int ret = -1;
2902 const char *impersonate_princ_s = NULL;
2903 const char *local_service = NULL;
2904 int i;
2906 for (i=0; i<argc; i++) {
2907 if (strnequal(argv[i], "impersonate", strlen("impersonate"))) {
2908 impersonate_princ_s = get_string_param(argv[i]);
2909 if (impersonate_princ_s == NULL) {
2910 return -1;
2913 if (strnequal(argv[i], "local_service", strlen("local_service"))) {
2914 local_service = get_string_param(argv[i]);
2915 if (local_service == NULL) {
2916 return -1;
2921 if (local_service == NULL) {
2922 local_service = talloc_asprintf(c, "%s$@%s",
2923 lp_netbios_name(), lp_realm());
2924 if (local_service == NULL) {
2925 goto out;
2929 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2931 status = kerberos_return_pac(c,
2932 c->opt_user_name,
2933 c->opt_password,
2935 NULL,
2936 NULL,
2937 NULL,
2938 true,
2939 true,
2940 2592000, /* one month */
2941 impersonate_princ_s,
2942 local_service,
2943 pac_data_ctr);
2944 if (!NT_STATUS_IS_OK(status)) {
2945 d_printf(_("failed to query kerberos PAC: %s\n"),
2946 nt_errstr(status));
2947 goto out;
2950 ret = 0;
2951 out:
2952 return ret;
2955 static int net_ads_kerberos_pac_dump(struct net_context *c, int argc, const char **argv)
2957 struct PAC_DATA_CTR *pac_data_ctr = NULL;
2958 int i;
2959 int ret = -1;
2960 enum PAC_TYPE type = 0;
2962 if (c->display_usage) {
2963 d_printf( "%s\n"
2964 "net ads kerberos pac dump [impersonate=string] [local_service=string] [pac_buffer_type=int]\n"
2965 " %s\n",
2966 _("Usage:"),
2967 _("Dump the Kerberos PAC"));
2968 return -1;
2971 for (i=0; i<argc; i++) {
2972 if (strnequal(argv[i], "pac_buffer_type", strlen("pac_buffer_type"))) {
2973 type = get_int_param(argv[i]);
2977 ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
2978 if (ret) {
2979 return ret;
2982 if (type == 0) {
2984 char *s = NULL;
2986 s = NDR_PRINT_STRUCT_STRING(c, PAC_DATA,
2987 pac_data_ctr->pac_data);
2988 if (s != NULL) {
2989 d_printf(_("The Pac: %s\n"), s);
2990 talloc_free(s);
2993 return 0;
2996 for (i=0; i < pac_data_ctr->pac_data->num_buffers; i++) {
2998 char *s = NULL;
3000 if (pac_data_ctr->pac_data->buffers[i].type != type) {
3001 continue;
3004 s = NDR_PRINT_UNION_STRING(c, PAC_INFO, type,
3005 pac_data_ctr->pac_data->buffers[i].info);
3006 if (s != NULL) {
3007 d_printf(_("The Pac: %s\n"), s);
3008 talloc_free(s);
3010 break;
3013 return 0;
3016 static int net_ads_kerberos_pac_save(struct net_context *c, int argc, const char **argv)
3018 struct PAC_DATA_CTR *pac_data_ctr = NULL;
3019 char *filename = NULL;
3020 int ret = -1;
3021 int i;
3023 if (c->display_usage) {
3024 d_printf( "%s\n"
3025 "net ads kerberos pac save [impersonate=string] [local_service=string] [filename=string]\n"
3026 " %s\n",
3027 _("Usage:"),
3028 _("Save the Kerberos PAC"));
3029 return -1;
3032 for (i=0; i<argc; i++) {
3033 if (strnequal(argv[i], "filename", strlen("filename"))) {
3034 filename = get_string_param(argv[i]);
3035 if (filename == NULL) {
3036 return -1;
3041 ret = net_ads_kerberos_pac_common(c, argc, argv, &pac_data_ctr);
3042 if (ret) {
3043 return ret;
3046 if (filename == NULL) {
3047 d_printf(_("please define \"filename=<filename>\" to save the PAC\n"));
3048 return -1;
3051 /* save the raw format */
3052 if (!file_save(filename, pac_data_ctr->pac_blob.data, pac_data_ctr->pac_blob.length)) {
3053 d_printf(_("failed to save PAC in %s\n"), filename);
3054 return -1;
3057 return 0;
3060 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
3062 struct functable func[] = {
3064 "dump",
3065 net_ads_kerberos_pac_dump,
3066 NET_TRANSPORT_ADS,
3067 N_("Dump Kerberos PAC"),
3068 N_("net ads kerberos pac dump\n"
3069 " Dump a Kerberos PAC to stdout")
3072 "save",
3073 net_ads_kerberos_pac_save,
3074 NET_TRANSPORT_ADS,
3075 N_("Save Kerberos PAC"),
3076 N_("net ads kerberos pac save\n"
3077 " Save a Kerberos PAC in a file")
3080 {NULL, NULL, 0, NULL, NULL}
3083 return net_run_function(c, argc, argv, "net ads kerberos pac", func);
3086 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
3088 TALLOC_CTX *mem_ctx = NULL;
3089 int ret = -1;
3090 NTSTATUS status;
3092 if (c->display_usage) {
3093 d_printf( "%s\n"
3094 "net ads kerberos kinit\n"
3095 " %s\n",
3096 _("Usage:"),
3097 _("Get Ticket Granting Ticket (TGT) for the user"));
3098 return 0;
3101 mem_ctx = talloc_init("net_ads_kerberos_kinit");
3102 if (!mem_ctx) {
3103 goto out;
3106 c->opt_password = net_prompt_pass(c, c->opt_user_name);
3108 ret = kerberos_kinit_password_ext(c->opt_user_name,
3109 c->opt_password,
3111 NULL,
3112 NULL,
3113 NULL,
3114 true,
3115 true,
3116 2592000, /* one month */
3117 &status);
3118 if (ret) {
3119 d_printf(_("failed to kinit password: %s\n"),
3120 nt_errstr(status));
3122 out:
3123 return ret;
3126 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3128 struct functable func[] = {
3130 "kinit",
3131 net_ads_kerberos_kinit,
3132 NET_TRANSPORT_ADS,
3133 N_("Retrieve Ticket Granting Ticket (TGT)"),
3134 N_("net ads kerberos kinit\n"
3135 " Receive Ticket Granting Ticket (TGT)")
3138 "renew",
3139 net_ads_kerberos_renew,
3140 NET_TRANSPORT_ADS,
3141 N_("Renew Ticket Granting Ticket from credential cache"),
3142 N_("net ads kerberos renew\n"
3143 " Renew Ticket Granting Ticket (TGT) from "
3144 "credential cache")
3147 "pac",
3148 net_ads_kerberos_pac,
3149 NET_TRANSPORT_ADS,
3150 N_("Dump Kerberos PAC"),
3151 N_("net ads kerberos pac\n"
3152 " Dump Kerberos PAC")
3154 {NULL, NULL, 0, NULL, NULL}
3157 return net_run_function(c, argc, argv, "net ads kerberos", func);
3160 static int net_ads_setspn_list(struct net_context *c, int argc, const char **argv)
3162 int ret = 0;
3163 bool ok = false;
3164 ADS_STRUCT *ads = NULL;
3165 if (c->display_usage) {
3166 d_printf("%s\n%s",
3167 _("Usage:"),
3168 _("net ads setspn list <machinename>\n"));
3169 ret = 0;
3170 goto done;
3172 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3173 ret = -1;
3174 goto done;
3176 if (argc) {
3177 ok = ads_setspn_list(ads, argv[0]);
3178 } else {
3179 ok = ads_setspn_list(ads, lp_netbios_name());
3181 if (!ok) {
3182 ret = -1;
3184 done:
3185 if (ads) {
3186 ads_destroy(&ads);
3188 return ret;
3191 static int net_ads_setspn_add(struct net_context *c, int argc, const char **argv)
3193 int ret = 0;
3194 bool ok = false;
3195 ADS_STRUCT *ads = NULL;
3196 if (c->display_usage || argc < 1) {
3197 d_printf("%s\n%s",
3198 _("Usage:"),
3199 _("net ads setspn add <machinename> SPN\n"));
3200 ret = 0;
3201 goto done;
3203 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3204 ret = -1;
3205 goto done;
3207 if (argc > 1) {
3208 ok = ads_setspn_add(ads, argv[0], argv[1]);
3209 } else {
3210 ok = ads_setspn_add(ads, lp_netbios_name(), argv[0]);
3212 if (!ok) {
3213 ret = -1;
3215 done:
3216 if (ads) {
3217 ads_destroy(&ads);
3219 return ret;
3222 static int net_ads_setspn_delete(struct net_context *c, int argc, const char **argv)
3224 int ret = 0;
3225 bool ok = false;
3226 ADS_STRUCT *ads = NULL;
3227 if (c->display_usage || argc < 1) {
3228 d_printf("%s\n%s",
3229 _("Usage:"),
3230 _("net ads setspn delete <machinename> SPN\n"));
3231 ret = 0;
3232 goto done;
3234 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
3235 ret = -1;
3236 goto done;
3238 if (argc > 1) {
3239 ok = ads_setspn_delete(ads, argv[0], argv[1]);
3240 } else {
3241 ok = ads_setspn_delete(ads, lp_netbios_name(), argv[0]);
3243 if (!ok) {
3244 ret = -1;
3246 done:
3247 if (ads) {
3248 ads_destroy(&ads);
3250 return ret;
3253 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
3255 struct functable func[] = {
3257 "list",
3258 net_ads_setspn_list,
3259 NET_TRANSPORT_ADS,
3260 N_("List Service Principal Names (SPN)"),
3261 N_("net ads setspn list machine\n"
3262 " List Service Principal Names (SPN)")
3265 "add",
3266 net_ads_setspn_add,
3267 NET_TRANSPORT_ADS,
3268 N_("Add Service Principal Names (SPN)"),
3269 N_("net ads setspn add machine spn\n"
3270 " Add Service Principal Names (SPN)")
3273 "delete",
3274 net_ads_setspn_delete,
3275 NET_TRANSPORT_ADS,
3276 N_("Delete Service Principal Names (SPN)"),
3277 N_("net ads setspn delete machine spn\n"
3278 " Delete Service Principal Names (SPN)")
3280 {NULL, NULL, 0, NULL, NULL}
3283 return net_run_function(c, argc, argv, "net ads setspn", func);
3286 static int net_ads_enctype_lookup_account(struct net_context *c,
3287 ADS_STRUCT *ads,
3288 const char *account,
3289 LDAPMessage **res,
3290 const char **enctype_str)
3292 const char *filter;
3293 const char *attrs[] = {
3294 "msDS-SupportedEncryptionTypes",
3295 NULL
3297 int count;
3298 int ret = -1;
3299 ADS_STATUS status;
3301 filter = talloc_asprintf(c, "(&(objectclass=user)(sAMAccountName=%s))",
3302 account);
3303 if (filter == NULL) {
3304 goto done;
3307 status = ads_search(ads, res, filter, attrs);
3308 if (!ADS_ERR_OK(status)) {
3309 d_printf(_("no account found with filter: %s\n"), filter);
3310 goto done;
3313 count = ads_count_replies(ads, *res);
3314 switch (count) {
3315 case 1:
3316 break;
3317 case 0:
3318 d_printf(_("no account found with filter: %s\n"), filter);
3319 goto done;
3320 default:
3321 d_printf(_("multiple accounts found with filter: %s\n"), filter);
3322 goto done;
3325 if (enctype_str) {
3326 *enctype_str = ads_pull_string(ads, c, *res,
3327 "msDS-SupportedEncryptionTypes");
3328 if (*enctype_str == NULL) {
3329 d_printf(_("no msDS-SupportedEncryptionTypes attribute found\n"));
3330 goto done;
3334 ret = 0;
3335 done:
3336 return ret;
3339 static void net_ads_enctype_dump_enctypes(const char *username,
3340 const char *enctype_str)
3342 int enctypes = atoi(enctype_str);
3344 d_printf(_("'%s' uses \"msDS-SupportedEncryptionTypes\": %d (0x%08x)\n"),
3345 username, enctypes, enctypes);
3347 printf("[%s] 0x%08x DES-CBC-CRC\n",
3348 enctypes & ENC_CRC32 ? "X" : " ",
3349 ENC_CRC32);
3350 printf("[%s] 0x%08x DES-CBC-MD5\n",
3351 enctypes & ENC_RSA_MD5 ? "X" : " ",
3352 ENC_RSA_MD5);
3353 printf("[%s] 0x%08x RC4-HMAC\n",
3354 enctypes & ENC_RC4_HMAC_MD5 ? "X" : " ",
3355 ENC_RC4_HMAC_MD5);
3356 printf("[%s] 0x%08x AES128-CTS-HMAC-SHA1-96\n",
3357 enctypes & ENC_HMAC_SHA1_96_AES128 ? "X" : " ",
3358 ENC_HMAC_SHA1_96_AES128);
3359 printf("[%s] 0x%08x AES256-CTS-HMAC-SHA1-96\n",
3360 enctypes & ENC_HMAC_SHA1_96_AES256 ? "X" : " ",
3361 ENC_HMAC_SHA1_96_AES256);
3364 static int net_ads_enctypes_list(struct net_context *c, int argc, const char **argv)
3366 int ret = -1;
3367 ADS_STATUS status;
3368 ADS_STRUCT *ads = NULL;
3369 LDAPMessage *res = NULL;
3370 const char *str = NULL;
3372 if (c->display_usage || (argc < 1)) {
3373 d_printf( "%s\n"
3374 "net ads enctypes list\n"
3375 " %s\n",
3376 _("Usage:"),
3377 _("List supported enctypes"));
3378 return 0;
3381 status = ads_startup(c, false, &ads);
3382 if (!ADS_ERR_OK(status)) {
3383 printf("startup failed\n");
3384 return ret;
3387 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3388 if (ret) {
3389 goto done;
3392 net_ads_enctype_dump_enctypes(argv[0], str);
3394 ret = 0;
3395 done:
3396 ads_msgfree(ads, res);
3397 ads_destroy(&ads);
3399 return ret;
3402 static int net_ads_enctypes_set(struct net_context *c, int argc, const char **argv)
3404 int ret = -1;
3405 ADS_STATUS status;
3406 ADS_STRUCT *ads;
3407 LDAPMessage *res = NULL;
3408 const char *etype_list_str;
3409 const char *dn;
3410 ADS_MODLIST mods;
3411 uint32_t etype_list;
3412 const char *str;
3414 if (c->display_usage || argc < 1) {
3415 d_printf( "%s\n"
3416 "net ads enctypes set <sAMAccountName> [enctypes]\n"
3417 " %s\n",
3418 _("Usage:"),
3419 _("Set supported enctypes"));
3420 return 0;
3423 status = ads_startup(c, false, &ads);
3424 if (!ADS_ERR_OK(status)) {
3425 printf("startup failed\n");
3426 return ret;
3429 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3430 if (ret) {
3431 goto done;
3434 dn = ads_get_dn(ads, c, res);
3435 if (dn == NULL) {
3436 goto done;
3439 etype_list = ENC_CRC32 | ENC_RSA_MD5 | ENC_RC4_HMAC_MD5;
3440 #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
3441 etype_list |= ENC_HMAC_SHA1_96_AES128;
3442 #endif
3443 #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
3444 etype_list |= ENC_HMAC_SHA1_96_AES256;
3445 #endif
3447 if (argv[1] != NULL) {
3448 sscanf(argv[1], "%i", &etype_list);
3451 etype_list_str = talloc_asprintf(c, "%d", etype_list);
3452 if (!etype_list_str) {
3453 goto done;
3456 mods = ads_init_mods(c);
3457 if (!mods) {
3458 goto done;
3461 status = ads_mod_str(c, &mods, "msDS-SupportedEncryptionTypes",
3462 etype_list_str);
3463 if (!ADS_ERR_OK(status)) {
3464 goto done;
3467 status = ads_gen_mod(ads, dn, mods);
3468 if (!ADS_ERR_OK(status)) {
3469 d_printf(_("failed to add msDS-SupportedEncryptionTypes: %s\n"),
3470 ads_errstr(status));
3471 goto done;
3474 ads_msgfree(ads, res);
3476 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, &str);
3477 if (ret) {
3478 goto done;
3481 net_ads_enctype_dump_enctypes(argv[0], str);
3483 ret = 0;
3484 done:
3485 ads_msgfree(ads, res);
3486 ads_destroy(&ads);
3488 return ret;
3491 static int net_ads_enctypes_delete(struct net_context *c, int argc, const char **argv)
3493 int ret = -1;
3494 ADS_STATUS status;
3495 ADS_STRUCT *ads;
3496 LDAPMessage *res = NULL;
3497 const char *dn;
3498 ADS_MODLIST mods;
3500 if (c->display_usage || argc < 1) {
3501 d_printf( "%s\n"
3502 "net ads enctypes delete <sAMAccountName>\n"
3503 " %s\n",
3504 _("Usage:"),
3505 _("Delete supported enctypes"));
3506 return 0;
3509 status = ads_startup(c, false, &ads);
3510 if (!ADS_ERR_OK(status)) {
3511 printf("startup failed\n");
3512 return ret;
3515 ret = net_ads_enctype_lookup_account(c, ads, argv[0], &res, NULL);
3516 if (ret) {
3517 goto done;
3520 dn = ads_get_dn(ads, c, res);
3521 if (dn == NULL) {
3522 goto done;
3525 mods = ads_init_mods(c);
3526 if (!mods) {
3527 goto done;
3530 status = ads_mod_str(c, &mods, "msDS-SupportedEncryptionTypes", NULL);
3531 if (!ADS_ERR_OK(status)) {
3532 goto done;
3535 status = ads_gen_mod(ads, dn, mods);
3536 if (!ADS_ERR_OK(status)) {
3537 d_printf(_("failed to remove msDS-SupportedEncryptionTypes: %s\n"),
3538 ads_errstr(status));
3539 goto done;
3542 ret = 0;
3544 done:
3545 ads_msgfree(ads, res);
3546 ads_destroy(&ads);
3547 return ret;
3550 static int net_ads_enctypes(struct net_context *c, int argc, const char **argv)
3552 struct functable func[] = {
3554 "list",
3555 net_ads_enctypes_list,
3556 NET_TRANSPORT_ADS,
3557 N_("List the supported encryption types"),
3558 N_("net ads enctypes list\n"
3559 " List the supported encryption types")
3562 "set",
3563 net_ads_enctypes_set,
3564 NET_TRANSPORT_ADS,
3565 N_("Set the supported encryption types"),
3566 N_("net ads enctypes set\n"
3567 " Set the supported encryption types")
3570 "delete",
3571 net_ads_enctypes_delete,
3572 NET_TRANSPORT_ADS,
3573 N_("Delete the supported encryption types"),
3574 N_("net ads enctypes delete\n"
3575 " Delete the supported encryption types")
3578 {NULL, NULL, 0, NULL, NULL}
3581 return net_run_function(c, argc, argv, "net ads enctypes", func);
3585 int net_ads(struct net_context *c, int argc, const char **argv)
3587 struct functable func[] = {
3589 "info",
3590 net_ads_info,
3591 NET_TRANSPORT_ADS,
3592 N_("Display details on remote ADS server"),
3593 N_("net ads info\n"
3594 " Display details on remote ADS server")
3597 "join",
3598 net_ads_join,
3599 NET_TRANSPORT_ADS,
3600 N_("Join the local machine to ADS realm"),
3601 N_("net ads join\n"
3602 " Join the local machine to ADS realm")
3605 "testjoin",
3606 net_ads_testjoin,
3607 NET_TRANSPORT_ADS,
3608 N_("Validate machine account"),
3609 N_("net ads testjoin\n"
3610 " Validate machine account")
3613 "leave",
3614 net_ads_leave,
3615 NET_TRANSPORT_ADS,
3616 N_("Remove the local machine from ADS"),
3617 N_("net ads leave\n"
3618 " Remove the local machine from ADS")
3621 "status",
3622 net_ads_status,
3623 NET_TRANSPORT_ADS,
3624 N_("Display machine account details"),
3625 N_("net ads status\n"
3626 " Display machine account details")
3629 "user",
3630 net_ads_user,
3631 NET_TRANSPORT_ADS,
3632 N_("List/modify users"),
3633 N_("net ads user\n"
3634 " List/modify users")
3637 "group",
3638 net_ads_group,
3639 NET_TRANSPORT_ADS,
3640 N_("List/modify groups"),
3641 N_("net ads group\n"
3642 " List/modify groups")
3645 "dns",
3646 net_ads_dns,
3647 NET_TRANSPORT_ADS,
3648 N_("Issue dynamic DNS update"),
3649 N_("net ads dns\n"
3650 " Issue dynamic DNS update")
3653 "password",
3654 net_ads_password,
3655 NET_TRANSPORT_ADS,
3656 N_("Change user passwords"),
3657 N_("net ads password\n"
3658 " Change user passwords")
3661 "changetrustpw",
3662 net_ads_changetrustpw,
3663 NET_TRANSPORT_ADS,
3664 N_("Change trust account password"),
3665 N_("net ads changetrustpw\n"
3666 " Change trust account password")
3669 "printer",
3670 net_ads_printer,
3671 NET_TRANSPORT_ADS,
3672 N_("List/modify printer entries"),
3673 N_("net ads printer\n"
3674 " List/modify printer entries")
3677 "search",
3678 net_ads_search,
3679 NET_TRANSPORT_ADS,
3680 N_("Issue LDAP search using filter"),
3681 N_("net ads search\n"
3682 " Issue LDAP search using filter")
3685 "dn",
3686 net_ads_dn,
3687 NET_TRANSPORT_ADS,
3688 N_("Issue LDAP search by DN"),
3689 N_("net ads dn\n"
3690 " Issue LDAP search by DN")
3693 "sid",
3694 net_ads_sid,
3695 NET_TRANSPORT_ADS,
3696 N_("Issue LDAP search by SID"),
3697 N_("net ads sid\n"
3698 " Issue LDAP search by SID")
3701 "workgroup",
3702 net_ads_workgroup,
3703 NET_TRANSPORT_ADS,
3704 N_("Display workgroup name"),
3705 N_("net ads workgroup\n"
3706 " Display the workgroup name")
3709 "lookup",
3710 net_ads_lookup,
3711 NET_TRANSPORT_ADS,
3712 N_("Perform CLDAP query on DC"),
3713 N_("net ads lookup\n"
3714 " Find the ADS DC using CLDAP lookups")
3717 "keytab",
3718 net_ads_keytab,
3719 NET_TRANSPORT_ADS,
3720 N_("Manage local keytab file"),
3721 N_("net ads keytab\n"
3722 " Manage local keytab file")
3725 "setspn",
3726 net_ads_setspn,
3727 NET_TRANSPORT_ADS,
3728 N_("Manage Service Principal Names (SPN)s"),
3729 N_("net ads spnset\n"
3730 " Manage Service Principal Names (SPN)s")
3733 "gpo",
3734 net_ads_gpo,
3735 NET_TRANSPORT_ADS,
3736 N_("Manage group policy objects"),
3737 N_("net ads gpo\n"
3738 " Manage group policy objects")
3741 "kerberos",
3742 net_ads_kerberos,
3743 NET_TRANSPORT_ADS,
3744 N_("Manage kerberos keytab"),
3745 N_("net ads kerberos\n"
3746 " Manage kerberos keytab")
3749 "enctypes",
3750 net_ads_enctypes,
3751 NET_TRANSPORT_ADS,
3752 N_("List/modify supported encryption types"),
3753 N_("net ads enctypes\n"
3754 " List/modify enctypes")
3756 {NULL, NULL, 0, NULL, NULL}
3759 return net_run_function(c, argc, argv, "net ads", func);
3762 #else
3764 static int net_ads_noads(void)
3766 d_fprintf(stderr, _("ADS support not compiled in\n"));
3767 return -1;
3770 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
3772 return net_ads_noads();
3775 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
3777 return net_ads_noads();
3780 int net_ads_setspn(struct net_context *c, int argc, const char **argv)
3782 return net_ads_noads();
3785 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
3787 return net_ads_noads();
3790 int net_ads_join(struct net_context *c, int argc, const char **argv)
3792 return net_ads_noads();
3795 int net_ads_user(struct net_context *c, int argc, const char **argv)
3797 return net_ads_noads();
3800 int net_ads_group(struct net_context *c, int argc, const char **argv)
3802 return net_ads_noads();
3805 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
3807 return net_ads_noads();
3810 /* this one shouldn't display a message */
3811 int net_ads_check(struct net_context *c)
3813 return -1;
3816 int net_ads_check_our_domain(struct net_context *c)
3818 return -1;
3821 int net_ads(struct net_context *c, int argc, const char **argv)
3823 return net_ads_noads();
3826 #endif /* HAVE_ADS */