s3-net: pass down struct net_context to the dns update calls.
[Samba/gebeck_regimport.git] / source3 / utils / net_ads.c
blob3b671fc600101fb667002cfe8b289959661c6ecb
1 /*
2 Samba Unix/Linux SMB client library
3 net ads commands
4 Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
5 Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
6 Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
7 Copyright (C) 2006 Gerald (Jerry) Carter (jerry@samba.org)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "utils/net.h"
25 #include "rpc_client/cli_pipe.h"
26 #include "librpc/gen_ndr/ndr_krb5pac.h"
27 #include "../librpc/gen_ndr/ndr_spoolss.h"
28 #include "nsswitch/libwbclient/wbclient.h"
29 #include "ads.h"
30 #include "libads/cldap.h"
31 #include "../lib/addns/dnsquery.h"
32 #include "../libds/common/flags.h"
33 #include "librpc/gen_ndr/libnet_join.h"
34 #include "libnet/libnet_join.h"
35 #include "smb_krb5.h"
36 #include "secrets.h"
37 #include "krb5_env.h"
38 #include "../libcli/security/security.h"
39 #include "libsmb/libsmb.h"
40 #include "lib/param/loadparm.h"
42 #ifdef HAVE_ADS
44 /* when we do not have sufficient input parameters to contact a remote domain
45 * we always fall back to our own realm - Guenther*/
47 static const char *assume_own_realm(struct net_context *c)
49 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
50 return lp_realm();
53 return NULL;
57 do a cldap netlogon query
59 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
61 char addr[INET6_ADDRSTRLEN];
62 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
64 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
66 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads->ldap.ss, ads->server.realm, &reply ) ) {
67 d_fprintf(stderr, _("CLDAP query failed!\n"));
68 return -1;
71 d_printf(_("Information for Domain Controller: %s\n\n"),
72 addr);
74 d_printf(_("Response Type: "));
75 switch (reply.command) {
76 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
77 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
78 break;
79 case LOGON_SAM_LOGON_RESPONSE_EX:
80 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
81 break;
82 default:
83 d_printf("0x%x\n", reply.command);
84 break;
87 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
89 d_printf(_("Flags:\n"
90 "\tIs a PDC: %s\n"
91 "\tIs a GC of the forest: %s\n"
92 "\tIs an LDAP server: %s\n"
93 "\tSupports DS: %s\n"
94 "\tIs running a KDC: %s\n"
95 "\tIs running time services: %s\n"
96 "\tIs the closest DC: %s\n"
97 "\tIs writable: %s\n"
98 "\tHas a hardware clock: %s\n"
99 "\tIs a non-domain NC serviced by LDAP server: %s\n"
100 "\tIs NT6 DC that has some secrets: %s\n"
101 "\tIs NT6 DC that has all secrets: %s\n"),
102 (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
103 (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
104 (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
105 (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
106 (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
107 (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
108 (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
109 (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
110 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
111 (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
112 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
113 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"));
116 printf(_("Forest:\t\t\t%s\n"), reply.forest);
117 printf(_("Domain:\t\t\t%s\n"), reply.dns_domain);
118 printf(_("Domain Controller:\t%s\n"), reply.pdc_dns_name);
120 printf(_("Pre-Win2k Domain:\t%s\n"), reply.domain_name);
121 printf(_("Pre-Win2k Hostname:\t%s\n"), reply.pdc_name);
123 if (*reply.user_name) printf(_("User name:\t%s\n"), reply.user_name);
125 printf(_("Server Site Name :\t\t%s\n"), reply.server_site);
126 printf(_("Client Site Name :\t\t%s\n"), reply.client_site);
128 d_printf(_("NT Version: %d\n"), reply.nt_version);
129 d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
130 d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
132 return 0;
136 this implements the CLDAP based netlogon lookup requests
137 for finding the domain controller of a ADS domain
139 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
141 ADS_STRUCT *ads;
142 int ret;
144 if (c->display_usage) {
145 d_printf("%s\n"
146 "net ads lookup\n"
147 " %s",
148 _("Usage:"),
149 _("Find the ADS DC using CLDAP lookup.\n"));
150 return 0;
153 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
154 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
155 ads_destroy(&ads);
156 return -1;
159 if (!ads->config.realm) {
160 ads->config.realm = discard_const_p(char, c->opt_target_workgroup);
161 ads->ldap.port = 389;
164 ret = net_ads_cldap_netlogon(c, ads);
165 ads_destroy(&ads);
166 return ret;
171 static int net_ads_info(struct net_context *c, int argc, const char **argv)
173 ADS_STRUCT *ads;
174 char addr[INET6_ADDRSTRLEN];
176 if (c->display_usage) {
177 d_printf("%s\n"
178 "net ads info\n"
179 " %s",
180 _("Usage:"),
181 _("Display information about an Active Directory "
182 "server.\n"));
183 return 0;
186 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
187 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
188 return -1;
191 if (!ads || !ads->config.realm) {
192 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
193 ads_destroy(&ads);
194 return -1;
197 /* Try to set the server's current time since we didn't do a full
198 TCP LDAP session initially */
200 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
201 d_fprintf( stderr, _("Failed to get server's current time!\n"));
204 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
206 d_printf(_("LDAP server: %s\n"), addr);
207 d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
208 d_printf(_("Realm: %s\n"), ads->config.realm);
209 d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
210 d_printf(_("LDAP port: %d\n"), ads->ldap.port);
211 d_printf(_("Server time: %s\n"),
212 http_timestring(talloc_tos(), ads->config.current_time));
214 d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
215 d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
217 ads_destroy(&ads);
218 return 0;
221 static void use_in_memory_ccache(void) {
222 /* Use in-memory credentials cache so we do not interfere with
223 * existing credentials */
224 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
227 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
228 uint32 auth_flags, ADS_STRUCT **ads_ret)
230 ADS_STRUCT *ads = NULL;
231 ADS_STATUS status;
232 bool need_password = false;
233 bool second_time = false;
234 char *cp;
235 const char *realm = NULL;
236 bool tried_closest_dc = false;
238 /* lp_realm() should be handled by a command line param,
239 However, the join requires that realm be set in smb.conf
240 and compares our realm with the remote server's so this is
241 ok until someone needs more flexibility */
243 *ads_ret = NULL;
245 retry_connect:
246 if (only_own_domain) {
247 realm = lp_realm();
248 } else {
249 realm = assume_own_realm(c);
252 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
254 if (!c->opt_user_name) {
255 c->opt_user_name = "administrator";
258 if (c->opt_user_specified) {
259 need_password = true;
262 retry:
263 if (!c->opt_password && need_password && !c->opt_machine_pass) {
264 c->opt_password = net_prompt_pass(c, c->opt_user_name);
265 if (!c->opt_password) {
266 ads_destroy(&ads);
267 return ADS_ERROR(LDAP_NO_MEMORY);
271 if (c->opt_password) {
272 use_in_memory_ccache();
273 SAFE_FREE(ads->auth.password);
274 ads->auth.password = smb_xstrdup(c->opt_password);
277 ads->auth.flags |= auth_flags;
278 SAFE_FREE(ads->auth.user_name);
279 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
282 * If the username is of the form "name@realm",
283 * extract the realm and convert to upper case.
284 * This is only used to establish the connection.
286 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
287 *cp++ = '\0';
288 SAFE_FREE(ads->auth.realm);
289 ads->auth.realm = smb_xstrdup(cp);
290 if (!strupper_m(ads->auth.realm)) {
291 ads_destroy(&ads);
292 return ADS_ERROR(LDAP_NO_MEMORY);
296 status = ads_connect(ads);
298 if (!ADS_ERR_OK(status)) {
300 if (NT_STATUS_EQUAL(ads_ntstatus(status),
301 NT_STATUS_NO_LOGON_SERVERS)) {
302 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
303 ads_destroy(&ads);
304 return status;
307 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
308 need_password = true;
309 second_time = true;
310 goto retry;
311 } else {
312 ads_destroy(&ads);
313 return status;
317 /* when contacting our own domain, make sure we use the closest DC.
318 * This is done by reconnecting to ADS because only the first call to
319 * ads_connect will give us our own sitename */
321 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
323 tried_closest_dc = true; /* avoid loop */
325 if (!ads_closest_dc(ads)) {
327 namecache_delete(ads->server.realm, 0x1C);
328 namecache_delete(ads->server.workgroup, 0x1C);
330 ads_destroy(&ads);
331 ads = NULL;
333 goto retry_connect;
337 *ads_ret = ads;
338 return status;
341 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
343 return ads_startup_int(c, only_own_domain, 0, ads);
346 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
348 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
352 Check to see if connection can be made via ads.
353 ads_startup() stores the password in opt_password if it needs to so
354 that rpc or rap can use it without re-prompting.
356 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
358 ADS_STRUCT *ads;
359 ADS_STATUS status;
361 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
362 return -1;
365 ads->auth.flags |= ADS_AUTH_NO_BIND;
367 status = ads_connect(ads);
368 if ( !ADS_ERR_OK(status) ) {
369 return -1;
372 ads_destroy(&ads);
373 return 0;
376 int net_ads_check_our_domain(struct net_context *c)
378 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
381 int net_ads_check(struct net_context *c)
383 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
387 determine the netbios workgroup name for a domain
389 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
391 ADS_STRUCT *ads;
392 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
394 if (c->display_usage) {
395 d_printf ("%s\n"
396 "net ads workgroup\n"
397 " %s\n",
398 _("Usage:"),
399 _("Print the workgroup name"));
400 return 0;
403 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
404 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
405 return -1;
408 if (!ads->config.realm) {
409 ads->config.realm = discard_const_p(char, c->opt_target_workgroup);
410 ads->ldap.port = 389;
413 if ( !ads_cldap_netlogon_5(talloc_tos(), &ads->ldap.ss, ads->server.realm, &reply ) ) {
414 d_fprintf(stderr, _("CLDAP query failed!\n"));
415 ads_destroy(&ads);
416 return -1;
419 d_printf(_("Workgroup: %s\n"), reply.domain_name);
421 ads_destroy(&ads);
423 return 0;
428 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
430 char **disp_fields = (char **) data_area;
432 if (!field) { /* must be end of record */
433 if (disp_fields[0]) {
434 if (!strchr_m(disp_fields[0], '$')) {
435 if (disp_fields[1])
436 d_printf("%-21.21s %s\n",
437 disp_fields[0], disp_fields[1]);
438 else
439 d_printf("%s\n", disp_fields[0]);
442 SAFE_FREE(disp_fields[0]);
443 SAFE_FREE(disp_fields[1]);
444 return true;
446 if (!values) /* must be new field, indicate string field */
447 return true;
448 if (strcasecmp_m(field, "sAMAccountName") == 0) {
449 disp_fields[0] = SMB_STRDUP((char *) values[0]);
451 if (strcasecmp_m(field, "description") == 0)
452 disp_fields[1] = SMB_STRDUP((char *) values[0]);
453 return true;
456 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
458 return net_user_usage(c, argc, argv);
461 static int ads_user_add(struct net_context *c, int argc, const char **argv)
463 ADS_STRUCT *ads;
464 ADS_STATUS status;
465 char *upn, *userdn;
466 LDAPMessage *res=NULL;
467 int rc = -1;
468 char *ou_str = NULL;
470 if (argc < 1 || c->display_usage)
471 return net_ads_user_usage(c, argc, argv);
473 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
474 return -1;
477 status = ads_find_user_acct(ads, &res, argv[0]);
479 if (!ADS_ERR_OK(status)) {
480 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
481 goto done;
484 if (ads_count_replies(ads, res)) {
485 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
486 argv[0]);
487 goto done;
490 if (c->opt_container) {
491 ou_str = SMB_STRDUP(c->opt_container);
492 } else {
493 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
496 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
498 if (!ADS_ERR_OK(status)) {
499 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
500 ads_errstr(status));
501 goto done;
504 /* if no password is to be set, we're done */
505 if (argc == 1) {
506 d_printf(_("User %s added\n"), argv[0]);
507 rc = 0;
508 goto done;
511 /* try setting the password */
512 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
513 goto done;
515 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
516 ads->auth.time_offset);
517 SAFE_FREE(upn);
518 if (ADS_ERR_OK(status)) {
519 d_printf(_("User %s added\n"), argv[0]);
520 rc = 0;
521 goto done;
524 /* password didn't set, delete account */
525 d_fprintf(stderr, _("Could not add user %s. "
526 "Error setting password %s\n"),
527 argv[0], ads_errstr(status));
528 ads_msgfree(ads, res);
529 status=ads_find_user_acct(ads, &res, argv[0]);
530 if (ADS_ERR_OK(status)) {
531 userdn = ads_get_dn(ads, talloc_tos(), res);
532 ads_del_dn(ads, userdn);
533 TALLOC_FREE(userdn);
536 done:
537 if (res)
538 ads_msgfree(ads, res);
539 ads_destroy(&ads);
540 SAFE_FREE(ou_str);
541 return rc;
544 static int ads_user_info(struct net_context *c, int argc, const char **argv)
546 ADS_STRUCT *ads = NULL;
547 ADS_STATUS rc;
548 LDAPMessage *res = NULL;
549 TALLOC_CTX *frame;
550 int ret = 0;
551 wbcErr wbc_status;
552 const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
553 char *searchstring=NULL;
554 char **grouplist;
555 char *primary_group;
556 char *escaped_user;
557 struct dom_sid primary_group_sid;
558 uint32_t group_rid;
559 enum wbcSidType type;
561 if (argc < 1 || c->display_usage) {
562 return net_ads_user_usage(c, argc, argv);
565 frame = talloc_new(talloc_tos());
566 if (frame == NULL) {
567 return -1;
570 escaped_user = escape_ldap_string(frame, argv[0]);
571 if (!escaped_user) {
572 d_fprintf(stderr,
573 _("ads_user_info: failed to escape user %s\n"),
574 argv[0]);
575 return -1;
578 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
579 ret = -1;
580 goto error;
583 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
584 ret =-1;
585 goto error;
587 rc = ads_search(ads, &res, searchstring, attrs);
588 SAFE_FREE(searchstring);
590 if (!ADS_ERR_OK(rc)) {
591 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(rc));
592 ret = -1;
593 goto error;
596 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
597 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
598 ret = -1;
599 goto error;
602 rc = ads_domain_sid(ads, &primary_group_sid);
603 if (!ADS_ERR_OK(rc)) {
604 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(rc));
605 ret = -1;
606 goto error;
609 sid_append_rid(&primary_group_sid, group_rid);
611 wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
612 NULL, /* don't look up domain */
613 &primary_group,
614 &type);
615 if (!WBC_ERROR_IS_OK(wbc_status)) {
616 d_fprintf(stderr, "wbcLookupSid: %s\n",
617 wbcErrorString(wbc_status));
618 ret = -1;
619 goto error;
622 d_printf("%s\n", primary_group);
624 wbcFreeMemory(primary_group);
626 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
627 (LDAPMessage *)res, "memberOf");
629 if (grouplist) {
630 int i;
631 char **groupname;
632 for (i=0;grouplist[i];i++) {
633 groupname = ldap_explode_dn(grouplist[i], 1);
634 d_printf("%s\n", groupname[0]);
635 ldap_value_free(groupname);
637 ldap_value_free(grouplist);
640 error:
641 if (res) ads_msgfree(ads, res);
642 if (ads) ads_destroy(&ads);
643 TALLOC_FREE(frame);
644 return ret;
647 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
649 ADS_STRUCT *ads;
650 ADS_STATUS rc;
651 LDAPMessage *res = NULL;
652 char *userdn;
654 if (argc < 1) {
655 return net_ads_user_usage(c, argc, argv);
658 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
659 return -1;
662 rc = ads_find_user_acct(ads, &res, argv[0]);
663 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
664 d_printf(_("User %s does not exist.\n"), argv[0]);
665 ads_msgfree(ads, res);
666 ads_destroy(&ads);
667 return -1;
669 userdn = ads_get_dn(ads, talloc_tos(), res);
670 ads_msgfree(ads, res);
671 rc = ads_del_dn(ads, userdn);
672 TALLOC_FREE(userdn);
673 if (ADS_ERR_OK(rc)) {
674 d_printf(_("User %s deleted\n"), argv[0]);
675 ads_destroy(&ads);
676 return 0;
678 d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
679 ads_errstr(rc));
680 ads_destroy(&ads);
681 return -1;
684 int net_ads_user(struct net_context *c, int argc, const char **argv)
686 struct functable func[] = {
688 "add",
689 ads_user_add,
690 NET_TRANSPORT_ADS,
691 N_("Add an AD user"),
692 N_("net ads user add\n"
693 " Add an AD user")
696 "info",
697 ads_user_info,
698 NET_TRANSPORT_ADS,
699 N_("Display information about an AD user"),
700 N_("net ads user info\n"
701 " Display information about an AD user")
704 "delete",
705 ads_user_delete,
706 NET_TRANSPORT_ADS,
707 N_("Delete an AD user"),
708 N_("net ads user delete\n"
709 " Delete an AD user")
711 {NULL, NULL, 0, NULL, NULL}
713 ADS_STRUCT *ads;
714 ADS_STATUS rc;
715 const char *shortattrs[] = {"sAMAccountName", NULL};
716 const char *longattrs[] = {"sAMAccountName", "description", NULL};
717 char *disp_fields[2] = {NULL, NULL};
719 if (argc == 0) {
720 if (c->display_usage) {
721 d_printf( "%s\n"
722 "net ads user\n"
723 " %s\n",
724 _("Usage:"),
725 _("List AD users"));
726 net_display_usage_from_functable(func);
727 return 0;
730 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
731 return -1;
734 if (c->opt_long_list_entries)
735 d_printf(_("\nUser name Comment"
736 "\n-----------------------------\n"));
738 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
739 LDAP_SCOPE_SUBTREE,
740 "(objectCategory=user)",
741 c->opt_long_list_entries ? longattrs :
742 shortattrs, usergrp_display,
743 disp_fields);
744 ads_destroy(&ads);
745 return ADS_ERR_OK(rc) ? 0 : -1;
748 return net_run_function(c, argc, argv, "net ads user", func);
751 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
753 return net_group_usage(c, argc, argv);
756 static int ads_group_add(struct net_context *c, int argc, const char **argv)
758 ADS_STRUCT *ads;
759 ADS_STATUS status;
760 LDAPMessage *res=NULL;
761 int rc = -1;
762 char *ou_str = NULL;
764 if (argc < 1 || c->display_usage) {
765 return net_ads_group_usage(c, argc, argv);
768 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
769 return -1;
772 status = ads_find_user_acct(ads, &res, argv[0]);
774 if (!ADS_ERR_OK(status)) {
775 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
776 goto done;
779 if (ads_count_replies(ads, res)) {
780 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
781 goto done;
784 if (c->opt_container) {
785 ou_str = SMB_STRDUP(c->opt_container);
786 } else {
787 ou_str = ads_default_ou_string(ads, DS_GUID_USERS_CONTAINER);
790 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
792 if (ADS_ERR_OK(status)) {
793 d_printf(_("Group %s added\n"), argv[0]);
794 rc = 0;
795 } else {
796 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
797 ads_errstr(status));
800 done:
801 if (res)
802 ads_msgfree(ads, res);
803 ads_destroy(&ads);
804 SAFE_FREE(ou_str);
805 return rc;
808 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
810 ADS_STRUCT *ads;
811 ADS_STATUS rc;
812 LDAPMessage *res = NULL;
813 char *groupdn;
815 if (argc < 1 || c->display_usage) {
816 return net_ads_group_usage(c, argc, argv);
819 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
820 return -1;
823 rc = ads_find_user_acct(ads, &res, argv[0]);
824 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
825 d_printf(_("Group %s does not exist.\n"), argv[0]);
826 ads_msgfree(ads, res);
827 ads_destroy(&ads);
828 return -1;
830 groupdn = ads_get_dn(ads, talloc_tos(), res);
831 ads_msgfree(ads, res);
832 rc = ads_del_dn(ads, groupdn);
833 TALLOC_FREE(groupdn);
834 if (ADS_ERR_OK(rc)) {
835 d_printf(_("Group %s deleted\n"), argv[0]);
836 ads_destroy(&ads);
837 return 0;
839 d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
840 ads_errstr(rc));
841 ads_destroy(&ads);
842 return -1;
845 int net_ads_group(struct net_context *c, int argc, const char **argv)
847 struct functable func[] = {
849 "add",
850 ads_group_add,
851 NET_TRANSPORT_ADS,
852 N_("Add an AD group"),
853 N_("net ads group add\n"
854 " Add an AD group")
857 "delete",
858 ads_group_delete,
859 NET_TRANSPORT_ADS,
860 N_("Delete an AD group"),
861 N_("net ads group delete\n"
862 " Delete an AD group")
864 {NULL, NULL, 0, NULL, NULL}
866 ADS_STRUCT *ads;
867 ADS_STATUS rc;
868 const char *shortattrs[] = {"sAMAccountName", NULL};
869 const char *longattrs[] = {"sAMAccountName", "description", NULL};
870 char *disp_fields[2] = {NULL, NULL};
872 if (argc == 0) {
873 if (c->display_usage) {
874 d_printf( "%s\n"
875 "net ads group\n"
876 " %s\n",
877 _("Usage:"),
878 _("List AD groups"));
879 net_display_usage_from_functable(func);
880 return 0;
883 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
884 return -1;
887 if (c->opt_long_list_entries)
888 d_printf(_("\nGroup name Comment"
889 "\n-----------------------------\n"));
890 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
891 LDAP_SCOPE_SUBTREE,
892 "(objectCategory=group)",
893 c->opt_long_list_entries ? longattrs :
894 shortattrs, usergrp_display,
895 disp_fields);
897 ads_destroy(&ads);
898 return ADS_ERR_OK(rc) ? 0 : -1;
900 return net_run_function(c, argc, argv, "net ads group", func);
903 static int net_ads_status(struct net_context *c, int argc, const char **argv)
905 ADS_STRUCT *ads;
906 ADS_STATUS rc;
907 LDAPMessage *res;
909 if (c->display_usage) {
910 d_printf( "%s\n"
911 "net ads status\n"
912 " %s\n",
913 _("Usage:"),
914 _("Display machine account details"));
915 return 0;
918 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
919 return -1;
922 rc = ads_find_machine_acct(ads, &res, lp_netbios_name());
923 if (!ADS_ERR_OK(rc)) {
924 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
925 ads_destroy(&ads);
926 return -1;
929 if (ads_count_replies(ads, res) == 0) {
930 d_fprintf(stderr, _("No machine account for '%s' found\n"), lp_netbios_name());
931 ads_destroy(&ads);
932 return -1;
935 ads_dump(ads, res);
936 ads_destroy(&ads);
937 return 0;
940 /*******************************************************************
941 Leave an AD domain. Windows XP disables the machine account.
942 We'll try the same. The old code would do an LDAP delete.
943 That only worked using the machine creds because added the machine
944 with full control to the computer object's ACL.
945 *******************************************************************/
947 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
949 TALLOC_CTX *ctx;
950 struct libnet_UnjoinCtx *r = NULL;
951 WERROR werr;
953 if (c->display_usage) {
954 d_printf( "%s\n"
955 "net ads leave\n"
956 " %s\n",
957 _("Usage:"),
958 _("Leave an AD domain"));
959 return 0;
962 if (!*lp_realm()) {
963 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
964 return -1;
967 if (!(ctx = talloc_init("net_ads_leave"))) {
968 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
969 return -1;
972 if (!c->opt_kerberos) {
973 use_in_memory_ccache();
976 if (!c->msg_ctx) {
977 d_fprintf(stderr, _("Could not initialise message context. "
978 "Try running as root\n"));
979 return -1;
982 werr = libnet_init_UnjoinCtx(ctx, &r);
983 if (!W_ERROR_IS_OK(werr)) {
984 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
985 return -1;
988 r->in.debug = true;
989 r->in.use_kerberos = c->opt_kerberos;
990 r->in.dc_name = c->opt_host;
991 r->in.domain_name = lp_realm();
992 r->in.admin_account = c->opt_user_name;
993 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
994 r->in.modify_config = lp_config_backend_is_registry();
996 /* Try to delete it, but if that fails, disable it. The
997 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
998 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
999 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
1000 r->in.delete_machine_account = true;
1001 r->in.msg_ctx = c->msg_ctx;
1003 werr = libnet_Unjoin(ctx, r);
1004 if (!W_ERROR_IS_OK(werr)) {
1005 d_printf(_("Failed to leave domain: %s\n"),
1006 r->out.error_string ? r->out.error_string :
1007 get_friendly_werror_msg(werr));
1008 goto done;
1011 if (r->out.deleted_machine_account) {
1012 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
1013 r->in.machine_name, r->out.dns_domain_name);
1014 goto done;
1017 /* We couldn't delete it - see if the disable succeeded. */
1018 if (r->out.disabled_machine_account) {
1019 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
1020 r->in.machine_name, r->out.dns_domain_name);
1021 werr = WERR_OK;
1022 goto done;
1025 /* Based on what we requested, we shouldn't get here, but if
1026 we did, it means the secrets were removed, and therefore
1027 we have left the domain */
1028 d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
1029 r->in.machine_name, r->out.dns_domain_name);
1031 done:
1032 TALLOC_FREE(r);
1033 TALLOC_FREE(ctx);
1035 if (W_ERROR_IS_OK(werr)) {
1036 return 0;
1039 return -1;
1042 static NTSTATUS net_ads_join_ok(struct net_context *c)
1044 ADS_STRUCT *ads = NULL;
1045 ADS_STATUS status;
1046 fstring dc_name;
1047 struct sockaddr_storage dcip;
1049 if (!secrets_init()) {
1050 DEBUG(1,("Failed to initialise secrets database\n"));
1051 return NT_STATUS_ACCESS_DENIED;
1054 net_use_krb_machine_account(c);
1056 get_dc_name(lp_workgroup(), lp_realm(), dc_name, &dcip);
1058 status = ads_startup(c, true, &ads);
1059 if (!ADS_ERR_OK(status)) {
1060 return ads_ntstatus(status);
1063 ads_destroy(&ads);
1064 return NT_STATUS_OK;
1068 check that an existing join is OK
1070 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1072 NTSTATUS status;
1073 use_in_memory_ccache();
1075 if (c->display_usage) {
1076 d_printf( "%s\n"
1077 "net ads testjoin\n"
1078 " %s\n",
1079 _("Usage:"),
1080 _("Test if the existing join is ok"));
1081 return 0;
1084 /* Display success or failure */
1085 status = net_ads_join_ok(c);
1086 if (!NT_STATUS_IS_OK(status)) {
1087 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1088 get_friendly_nt_error_msg(status));
1089 return -1;
1092 printf(_("Join is OK\n"));
1093 return 0;
1096 /*******************************************************************
1097 Simple configu checks before beginning the join
1098 ********************************************************************/
1100 static WERROR check_ads_config( void )
1102 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1103 d_printf(_("Host is not configured as a member server.\n"));
1104 return WERR_INVALID_DOMAIN_ROLE;
1107 if (strlen(lp_netbios_name()) > 15) {
1108 d_printf(_("Our netbios name can be at most 15 chars long, "
1109 "\"%s\" is %u chars long\n"), lp_netbios_name(),
1110 (unsigned int)strlen(lp_netbios_name()));
1111 return WERR_INVALID_COMPUTERNAME;
1114 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1115 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1116 "join to succeed.\n"), get_dyn_CONFIGFILE());
1117 return WERR_INVALID_PARAM;
1120 return WERR_OK;
1123 /*******************************************************************
1124 Send a DNS update request
1125 *******************************************************************/
1127 #if defined(WITH_DNS_UPDATES)
1128 #include "../lib/addns/dns.h"
1129 DNS_ERROR DoDNSUpdate(char *pszServerName,
1130 const char *pszDomainName, const char *pszHostName,
1131 const struct sockaddr_storage *sslist,
1132 size_t num_addrs );
1134 static NTSTATUS net_update_dns_internal(struct net_context *c,
1135 TALLOC_CTX *ctx, ADS_STRUCT *ads,
1136 const char *machine_name,
1137 const struct sockaddr_storage *addrs,
1138 int num_addrs)
1140 struct dns_rr_ns *nameservers = NULL;
1141 int ns_count = 0, i;
1142 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1143 DNS_ERROR dns_err;
1144 fstring dns_server;
1145 const char *dns_hosts_file;
1146 const char *dnsdomain = NULL;
1147 char *root_domain = NULL;
1149 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1150 d_printf(_("No DNS domain configured for %s. "
1151 "Unable to perform DNS Update.\n"), machine_name);
1152 status = NT_STATUS_INVALID_PARAMETER;
1153 goto done;
1155 dnsdomain++;
1157 dns_hosts_file = lp_parm_const_string(-1, "resolv", "host file", NULL);
1158 status = ads_dns_lookup_ns(ctx, dns_hosts_file,
1159 dnsdomain, &nameservers, &ns_count);
1160 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1161 /* Child domains often do not have NS records. Look
1162 for the NS record for the forest root domain
1163 (rootDomainNamingContext in therootDSE) */
1165 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1166 LDAPMessage *msg = NULL;
1167 char *root_dn;
1168 ADS_STATUS ads_status;
1170 if ( !ads->ldap.ld ) {
1171 ads_status = ads_connect( ads );
1172 if ( !ADS_ERR_OK(ads_status) ) {
1173 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1174 goto done;
1178 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1179 "(objectclass=*)", rootname_attrs, &msg);
1180 if (!ADS_ERR_OK(ads_status)) {
1181 goto done;
1184 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1185 if ( !root_dn ) {
1186 ads_msgfree( ads, msg );
1187 goto done;
1190 root_domain = ads_build_domain( root_dn );
1192 /* cleanup */
1193 ads_msgfree( ads, msg );
1195 /* try again for NS servers */
1197 status = ads_dns_lookup_ns(ctx, dns_hosts_file, root_domain,
1198 &nameservers, &ns_count);
1200 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1201 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1202 "realm\n", ads->config.realm));
1203 goto done;
1206 dnsdomain = root_domain;
1210 for (i=0; i < ns_count; i++) {
1212 status = NT_STATUS_UNSUCCESSFUL;
1214 /* Now perform the dns update - we'll try non-secure and if we fail,
1215 we'll follow it up with a secure update */
1217 fstrcpy( dns_server, nameservers[i].hostname );
1219 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1220 if (ERR_DNS_IS_OK(dns_err)) {
1221 status = NT_STATUS_OK;
1222 goto done;
1225 if (ERR_DNS_EQUAL(dns_err, ERROR_DNS_INVALID_NAME_SERVER) ||
1226 ERR_DNS_EQUAL(dns_err, ERROR_DNS_CONNECTION_FAILED) ||
1227 ERR_DNS_EQUAL(dns_err, ERROR_DNS_SOCKET_ERROR)) {
1228 DEBUG(1,("retrying DNS update with next nameserver after receiving %s\n",
1229 dns_errstr(dns_err)));
1230 continue;
1233 d_printf(_("DNS Update for %s failed: %s\n"),
1234 machine_name, dns_errstr(dns_err));
1235 status = NT_STATUS_UNSUCCESSFUL;
1236 goto done;
1239 done:
1241 SAFE_FREE( root_domain );
1243 return status;
1246 static NTSTATUS net_update_dns_ext(struct net_context *c,
1247 TALLOC_CTX *mem_ctx, ADS_STRUCT *ads,
1248 const char *hostname,
1249 struct sockaddr_storage *iplist,
1250 int num_addrs)
1252 struct sockaddr_storage *iplist_alloc = NULL;
1253 fstring machine_name;
1254 NTSTATUS status;
1256 if (hostname) {
1257 fstrcpy(machine_name, hostname);
1258 } else {
1259 name_to_fqdn( machine_name, lp_netbios_name() );
1261 if (!strlower_m( machine_name )) {
1262 return NT_STATUS_INVALID_PARAMETER;
1265 if (num_addrs == 0 || iplist == NULL) {
1267 * Get our ip address
1268 * (not the 127.0.0.x address but a real ip address)
1270 num_addrs = get_my_ip_address(&iplist_alloc);
1271 if ( num_addrs <= 0 ) {
1272 DEBUG(4, ("net_update_dns_ext: Failed to find my "
1273 "non-loopback IP addresses!\n"));
1274 return NT_STATUS_INVALID_PARAMETER;
1276 iplist = iplist_alloc;
1279 status = net_update_dns_internal(c, mem_ctx, ads, machine_name,
1280 iplist, num_addrs);
1282 SAFE_FREE(iplist_alloc);
1283 return status;
1286 static NTSTATUS net_update_dns(struct net_context *c, TALLOC_CTX *mem_ctx, ADS_STRUCT *ads, const char *hostname)
1288 NTSTATUS status;
1290 status = net_update_dns_ext(c, mem_ctx, ads, hostname, NULL, 0);
1291 return status;
1293 #endif
1296 /*******************************************************************
1297 ********************************************************************/
1299 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1301 d_printf(_("net ads join [options]\n"
1302 "Valid options:\n"));
1303 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1304 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1305 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1306 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1307 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1308 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1309 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1310 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1311 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1312 " NB: osName and osVer must be specified together for either to take effect.\n"
1313 " Also, the operatingSystemService attribute is also set when along with\n"
1314 " the two other attributes.\n"));
1316 return -1;
1320 static void _net_ads_join_dns_updates(struct net_context *c, TALLOC_CTX *ctx, struct libnet_JoinCtx *r)
1322 #if defined(WITH_DNS_UPDATES)
1323 ADS_STRUCT *ads_dns = NULL;
1324 int ret;
1325 NTSTATUS status;
1328 * In a clustered environment, don't do dynamic dns updates:
1329 * Registering the set of ip addresses that are assigned to
1330 * the interfaces of the node that performs the join does usually
1331 * not have the desired effect, since the local interfaces do not
1332 * carry the complete set of the cluster's public IP addresses.
1333 * And it can also contain internal addresses that should not
1334 * be visible to the outside at all.
1335 * In order to do dns updates in a clustererd setup, use
1336 * net ads dns register.
1338 if (lp_clustering()) {
1339 d_fprintf(stderr, _("Not doing automatic DNS update in a "
1340 "clustered setup.\n"));
1341 return;
1344 if (!r->out.domain_is_ad) {
1345 return;
1349 * We enter this block with user creds.
1350 * kinit with the machine password to do dns update.
1353 ads_dns = ads_init(lp_realm(), NULL, r->in.dc_name);
1355 if (ads_dns == NULL) {
1356 d_fprintf(stderr, _("DNS update failed: out of memory!\n"));
1357 goto done;
1360 use_in_memory_ccache();
1362 ret = asprintf(&ads_dns->auth.user_name, "%s$", lp_netbios_name());
1363 if (ret == -1) {
1364 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1365 goto done;
1368 ads_dns->auth.password = secrets_fetch_machine_password(
1369 r->out.netbios_domain_name, NULL, NULL);
1370 if (ads_dns->auth.password == NULL) {
1371 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1372 goto done;
1375 ads_dns->auth.realm = SMB_STRDUP(r->out.dns_domain_name);
1376 if (ads_dns->auth.realm == NULL) {
1377 d_fprintf(stderr, _("DNS update failed: out of memory\n"));
1378 goto done;
1381 if (!strupper_m(ads_dns->auth.realm)) {
1382 d_fprintf(stderr, _("strupper_m %s failed\n"), ads_dns->auth.realm);
1383 goto done;
1386 ret = ads_kinit_password(ads_dns);
1387 if (ret != 0) {
1388 d_fprintf(stderr,
1389 _("DNS update failed: kinit failed: %s\n"),
1390 error_message(ret));
1391 goto done;
1394 status = net_update_dns(c, ctx, ads_dns, NULL);
1395 if (!NT_STATUS_IS_OK(status)) {
1396 d_fprintf( stderr, _("DNS update failed: %s\n"),
1397 nt_errstr(status));
1400 done:
1401 ads_destroy(&ads_dns);
1402 #endif
1404 return;
1408 int net_ads_join(struct net_context *c, int argc, const char **argv)
1410 TALLOC_CTX *ctx = NULL;
1411 struct libnet_JoinCtx *r = NULL;
1412 const char *domain = lp_realm();
1413 WERROR werr = WERR_SETUP_NOT_JOINED;
1414 bool createupn = false;
1415 const char *machineupn = NULL;
1416 const char *create_in_ou = NULL;
1417 int i;
1418 const char *os_name = NULL;
1419 const char *os_version = NULL;
1420 bool modify_config = lp_config_backend_is_registry();
1422 if (c->display_usage)
1423 return net_ads_join_usage(c, argc, argv);
1425 if (!modify_config) {
1427 werr = check_ads_config();
1428 if (!W_ERROR_IS_OK(werr)) {
1429 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1430 goto fail;
1434 if (!(ctx = talloc_init("net_ads_join"))) {
1435 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1436 werr = WERR_NOMEM;
1437 goto fail;
1440 if (!c->opt_kerberos) {
1441 use_in_memory_ccache();
1444 werr = libnet_init_JoinCtx(ctx, &r);
1445 if (!W_ERROR_IS_OK(werr)) {
1446 goto fail;
1449 /* process additional command line args */
1451 for ( i=0; i<argc; i++ ) {
1452 if ( !strncasecmp_m(argv[i], "createupn", strlen("createupn")) ) {
1453 createupn = true;
1454 machineupn = get_string_param(argv[i]);
1456 else if ( !strncasecmp_m(argv[i], "createcomputer", strlen("createcomputer")) ) {
1457 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1458 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1459 werr = WERR_INVALID_PARAM;
1460 goto fail;
1463 else if ( !strncasecmp_m(argv[i], "osName", strlen("osName")) ) {
1464 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1465 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1466 werr = WERR_INVALID_PARAM;
1467 goto fail;
1470 else if ( !strncasecmp_m(argv[i], "osVer", strlen("osVer")) ) {
1471 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1472 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1473 werr = WERR_INVALID_PARAM;
1474 goto fail;
1477 else {
1478 domain = argv[i];
1482 if (!*domain) {
1483 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1484 werr = WERR_INVALID_PARAM;
1485 goto fail;
1488 if (!c->msg_ctx) {
1489 d_fprintf(stderr, _("Could not initialise message context. "
1490 "Try running as root\n"));
1491 werr = WERR_ACCESS_DENIED;
1492 goto fail;
1495 /* Do the domain join here */
1497 r->in.domain_name = domain;
1498 r->in.create_upn = createupn;
1499 r->in.upn = machineupn;
1500 r->in.account_ou = create_in_ou;
1501 r->in.os_name = os_name;
1502 r->in.os_version = os_version;
1503 r->in.dc_name = c->opt_host;
1504 r->in.admin_account = c->opt_user_name;
1505 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1506 r->in.debug = true;
1507 r->in.use_kerberos = c->opt_kerberos;
1508 r->in.modify_config = modify_config;
1509 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1510 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1511 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1512 r->in.msg_ctx = c->msg_ctx;
1514 werr = libnet_Join(ctx, r);
1515 if (W_ERROR_EQUAL(werr, WERR_DCNOTFOUND) &&
1516 strequal(domain, lp_realm())) {
1517 r->in.domain_name = lp_workgroup();
1518 werr = libnet_Join(ctx, r);
1520 if (!W_ERROR_IS_OK(werr)) {
1521 goto fail;
1524 /* Check the short name of the domain */
1526 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1527 d_printf(_("The workgroup in %s does not match the short\n"
1528 "domain name obtained from the server.\n"
1529 "Using the name [%s] from the server.\n"
1530 "You should set \"workgroup = %s\" in %s.\n"),
1531 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1532 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1535 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1537 if (r->out.dns_domain_name) {
1538 d_printf(_("Joined '%s' to realm '%s'\n"), r->in.machine_name,
1539 r->out.dns_domain_name);
1540 } else {
1541 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1542 r->out.netbios_domain_name);
1546 * We try doing the dns update (if it was compiled in).
1547 * If the dns update fails, we still consider the join
1548 * operation as succeeded if we came this far.
1550 _net_ads_join_dns_updates(c, ctx, r);
1552 TALLOC_FREE(r);
1553 TALLOC_FREE( ctx );
1555 return 0;
1557 fail:
1558 /* issue an overall failure message at the end. */
1559 d_printf(_("Failed to join domain: %s\n"),
1560 r && r->out.error_string ? r->out.error_string :
1561 get_friendly_werror_msg(werr));
1562 TALLOC_FREE( ctx );
1564 return -1;
1567 /*******************************************************************
1568 ********************************************************************/
1570 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1572 #if defined(WITH_DNS_UPDATES)
1573 ADS_STRUCT *ads;
1574 ADS_STATUS status;
1575 NTSTATUS ntstatus;
1576 TALLOC_CTX *ctx;
1577 const char *hostname = NULL;
1578 const char **addrs_list = NULL;
1579 struct sockaddr_storage *addrs = NULL;
1580 int num_addrs = 0;
1581 int count;
1583 #ifdef DEVELOPER
1584 talloc_enable_leak_report();
1585 #endif
1587 if (argc <= 1 && lp_clustering() && lp_cluster_addresses() == NULL) {
1588 d_fprintf(stderr, _("Refusing DNS updates with automatic "
1589 "detection of addresses in a clustered "
1590 "setup.\n"));
1591 c->display_usage = true;
1594 if (c->display_usage) {
1595 d_printf( "%s\n"
1596 "net ads dns register [hostname [IP [IP...]]]\n"
1597 " %s\n",
1598 _("Usage:"),
1599 _("Register hostname with DNS\n"));
1600 return -1;
1603 if (!(ctx = talloc_init("net_ads_dns"))) {
1604 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1605 return -1;
1608 if (argc >= 1) {
1609 hostname = argv[0];
1612 if (argc > 1) {
1613 num_addrs = argc - 1;
1614 addrs_list = &argv[1];
1615 } else if (lp_clustering()) {
1616 addrs_list = lp_cluster_addresses();
1617 num_addrs = str_list_length(addrs_list);
1620 if (num_addrs > 0) {
1621 addrs = talloc_zero_array(ctx, struct sockaddr_storage, num_addrs);
1622 if (addrs == NULL) {
1623 d_fprintf(stderr, _("Error allocating memory!\n"));
1624 talloc_free(ctx);
1625 return -1;
1629 for (count = 0; count < num_addrs; count++) {
1630 if (!interpret_string_addr(&addrs[count], addrs_list[count], 0)) {
1631 d_fprintf(stderr, "%s '%s'.\n",
1632 _("Cannot interpret address"),
1633 addrs_list[count]);
1634 talloc_free(ctx);
1635 return -1;
1639 status = ads_startup(c, true, &ads);
1640 if ( !ADS_ERR_OK(status) ) {
1641 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1642 TALLOC_FREE(ctx);
1643 return -1;
1646 ntstatus = net_update_dns_ext(c, ctx, ads, hostname, addrs, num_addrs);
1647 if (!NT_STATUS_IS_OK(ntstatus)) {
1648 d_fprintf( stderr, _("DNS update failed!\n") );
1649 ads_destroy( &ads );
1650 TALLOC_FREE( ctx );
1651 return -1;
1654 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1656 ads_destroy(&ads);
1657 TALLOC_FREE( ctx );
1659 return 0;
1660 #else
1661 d_fprintf(stderr,
1662 _("DNS update support not enabled at compile time!\n"));
1663 return -1;
1664 #endif
1667 #if defined(WITH_DNS_UPDATES)
1668 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1669 #endif
1671 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1673 #if defined(WITH_DNS_UPDATES)
1674 DNS_ERROR err;
1676 #ifdef DEVELOPER
1677 talloc_enable_leak_report();
1678 #endif
1680 if (argc != 2 || c->display_usage) {
1681 d_printf( "%s\n"
1682 " %s\n"
1683 " %s\n",
1684 _("Usage:"),
1685 _("net ads dns gethostbyname <server> <name>\n"),
1686 _(" Look up hostname from the AD\n"
1687 " server\tName server to use\n"
1688 " name\tName to look up\n"));
1689 return -1;
1692 err = do_gethostbyname(argv[0], argv[1]);
1694 d_printf(_("do_gethostbyname returned %s (%d)\n"),
1695 dns_errstr(err), ERROR_DNS_V(err));
1696 #endif
1697 return 0;
1700 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1702 struct functable func[] = {
1704 "register",
1705 net_ads_dns_register,
1706 NET_TRANSPORT_ADS,
1707 N_("Add host dns entry to AD"),
1708 N_("net ads dns register\n"
1709 " Add host dns entry to AD")
1712 "gethostbyname",
1713 net_ads_dns_gethostbyname,
1714 NET_TRANSPORT_ADS,
1715 N_("Look up host"),
1716 N_("net ads dns gethostbyname\n"
1717 " Look up host")
1719 {NULL, NULL, 0, NULL, NULL}
1722 return net_run_function(c, argc, argv, "net ads dns", func);
1725 /*******************************************************************
1726 ********************************************************************/
1728 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1730 d_printf(_(
1731 "\nnet ads printer search <printer>"
1732 "\n\tsearch for a printer in the directory\n"
1733 "\nnet ads printer info <printer> <server>"
1734 "\n\tlookup info in directory for printer on server"
1735 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1736 "\nnet ads printer publish <printername>"
1737 "\n\tpublish printer in directory"
1738 "\n\t(note: printer name is required)\n"
1739 "\nnet ads printer remove <printername>"
1740 "\n\tremove printer from directory"
1741 "\n\t(note: printer name is required)\n"));
1742 return -1;
1745 /*******************************************************************
1746 ********************************************************************/
1748 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1750 ADS_STRUCT *ads;
1751 ADS_STATUS rc;
1752 LDAPMessage *res = NULL;
1754 if (c->display_usage) {
1755 d_printf( "%s\n"
1756 "net ads printer search\n"
1757 " %s\n",
1758 _("Usage:"),
1759 _("List printers in the AD"));
1760 return 0;
1763 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1764 return -1;
1767 rc = ads_find_printers(ads, &res);
1769 if (!ADS_ERR_OK(rc)) {
1770 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
1771 ads_msgfree(ads, res);
1772 ads_destroy(&ads);
1773 return -1;
1776 if (ads_count_replies(ads, res) == 0) {
1777 d_fprintf(stderr, _("No results found\n"));
1778 ads_msgfree(ads, res);
1779 ads_destroy(&ads);
1780 return -1;
1783 ads_dump(ads, res);
1784 ads_msgfree(ads, res);
1785 ads_destroy(&ads);
1786 return 0;
1789 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1791 ADS_STRUCT *ads;
1792 ADS_STATUS rc;
1793 const char *servername, *printername;
1794 LDAPMessage *res = NULL;
1796 if (c->display_usage) {
1797 d_printf("%s\n%s",
1798 _("Usage:"),
1799 _("net ads printer info [printername [servername]]\n"
1800 " Display printer info from AD\n"
1801 " printername\tPrinter name or wildcard\n"
1802 " servername\tName of the print server\n"));
1803 return 0;
1806 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1807 return -1;
1810 if (argc > 0) {
1811 printername = argv[0];
1812 } else {
1813 printername = "*";
1816 if (argc > 1) {
1817 servername = argv[1];
1818 } else {
1819 servername = lp_netbios_name();
1822 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1824 if (!ADS_ERR_OK(rc)) {
1825 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
1826 servername, ads_errstr(rc));
1827 ads_msgfree(ads, res);
1828 ads_destroy(&ads);
1829 return -1;
1832 if (ads_count_replies(ads, res) == 0) {
1833 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
1834 ads_msgfree(ads, res);
1835 ads_destroy(&ads);
1836 return -1;
1839 ads_dump(ads, res);
1840 ads_msgfree(ads, res);
1841 ads_destroy(&ads);
1843 return 0;
1846 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1848 ADS_STRUCT *ads;
1849 ADS_STATUS rc;
1850 const char *servername, *printername;
1851 struct cli_state *cli = NULL;
1852 struct rpc_pipe_client *pipe_hnd = NULL;
1853 struct sockaddr_storage server_ss;
1854 NTSTATUS nt_status;
1855 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1856 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1857 char *prt_dn, *srv_dn, **srv_cn;
1858 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1859 LDAPMessage *res = NULL;
1861 if (argc < 1 || c->display_usage) {
1862 d_printf("%s\n%s",
1863 _("Usage:"),
1864 _("net ads printer publish <printername> [servername]\n"
1865 " Publish printer in AD\n"
1866 " printername\tName of the printer\n"
1867 " servername\tName of the print server\n"));
1868 talloc_destroy(mem_ctx);
1869 return -1;
1872 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1873 talloc_destroy(mem_ctx);
1874 return -1;
1877 printername = argv[0];
1879 if (argc == 2) {
1880 servername = argv[1];
1881 } else {
1882 servername = lp_netbios_name();
1885 /* Get printer data from SPOOLSS */
1887 resolve_name(servername, &server_ss, 0x20, false);
1889 nt_status = cli_full_connection(&cli, lp_netbios_name(), servername,
1890 &server_ss, 0,
1891 "IPC$", "IPC",
1892 c->opt_user_name, c->opt_workgroup,
1893 c->opt_password ? c->opt_password : "",
1894 CLI_FULL_CONNECTION_USE_KERBEROS,
1895 SMB_SIGNING_DEFAULT);
1897 if (NT_STATUS_IS_ERR(nt_status)) {
1898 d_fprintf(stderr, _("Unable to open a connection to %s to "
1899 "obtain data for %s\n"),
1900 servername, printername);
1901 ads_destroy(&ads);
1902 talloc_destroy(mem_ctx);
1903 return -1;
1906 /* Publish on AD server */
1908 ads_find_machine_acct(ads, &res, servername);
1910 if (ads_count_replies(ads, res) == 0) {
1911 d_fprintf(stderr, _("Could not find machine account for server "
1912 "%s\n"),
1913 servername);
1914 ads_destroy(&ads);
1915 talloc_destroy(mem_ctx);
1916 return -1;
1919 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1920 srv_cn = ldap_explode_dn(srv_dn, 1);
1922 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1923 printername_escaped = escape_rdn_val_string_alloc(printername);
1924 if (!srv_cn_escaped || !printername_escaped) {
1925 SAFE_FREE(srv_cn_escaped);
1926 SAFE_FREE(printername_escaped);
1927 d_fprintf(stderr, _("Internal error, out of memory!"));
1928 ads_destroy(&ads);
1929 talloc_destroy(mem_ctx);
1930 return -1;
1933 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1934 SAFE_FREE(srv_cn_escaped);
1935 SAFE_FREE(printername_escaped);
1936 d_fprintf(stderr, _("Internal error, out of memory!"));
1937 ads_destroy(&ads);
1938 talloc_destroy(mem_ctx);
1939 return -1;
1942 SAFE_FREE(srv_cn_escaped);
1943 SAFE_FREE(printername_escaped);
1945 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
1946 if (!NT_STATUS_IS_OK(nt_status)) {
1947 d_fprintf(stderr, _("Unable to open a connection to the spoolss pipe on %s\n"),
1948 servername);
1949 SAFE_FREE(prt_dn);
1950 ads_destroy(&ads);
1951 talloc_destroy(mem_ctx);
1952 return -1;
1955 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1956 printername))) {
1957 SAFE_FREE(prt_dn);
1958 ads_destroy(&ads);
1959 talloc_destroy(mem_ctx);
1960 return -1;
1963 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1964 if (!ADS_ERR_OK(rc)) {
1965 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1966 SAFE_FREE(prt_dn);
1967 ads_destroy(&ads);
1968 talloc_destroy(mem_ctx);
1969 return -1;
1972 d_printf("published printer\n");
1973 SAFE_FREE(prt_dn);
1974 ads_destroy(&ads);
1975 talloc_destroy(mem_ctx);
1977 return 0;
1980 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1982 ADS_STRUCT *ads;
1983 ADS_STATUS rc;
1984 const char *servername;
1985 char *prt_dn;
1986 LDAPMessage *res = NULL;
1988 if (argc < 1 || c->display_usage) {
1989 d_printf("%s\n%s",
1990 _("Usage:"),
1991 _("net ads printer remove <printername> [servername]\n"
1992 " Remove a printer from the AD\n"
1993 " printername\tName of the printer\n"
1994 " servername\tName of the print server\n"));
1995 return -1;
1998 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1999 return -1;
2002 if (argc > 1) {
2003 servername = argv[1];
2004 } else {
2005 servername = lp_netbios_name();
2008 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
2010 if (!ADS_ERR_OK(rc)) {
2011 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
2012 ads_msgfree(ads, res);
2013 ads_destroy(&ads);
2014 return -1;
2017 if (ads_count_replies(ads, res) == 0) {
2018 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
2019 ads_msgfree(ads, res);
2020 ads_destroy(&ads);
2021 return -1;
2024 prt_dn = ads_get_dn(ads, talloc_tos(), res);
2025 ads_msgfree(ads, res);
2026 rc = ads_del_dn(ads, prt_dn);
2027 TALLOC_FREE(prt_dn);
2029 if (!ADS_ERR_OK(rc)) {
2030 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
2031 ads_destroy(&ads);
2032 return -1;
2035 ads_destroy(&ads);
2036 return 0;
2039 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
2041 struct functable func[] = {
2043 "search",
2044 net_ads_printer_search,
2045 NET_TRANSPORT_ADS,
2046 N_("Search for a printer"),
2047 N_("net ads printer search\n"
2048 " Search for a printer")
2051 "info",
2052 net_ads_printer_info,
2053 NET_TRANSPORT_ADS,
2054 N_("Display printer information"),
2055 N_("net ads printer info\n"
2056 " Display printer information")
2059 "publish",
2060 net_ads_printer_publish,
2061 NET_TRANSPORT_ADS,
2062 N_("Publish a printer"),
2063 N_("net ads printer publish\n"
2064 " Publish a printer")
2067 "remove",
2068 net_ads_printer_remove,
2069 NET_TRANSPORT_ADS,
2070 N_("Delete a printer"),
2071 N_("net ads printer remove\n"
2072 " Delete a printer")
2074 {NULL, NULL, 0, NULL, NULL}
2077 return net_run_function(c, argc, argv, "net ads printer", func);
2081 static int net_ads_password(struct net_context *c, int argc, const char **argv)
2083 ADS_STRUCT *ads;
2084 const char *auth_principal = c->opt_user_name;
2085 const char *auth_password = c->opt_password;
2086 const char *realm = NULL;
2087 const char *new_password = NULL;
2088 char *chr, *prompt;
2089 const char *user;
2090 ADS_STATUS ret;
2092 if (c->display_usage) {
2093 d_printf("%s\n%s",
2094 _("Usage:"),
2095 _("net ads password <username>\n"
2096 " Change password for user\n"
2097 " username\tName of user to change password for\n"));
2098 return 0;
2101 if (c->opt_user_name == NULL || c->opt_password == NULL) {
2102 d_fprintf(stderr, _("You must supply an administrator "
2103 "username/password\n"));
2104 return -1;
2107 if (argc < 1) {
2108 d_fprintf(stderr, _("ERROR: You must say which username to "
2109 "change password for\n"));
2110 return -1;
2113 user = argv[0];
2114 if (!strchr_m(user, '@')) {
2115 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
2116 return -1;
2118 user = chr;
2121 use_in_memory_ccache();
2122 chr = strchr_m(auth_principal, '@');
2123 if (chr) {
2124 realm = ++chr;
2125 } else {
2126 realm = lp_realm();
2129 /* use the realm so we can eventually change passwords for users
2130 in realms other than default */
2131 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
2132 return -1;
2135 /* we don't actually need a full connect, but it's the easy way to
2136 fill in the KDC's addresss */
2137 ads_connect(ads);
2139 if (!ads->config.realm) {
2140 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
2141 ads_destroy(&ads);
2142 return -1;
2145 if (argv[1]) {
2146 new_password = (const char *)argv[1];
2147 } else {
2148 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
2149 return -1;
2151 new_password = getpass(prompt);
2152 free(prompt);
2155 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
2156 auth_password, user, new_password, ads->auth.time_offset);
2157 if (!ADS_ERR_OK(ret)) {
2158 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2159 ads_destroy(&ads);
2160 return -1;
2163 d_printf(_("Password change for %s completed.\n"), user);
2164 ads_destroy(&ads);
2166 return 0;
2169 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2171 ADS_STRUCT *ads;
2172 char *host_principal;
2173 fstring my_name;
2174 ADS_STATUS ret;
2176 if (c->display_usage) {
2177 d_printf( "%s\n"
2178 "net ads changetrustpw\n"
2179 " %s\n",
2180 _("Usage:"),
2181 _("Change the machine account's trust password"));
2182 return 0;
2185 if (!secrets_init()) {
2186 DEBUG(1,("Failed to initialise secrets database\n"));
2187 return -1;
2190 net_use_krb_machine_account(c);
2192 use_in_memory_ccache();
2194 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2195 return -1;
2198 fstrcpy(my_name, lp_netbios_name());
2199 if (!strlower_m(my_name)) {
2200 ads_destroy(&ads);
2201 return -1;
2204 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
2205 ads_destroy(&ads);
2206 return -1;
2208 d_printf(_("Changing password for principal: %s\n"), host_principal);
2210 ret = ads_change_trust_account_password(ads, host_principal);
2212 if (!ADS_ERR_OK(ret)) {
2213 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
2214 ads_destroy(&ads);
2215 SAFE_FREE(host_principal);
2216 return -1;
2219 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
2221 if (USE_SYSTEM_KEYTAB) {
2222 d_printf(_("Attempting to update system keytab with new password.\n"));
2223 if (ads_keytab_create_default(ads)) {
2224 d_printf(_("Failed to update system keytab.\n"));
2228 ads_destroy(&ads);
2229 SAFE_FREE(host_principal);
2231 return 0;
2235 help for net ads search
2237 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2239 d_printf(_(
2240 "\nnet ads search <expression> <attributes...>\n"
2241 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2242 "The expression is a standard LDAP search expression, and the\n"
2243 "attributes are a list of LDAP fields to show in the results.\n\n"
2244 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2246 net_common_flags_usage(c, argc, argv);
2247 return -1;
2252 general ADS search function. Useful in diagnosing problems in ADS
2254 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2256 ADS_STRUCT *ads;
2257 ADS_STATUS rc;
2258 const char *ldap_exp;
2259 const char **attrs;
2260 LDAPMessage *res = NULL;
2262 if (argc < 1 || c->display_usage) {
2263 return net_ads_search_usage(c, argc, argv);
2266 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2267 return -1;
2270 ldap_exp = argv[0];
2271 attrs = (argv + 1);
2273 rc = ads_do_search_retry(ads, ads->config.bind_path,
2274 LDAP_SCOPE_SUBTREE,
2275 ldap_exp, attrs, &res);
2276 if (!ADS_ERR_OK(rc)) {
2277 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2278 ads_destroy(&ads);
2279 return -1;
2282 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2284 /* dump the results */
2285 ads_dump(ads, res);
2287 ads_msgfree(ads, res);
2288 ads_destroy(&ads);
2290 return 0;
2295 help for net ads search
2297 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2299 d_printf(_(
2300 "\nnet ads dn <dn> <attributes...>\n"
2301 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2302 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2303 "to show in the results\n\n"
2304 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2305 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2307 net_common_flags_usage(c, argc, argv);
2308 return -1;
2313 general ADS search function. Useful in diagnosing problems in ADS
2315 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2317 ADS_STRUCT *ads;
2318 ADS_STATUS rc;
2319 const char *dn;
2320 const char **attrs;
2321 LDAPMessage *res = NULL;
2323 if (argc < 1 || c->display_usage) {
2324 return net_ads_dn_usage(c, argc, argv);
2327 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2328 return -1;
2331 dn = argv[0];
2332 attrs = (argv + 1);
2334 rc = ads_do_search_all(ads, dn,
2335 LDAP_SCOPE_BASE,
2336 "(objectclass=*)", attrs, &res);
2337 if (!ADS_ERR_OK(rc)) {
2338 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2339 ads_destroy(&ads);
2340 return -1;
2343 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2345 /* dump the results */
2346 ads_dump(ads, res);
2348 ads_msgfree(ads, res);
2349 ads_destroy(&ads);
2351 return 0;
2355 help for net ads sid search
2357 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2359 d_printf(_(
2360 "\nnet ads sid <sid> <attributes...>\n"
2361 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2362 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2363 "to show in the results\n\n"
2364 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2366 net_common_flags_usage(c, argc, argv);
2367 return -1;
2372 general ADS search function. Useful in diagnosing problems in ADS
2374 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2376 ADS_STRUCT *ads;
2377 ADS_STATUS rc;
2378 const char *sid_string;
2379 const char **attrs;
2380 LDAPMessage *res = NULL;
2381 struct dom_sid sid;
2383 if (argc < 1 || c->display_usage) {
2384 return net_ads_sid_usage(c, argc, argv);
2387 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2388 return -1;
2391 sid_string = argv[0];
2392 attrs = (argv + 1);
2394 if (!string_to_sid(&sid, sid_string)) {
2395 d_fprintf(stderr, _("could not convert sid\n"));
2396 ads_destroy(&ads);
2397 return -1;
2400 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2401 if (!ADS_ERR_OK(rc)) {
2402 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2403 ads_destroy(&ads);
2404 return -1;
2407 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2409 /* dump the results */
2410 ads_dump(ads, res);
2412 ads_msgfree(ads, res);
2413 ads_destroy(&ads);
2415 return 0;
2418 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2420 int ret;
2421 ADS_STRUCT *ads;
2423 if (c->display_usage) {
2424 d_printf( "%s\n"
2425 "net ads keytab flush\n"
2426 " %s\n",
2427 _("Usage:"),
2428 _("Delete the whole keytab"));
2429 return 0;
2432 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2433 return -1;
2435 ret = ads_keytab_flush(ads);
2436 ads_destroy(&ads);
2437 return ret;
2440 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2442 int i;
2443 int ret = 0;
2444 ADS_STRUCT *ads;
2446 if (c->display_usage) {
2447 d_printf("%s\n%s",
2448 _("Usage:"),
2449 _("net ads keytab add <principal> [principal ...]\n"
2450 " Add principals to local keytab\n"
2451 " principal\tKerberos principal to add to "
2452 "keytab\n"));
2453 return 0;
2456 d_printf(_("Processing principals to add...\n"));
2457 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2458 return -1;
2460 for (i = 0; i < argc; i++) {
2461 ret |= ads_keytab_add_entry(ads, argv[i]);
2463 ads_destroy(&ads);
2464 return ret;
2467 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2469 ADS_STRUCT *ads;
2470 int ret;
2472 if (c->display_usage) {
2473 d_printf( "%s\n"
2474 "net ads keytab create\n"
2475 " %s\n",
2476 _("Usage:"),
2477 _("Create new default keytab"));
2478 return 0;
2481 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2482 return -1;
2484 ret = ads_keytab_create_default(ads);
2485 ads_destroy(&ads);
2486 return ret;
2489 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2491 const char *keytab = NULL;
2493 if (c->display_usage) {
2494 d_printf("%s\n%s",
2495 _("Usage:"),
2496 _("net ads keytab list [keytab]\n"
2497 " List a local keytab\n"
2498 " keytab\tKeytab to list\n"));
2499 return 0;
2502 if (argc >= 1) {
2503 keytab = argv[0];
2506 return ads_keytab_list(keytab);
2510 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2512 struct functable func[] = {
2514 "add",
2515 net_ads_keytab_add,
2516 NET_TRANSPORT_ADS,
2517 N_("Add a service principal"),
2518 N_("net ads keytab add\n"
2519 " Add a service principal")
2522 "create",
2523 net_ads_keytab_create,
2524 NET_TRANSPORT_ADS,
2525 N_("Create a fresh keytab"),
2526 N_("net ads keytab create\n"
2527 " Create a fresh keytab")
2530 "flush",
2531 net_ads_keytab_flush,
2532 NET_TRANSPORT_ADS,
2533 N_("Remove all keytab entries"),
2534 N_("net ads keytab flush\n"
2535 " Remove all keytab entries")
2538 "list",
2539 net_ads_keytab_list,
2540 NET_TRANSPORT_ADS,
2541 N_("List a keytab"),
2542 N_("net ads keytab list\n"
2543 " List a keytab")
2545 {NULL, NULL, 0, NULL, NULL}
2548 if (!USE_KERBEROS_KEYTAB) {
2549 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2550 "keytab method to use keytab functions.\n"));
2553 return net_run_function(c, argc, argv, "net ads keytab", func);
2556 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2558 int ret = -1;
2560 if (c->display_usage) {
2561 d_printf( "%s\n"
2562 "net ads kerberos renew\n"
2563 " %s\n",
2564 _("Usage:"),
2565 _("Renew TGT from existing credential cache"));
2566 return 0;
2569 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2570 if (ret) {
2571 d_printf(_("failed to renew kerberos ticket: %s\n"),
2572 error_message(ret));
2574 return ret;
2577 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2579 struct PAC_LOGON_INFO *info = NULL;
2580 TALLOC_CTX *mem_ctx = NULL;
2581 NTSTATUS status;
2582 int ret = -1;
2583 const char *impersonate_princ_s = NULL;
2585 if (c->display_usage) {
2586 d_printf( "%s\n"
2587 "net ads kerberos pac\n"
2588 " %s\n",
2589 _("Usage:"),
2590 _("Dump the Kerberos PAC"));
2591 return 0;
2594 mem_ctx = talloc_init("net_ads_kerberos_pac");
2595 if (!mem_ctx) {
2596 goto out;
2599 if (argc > 0) {
2600 impersonate_princ_s = argv[0];
2603 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2605 status = kerberos_return_pac(mem_ctx,
2606 c->opt_user_name,
2607 c->opt_password,
2609 NULL,
2610 NULL,
2611 NULL,
2612 true,
2613 true,
2614 2592000, /* one month */
2615 impersonate_princ_s,
2616 &info);
2617 if (!NT_STATUS_IS_OK(status)) {
2618 d_printf(_("failed to query kerberos PAC: %s\n"),
2619 nt_errstr(status));
2620 goto out;
2623 if (info) {
2624 const char *s;
2625 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2626 d_printf(_("The Pac: %s\n"), s);
2629 ret = 0;
2630 out:
2631 TALLOC_FREE(mem_ctx);
2632 return ret;
2635 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2637 TALLOC_CTX *mem_ctx = NULL;
2638 int ret = -1;
2639 NTSTATUS status;
2641 if (c->display_usage) {
2642 d_printf( "%s\n"
2643 "net ads kerberos kinit\n"
2644 " %s\n",
2645 _("Usage:"),
2646 _("Get Ticket Granting Ticket (TGT) for the user"));
2647 return 0;
2650 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2651 if (!mem_ctx) {
2652 goto out;
2655 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2657 ret = kerberos_kinit_password_ext(c->opt_user_name,
2658 c->opt_password,
2660 NULL,
2661 NULL,
2662 NULL,
2663 true,
2664 true,
2665 2592000, /* one month */
2666 &status);
2667 if (ret) {
2668 d_printf(_("failed to kinit password: %s\n"),
2669 nt_errstr(status));
2671 out:
2672 return ret;
2675 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2677 struct functable func[] = {
2679 "kinit",
2680 net_ads_kerberos_kinit,
2681 NET_TRANSPORT_ADS,
2682 N_("Retrieve Ticket Granting Ticket (TGT)"),
2683 N_("net ads kerberos kinit\n"
2684 " Receive Ticket Granting Ticket (TGT)")
2687 "renew",
2688 net_ads_kerberos_renew,
2689 NET_TRANSPORT_ADS,
2690 N_("Renew Ticket Granting Ticket from credential cache"),
2691 N_("net ads kerberos renew\n"
2692 " Renew Ticket Granting Ticket (TGT) from "
2693 "credential cache")
2696 "pac",
2697 net_ads_kerberos_pac,
2698 NET_TRANSPORT_ADS,
2699 N_("Dump Kerberos PAC"),
2700 N_("net ads kerberos pac\n"
2701 " Dump Kerberos PAC")
2703 {NULL, NULL, 0, NULL, NULL}
2706 return net_run_function(c, argc, argv, "net ads kerberos", func);
2709 int net_ads(struct net_context *c, int argc, const char **argv)
2711 struct functable func[] = {
2713 "info",
2714 net_ads_info,
2715 NET_TRANSPORT_ADS,
2716 N_("Display details on remote ADS server"),
2717 N_("net ads info\n"
2718 " Display details on remote ADS server")
2721 "join",
2722 net_ads_join,
2723 NET_TRANSPORT_ADS,
2724 N_("Join the local machine to ADS realm"),
2725 N_("net ads join\n"
2726 " Join the local machine to ADS realm")
2729 "testjoin",
2730 net_ads_testjoin,
2731 NET_TRANSPORT_ADS,
2732 N_("Validate machine account"),
2733 N_("net ads testjoin\n"
2734 " Validate machine account")
2737 "leave",
2738 net_ads_leave,
2739 NET_TRANSPORT_ADS,
2740 N_("Remove the local machine from ADS"),
2741 N_("net ads leave\n"
2742 " Remove the local machine from ADS")
2745 "status",
2746 net_ads_status,
2747 NET_TRANSPORT_ADS,
2748 N_("Display machine account details"),
2749 N_("net ads status\n"
2750 " Display machine account details")
2753 "user",
2754 net_ads_user,
2755 NET_TRANSPORT_ADS,
2756 N_("List/modify users"),
2757 N_("net ads user\n"
2758 " List/modify users")
2761 "group",
2762 net_ads_group,
2763 NET_TRANSPORT_ADS,
2764 N_("List/modify groups"),
2765 N_("net ads group\n"
2766 " List/modify groups")
2769 "dns",
2770 net_ads_dns,
2771 NET_TRANSPORT_ADS,
2772 N_("Issue dynamic DNS update"),
2773 N_("net ads dns\n"
2774 " Issue dynamic DNS update")
2777 "password",
2778 net_ads_password,
2779 NET_TRANSPORT_ADS,
2780 N_("Change user passwords"),
2781 N_("net ads password\n"
2782 " Change user passwords")
2785 "changetrustpw",
2786 net_ads_changetrustpw,
2787 NET_TRANSPORT_ADS,
2788 N_("Change trust account password"),
2789 N_("net ads changetrustpw\n"
2790 " Change trust account password")
2793 "printer",
2794 net_ads_printer,
2795 NET_TRANSPORT_ADS,
2796 N_("List/modify printer entries"),
2797 N_("net ads printer\n"
2798 " List/modify printer entries")
2801 "search",
2802 net_ads_search,
2803 NET_TRANSPORT_ADS,
2804 N_("Issue LDAP search using filter"),
2805 N_("net ads search\n"
2806 " Issue LDAP search using filter")
2809 "dn",
2810 net_ads_dn,
2811 NET_TRANSPORT_ADS,
2812 N_("Issue LDAP search by DN"),
2813 N_("net ads dn\n"
2814 " Issue LDAP search by DN")
2817 "sid",
2818 net_ads_sid,
2819 NET_TRANSPORT_ADS,
2820 N_("Issue LDAP search by SID"),
2821 N_("net ads sid\n"
2822 " Issue LDAP search by SID")
2825 "workgroup",
2826 net_ads_workgroup,
2827 NET_TRANSPORT_ADS,
2828 N_("Display workgroup name"),
2829 N_("net ads workgroup\n"
2830 " Display the workgroup name")
2833 "lookup",
2834 net_ads_lookup,
2835 NET_TRANSPORT_ADS,
2836 N_("Perfom CLDAP query on DC"),
2837 N_("net ads lookup\n"
2838 " Find the ADS DC using CLDAP lookups")
2841 "keytab",
2842 net_ads_keytab,
2843 NET_TRANSPORT_ADS,
2844 N_("Manage local keytab file"),
2845 N_("net ads keytab\n"
2846 " Manage local keytab file")
2849 "gpo",
2850 net_ads_gpo,
2851 NET_TRANSPORT_ADS,
2852 N_("Manage group policy objects"),
2853 N_("net ads gpo\n"
2854 " Manage group policy objects")
2857 "kerberos",
2858 net_ads_kerberos,
2859 NET_TRANSPORT_ADS,
2860 N_("Manage kerberos keytab"),
2861 N_("net ads kerberos\n"
2862 " Manage kerberos keytab")
2864 {NULL, NULL, 0, NULL, NULL}
2867 return net_run_function(c, argc, argv, "net ads", func);
2870 #else
2872 static int net_ads_noads(void)
2874 d_fprintf(stderr, _("ADS support not compiled in\n"));
2875 return -1;
2878 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2880 return net_ads_noads();
2883 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2885 return net_ads_noads();
2888 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2890 return net_ads_noads();
2893 int net_ads_join(struct net_context *c, int argc, const char **argv)
2895 return net_ads_noads();
2898 int net_ads_user(struct net_context *c, int argc, const char **argv)
2900 return net_ads_noads();
2903 int net_ads_group(struct net_context *c, int argc, const char **argv)
2905 return net_ads_noads();
2908 int net_ads_gpo(struct net_context *c, int argc, const char **argv)
2910 return net_ads_noads();
2913 /* this one shouldn't display a message */
2914 int net_ads_check(struct net_context *c)
2916 return -1;
2919 int net_ads_check_our_domain(struct net_context *c)
2921 return -1;
2924 int net_ads(struct net_context *c, int argc, const char **argv)
2926 return net_ads_noads();
2929 #endif /* HAVE_ADS */