s3:winbind: Convert WINBINDD_GETGRNAM to the new API
[Samba/aatanasov.git] / source3 / utils / net_ads.c
blobebc175b8c791d0766b02be7adb61045c14677a93
1 /*
2 Samba Unix/Linux SMB client library
3 net ads commands
4 Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
5 Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
6 Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
7 Copyright (C) 2006 Gerald (Jerry) Carter (jerry@samba.org)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "utils/net.h"
25 #include "librpc/gen_ndr/ndr_krb5pac.h"
26 #include "nsswitch/libwbclient/wbclient.h"
28 #ifdef HAVE_ADS
30 /* when we do not have sufficient input parameters to contact a remote domain
31 * we always fall back to our own realm - Guenther*/
33 static const char *assume_own_realm(struct net_context *c)
35 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
36 return lp_realm();
39 return NULL;
43 do a cldap netlogon query
45 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
47 char addr[INET6_ADDRSTRLEN];
48 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
50 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
51 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
52 d_fprintf(stderr, _("CLDAP query failed!\n"));
53 return -1;
56 d_printf(_("Information for Domain Controller: %s\n\n"),
57 addr);
59 d_printf(_("Response Type: "));
60 switch (reply.command) {
61 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
62 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
63 break;
64 case LOGON_SAM_LOGON_RESPONSE_EX:
65 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
66 break;
67 default:
68 d_printf("0x%x\n", reply.command);
69 break;
72 d_printf(_("GUID: %s\n"), GUID_string(talloc_tos(),&reply.domain_uuid));
74 d_printf(_("Flags:\n"
75 "\tIs a PDC: %s\n"
76 "\tIs a GC of the forest: %s\n"
77 "\tIs an LDAP server: %s\n"
78 "\tSupports DS: %s\n"
79 "\tIs running a KDC: %s\n"
80 "\tIs running time services: %s\n"
81 "\tIs the closest DC: %s\n"
82 "\tIs writable: %s\n"
83 "\tHas a hardware clock: %s\n"
84 "\tIs a non-domain NC serviced by LDAP server: %s\n"
85 "\tIs NT6 DC that has some secrets: %s\n"
86 "\tIs NT6 DC that has all secrets: %s\n"),
87 (reply.server_type & NBT_SERVER_PDC) ? _("yes") : _("no"),
88 (reply.server_type & NBT_SERVER_GC) ? _("yes") : _("no"),
89 (reply.server_type & NBT_SERVER_LDAP) ? _("yes") : _("no"),
90 (reply.server_type & NBT_SERVER_DS) ? _("yes") : _("no"),
91 (reply.server_type & NBT_SERVER_KDC) ? _("yes") : _("no"),
92 (reply.server_type & NBT_SERVER_TIMESERV) ? _("yes") : _("no"),
93 (reply.server_type & NBT_SERVER_CLOSEST) ? _("yes") : _("no"),
94 (reply.server_type & NBT_SERVER_WRITABLE) ? _("yes") : _("no"),
95 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? _("yes") : _("no"),
96 (reply.server_type & NBT_SERVER_NDNC) ? _("yes") : _("no"),
97 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? _("yes") : _("no"),
98 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? _("yes") : _("no"));
101 printf(_("Forest:\t\t\t%s\n"), reply.forest);
102 printf(_("Domain:\t\t\t%s\n"), reply.dns_domain);
103 printf(_("Domain Controller:\t%s\n"), reply.pdc_dns_name);
105 printf(_("Pre-Win2k Domain:\t%s\n"), reply.domain);
106 printf(_("Pre-Win2k Hostname:\t%s\n"), reply.pdc_name);
108 if (*reply.user_name) printf(_("User name:\t%s\n"), reply.user_name);
110 printf(_("Server Site Name :\t\t%s\n"), reply.server_site);
111 printf(_("Client Site Name :\t\t%s\n"), reply.client_site);
113 d_printf(_("NT Version: %d\n"), reply.nt_version);
114 d_printf(_("LMNT Token: %.2x\n"), reply.lmnt_token);
115 d_printf(_("LM20 Token: %.2x\n"), reply.lm20_token);
117 return 0;
121 this implements the CLDAP based netlogon lookup requests
122 for finding the domain controller of a ADS domain
124 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
126 ADS_STRUCT *ads;
127 int ret;
129 if (c->display_usage) {
130 d_printf(_("Usage:\n"
131 "net ads lookup\n"
132 " Find the ADS DC using CLDAP lookup.\n"));
133 return 0;
136 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
137 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
138 ads_destroy(&ads);
139 return -1;
142 if (!ads->config.realm) {
143 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
144 ads->ldap.port = 389;
147 ret = net_ads_cldap_netlogon(c, ads);
148 ads_destroy(&ads);
149 return ret;
154 static int net_ads_info(struct net_context *c, int argc, const char **argv)
156 ADS_STRUCT *ads;
157 char addr[INET6_ADDRSTRLEN];
159 if (c->display_usage) {
160 d_printf(_("Usage:\n"
161 "net ads info\n"
162 " Display information about an Active Directory "
163 "server.\n"));
164 return 0;
167 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
168 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
169 return -1;
172 if (!ads || !ads->config.realm) {
173 d_fprintf(stderr, _("Didn't find the ldap server!\n"));
174 ads_destroy(&ads);
175 return -1;
178 /* Try to set the server's current time since we didn't do a full
179 TCP LDAP session initially */
181 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
182 d_fprintf( stderr, _("Failed to get server's current time!\n"));
185 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
187 d_printf(_("LDAP server: %s\n"), addr);
188 d_printf(_("LDAP server name: %s\n"), ads->config.ldap_server_name);
189 d_printf(_("Realm: %s\n"), ads->config.realm);
190 d_printf(_("Bind Path: %s\n"), ads->config.bind_path);
191 d_printf(_("LDAP port: %d\n"), ads->ldap.port);
192 d_printf(_("Server time: %s\n"),
193 http_timestring(talloc_tos(), ads->config.current_time));
195 d_printf(_("KDC server: %s\n"), ads->auth.kdc_server );
196 d_printf(_("Server time offset: %d\n"), ads->auth.time_offset );
198 ads_destroy(&ads);
199 return 0;
202 static void use_in_memory_ccache(void) {
203 /* Use in-memory credentials cache so we do not interfere with
204 * existing credentials */
205 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
208 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
209 uint32 auth_flags, ADS_STRUCT **ads_ret)
211 ADS_STRUCT *ads = NULL;
212 ADS_STATUS status;
213 bool need_password = false;
214 bool second_time = false;
215 char *cp;
216 const char *realm = NULL;
217 bool tried_closest_dc = false;
219 /* lp_realm() should be handled by a command line param,
220 However, the join requires that realm be set in smb.conf
221 and compares our realm with the remote server's so this is
222 ok until someone needs more flexibility */
224 *ads_ret = NULL;
226 retry_connect:
227 if (only_own_domain) {
228 realm = lp_realm();
229 } else {
230 realm = assume_own_realm(c);
233 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
235 if (!c->opt_user_name) {
236 c->opt_user_name = "administrator";
239 if (c->opt_user_specified) {
240 need_password = true;
243 retry:
244 if (!c->opt_password && need_password && !c->opt_machine_pass) {
245 c->opt_password = net_prompt_pass(c, c->opt_user_name);
246 if (!c->opt_password) {
247 ads_destroy(&ads);
248 return ADS_ERROR(LDAP_NO_MEMORY);
252 if (c->opt_password) {
253 use_in_memory_ccache();
254 SAFE_FREE(ads->auth.password);
255 ads->auth.password = smb_xstrdup(c->opt_password);
258 ads->auth.flags |= auth_flags;
259 SAFE_FREE(ads->auth.user_name);
260 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
263 * If the username is of the form "name@realm",
264 * extract the realm and convert to upper case.
265 * This is only used to establish the connection.
267 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
268 *cp++ = '\0';
269 SAFE_FREE(ads->auth.realm);
270 ads->auth.realm = smb_xstrdup(cp);
271 strupper_m(ads->auth.realm);
274 status = ads_connect(ads);
276 if (!ADS_ERR_OK(status)) {
278 if (NT_STATUS_EQUAL(ads_ntstatus(status),
279 NT_STATUS_NO_LOGON_SERVERS)) {
280 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
281 ads_destroy(&ads);
282 return status;
285 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
286 need_password = true;
287 second_time = true;
288 goto retry;
289 } else {
290 ads_destroy(&ads);
291 return status;
295 /* when contacting our own domain, make sure we use the closest DC.
296 * This is done by reconnecting to ADS because only the first call to
297 * ads_connect will give us our own sitename */
299 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
301 tried_closest_dc = true; /* avoid loop */
303 if (!ads_closest_dc(ads)) {
305 namecache_delete(ads->server.realm, 0x1C);
306 namecache_delete(ads->server.workgroup, 0x1C);
308 ads_destroy(&ads);
309 ads = NULL;
311 goto retry_connect;
315 *ads_ret = ads;
316 return status;
319 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
321 return ads_startup_int(c, only_own_domain, 0, ads);
324 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
326 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
330 Check to see if connection can be made via ads.
331 ads_startup() stores the password in opt_password if it needs to so
332 that rpc or rap can use it without re-prompting.
334 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
336 ADS_STRUCT *ads;
337 ADS_STATUS status;
339 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
340 return -1;
343 ads->auth.flags |= ADS_AUTH_NO_BIND;
345 status = ads_connect(ads);
346 if ( !ADS_ERR_OK(status) ) {
347 return -1;
350 ads_destroy(&ads);
351 return 0;
354 int net_ads_check_our_domain(struct net_context *c)
356 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
359 int net_ads_check(struct net_context *c)
361 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
365 determine the netbios workgroup name for a domain
367 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
369 ADS_STRUCT *ads;
370 char addr[INET6_ADDRSTRLEN];
371 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
373 if (c->display_usage) {
374 d_printf(_("Usage:\n"
375 "net ads workgroup\n"
376 " Print the workgroup name\n"));
377 return 0;
380 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
381 d_fprintf(stderr, _("Didn't find the cldap server!\n"));
382 return -1;
385 if (!ads->config.realm) {
386 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
387 ads->ldap.port = 389;
390 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
391 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
392 d_fprintf(stderr, _("CLDAP query failed!\n"));
393 ads_destroy(&ads);
394 return -1;
397 d_printf(_("Workgroup: %s\n"), reply.domain);
399 ads_destroy(&ads);
401 return 0;
406 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
408 char **disp_fields = (char **) data_area;
410 if (!field) { /* must be end of record */
411 if (disp_fields[0]) {
412 if (!strchr_m(disp_fields[0], '$')) {
413 if (disp_fields[1])
414 d_printf("%-21.21s %s\n",
415 disp_fields[0], disp_fields[1]);
416 else
417 d_printf("%s\n", disp_fields[0]);
420 SAFE_FREE(disp_fields[0]);
421 SAFE_FREE(disp_fields[1]);
422 return true;
424 if (!values) /* must be new field, indicate string field */
425 return true;
426 if (StrCaseCmp(field, "sAMAccountName") == 0) {
427 disp_fields[0] = SMB_STRDUP((char *) values[0]);
429 if (StrCaseCmp(field, "description") == 0)
430 disp_fields[1] = SMB_STRDUP((char *) values[0]);
431 return true;
434 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
436 return net_user_usage(c, argc, argv);
439 static int ads_user_add(struct net_context *c, int argc, const char **argv)
441 ADS_STRUCT *ads;
442 ADS_STATUS status;
443 char *upn, *userdn;
444 LDAPMessage *res=NULL;
445 int rc = -1;
446 char *ou_str = NULL;
448 if (argc < 1 || c->display_usage)
449 return net_ads_user_usage(c, argc, argv);
451 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
452 return -1;
455 status = ads_find_user_acct(ads, &res, argv[0]);
457 if (!ADS_ERR_OK(status)) {
458 d_fprintf(stderr, _("ads_user_add: %s\n"), ads_errstr(status));
459 goto done;
462 if (ads_count_replies(ads, res)) {
463 d_fprintf(stderr, _("ads_user_add: User %s already exists\n"),
464 argv[0]);
465 goto done;
468 if (c->opt_container) {
469 ou_str = SMB_STRDUP(c->opt_container);
470 } else {
471 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
474 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
476 if (!ADS_ERR_OK(status)) {
477 d_fprintf(stderr, _("Could not add user %s: %s\n"), argv[0],
478 ads_errstr(status));
479 goto done;
482 /* if no password is to be set, we're done */
483 if (argc == 1) {
484 d_printf(_("User %s added\n"), argv[0]);
485 rc = 0;
486 goto done;
489 /* try setting the password */
490 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
491 goto done;
493 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
494 ads->auth.time_offset);
495 SAFE_FREE(upn);
496 if (ADS_ERR_OK(status)) {
497 d_printf(_("User %s added\n"), argv[0]);
498 rc = 0;
499 goto done;
502 /* password didn't set, delete account */
503 d_fprintf(stderr, _("Could not add user %s. "
504 "Error setting password %s\n"),
505 argv[0], ads_errstr(status));
506 ads_msgfree(ads, res);
507 status=ads_find_user_acct(ads, &res, argv[0]);
508 if (ADS_ERR_OK(status)) {
509 userdn = ads_get_dn(ads, talloc_tos(), res);
510 ads_del_dn(ads, userdn);
511 TALLOC_FREE(userdn);
514 done:
515 if (res)
516 ads_msgfree(ads, res);
517 ads_destroy(&ads);
518 SAFE_FREE(ou_str);
519 return rc;
522 static int ads_user_info(struct net_context *c, int argc, const char **argv)
524 ADS_STRUCT *ads = NULL;
525 ADS_STATUS rc;
526 LDAPMessage *res = NULL;
527 TALLOC_CTX *frame;
528 int ret = 0;
529 wbcErr wbc_status;
530 const char *attrs[] = {"memberOf", "primaryGroupID", NULL};
531 char *searchstring=NULL;
532 char **grouplist;
533 char *primary_group;
534 char *escaped_user;
535 DOM_SID primary_group_sid;
536 uint32_t group_rid;
537 enum SID_NAME_USE type;
539 if (argc < 1 || c->display_usage) {
540 return net_ads_user_usage(c, argc, argv);
543 frame = talloc_new(talloc_tos());
544 if (frame == NULL) {
545 return -1;
548 escaped_user = escape_ldap_string(frame, argv[0]);
549 if (!escaped_user) {
550 d_fprintf(stderr,
551 _("ads_user_info: failed to escape user %s\n"),
552 argv[0]);
553 return -1;
556 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
557 ret = -1;
558 goto error;
561 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
562 ret =-1;
563 goto error;
565 rc = ads_search(ads, &res, searchstring, attrs);
566 SAFE_FREE(searchstring);
568 if (!ADS_ERR_OK(rc)) {
569 d_fprintf(stderr, _("ads_search: %s\n"), ads_errstr(rc));
570 ret = -1;
571 goto error;
574 if (!ads_pull_uint32(ads, res, "primaryGroupID", &group_rid)) {
575 d_fprintf(stderr, _("ads_pull_uint32 failed\n"));
576 ret = -1;
577 goto error;
580 rc = ads_domain_sid(ads, &primary_group_sid);
581 if (!ADS_ERR_OK(rc)) {
582 d_fprintf(stderr, _("ads_domain_sid: %s\n"), ads_errstr(rc));
583 ret = -1;
584 goto error;
587 sid_append_rid(&primary_group_sid, group_rid);
589 wbc_status = wbcLookupSid((struct wbcDomainSid *)&primary_group_sid,
590 NULL, /* don't look up domain */
591 &primary_group,
592 (enum wbcSidType *) &type);
593 if (!WBC_ERROR_IS_OK(wbc_status)) {
594 d_fprintf(stderr, "wbcLookupSid: %s\n",
595 wbcErrorString(wbc_status));
596 ret = -1;
597 goto error;
600 d_printf("%s\n", primary_group);
602 wbcFreeMemory(primary_group);
604 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
605 (LDAPMessage *)res, "memberOf");
607 if (grouplist) {
608 int i;
609 char **groupname;
610 for (i=0;grouplist[i];i++) {
611 groupname = ldap_explode_dn(grouplist[i], 1);
612 d_printf("%s\n", groupname[0]);
613 ldap_value_free(groupname);
615 ldap_value_free(grouplist);
618 error:
619 if (res) ads_msgfree(ads, res);
620 if (ads) ads_destroy(&ads);
621 TALLOC_FREE(frame);
622 return ret;
625 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
627 ADS_STRUCT *ads;
628 ADS_STATUS rc;
629 LDAPMessage *res = NULL;
630 char *userdn;
632 if (argc < 1) {
633 return net_ads_user_usage(c, argc, argv);
636 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
637 return -1;
640 rc = ads_find_user_acct(ads, &res, argv[0]);
641 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
642 d_printf(_("User %s does not exist.\n"), argv[0]);
643 ads_msgfree(ads, res);
644 ads_destroy(&ads);
645 return -1;
647 userdn = ads_get_dn(ads, talloc_tos(), res);
648 ads_msgfree(ads, res);
649 rc = ads_del_dn(ads, userdn);
650 TALLOC_FREE(userdn);
651 if (ADS_ERR_OK(rc)) {
652 d_printf(_("User %s deleted\n"), argv[0]);
653 ads_destroy(&ads);
654 return 0;
656 d_fprintf(stderr, _("Error deleting user %s: %s\n"), argv[0],
657 ads_errstr(rc));
658 ads_destroy(&ads);
659 return -1;
662 int net_ads_user(struct net_context *c, int argc, const char **argv)
664 struct functable func[] = {
666 "add",
667 ads_user_add,
668 NET_TRANSPORT_ADS,
669 N_("Add an AD user"),
670 N_("net ads user add\n"
671 " Add an AD user")
674 "info",
675 ads_user_info,
676 NET_TRANSPORT_ADS,
677 N_("Display information about an AD user"),
678 N_("net ads user info\n"
679 " Display information about an AD user")
682 "delete",
683 ads_user_delete,
684 NET_TRANSPORT_ADS,
685 N_("Delete an AD user"),
686 N_("net ads user delete\n"
687 " Delete an AD user")
689 {NULL, NULL, 0, NULL, NULL}
691 ADS_STRUCT *ads;
692 ADS_STATUS rc;
693 const char *shortattrs[] = {"sAMAccountName", NULL};
694 const char *longattrs[] = {"sAMAccountName", "description", NULL};
695 char *disp_fields[2] = {NULL, NULL};
697 if (argc == 0) {
698 if (c->display_usage) {
699 d_printf(_("Usage:\n"
700 "net ads user\n"
701 " List AD users\n"));
702 net_display_usage_from_functable(func);
703 return 0;
706 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
707 return -1;
710 if (c->opt_long_list_entries)
711 d_printf(_("\nUser name Comment"
712 "\n-----------------------------\n"));
714 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
715 LDAP_SCOPE_SUBTREE,
716 "(objectCategory=user)",
717 c->opt_long_list_entries ? longattrs :
718 shortattrs, usergrp_display,
719 disp_fields);
720 ads_destroy(&ads);
721 return ADS_ERR_OK(rc) ? 0 : -1;
724 return net_run_function(c, argc, argv, "net ads user", func);
727 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
729 return net_group_usage(c, argc, argv);
732 static int ads_group_add(struct net_context *c, int argc, const char **argv)
734 ADS_STRUCT *ads;
735 ADS_STATUS status;
736 LDAPMessage *res=NULL;
737 int rc = -1;
738 char *ou_str = NULL;
740 if (argc < 1 || c->display_usage) {
741 return net_ads_group_usage(c, argc, argv);
744 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
745 return -1;
748 status = ads_find_user_acct(ads, &res, argv[0]);
750 if (!ADS_ERR_OK(status)) {
751 d_fprintf(stderr, _("ads_group_add: %s\n"), ads_errstr(status));
752 goto done;
755 if (ads_count_replies(ads, res)) {
756 d_fprintf(stderr, _("ads_group_add: Group %s already exists\n"), argv[0]);
757 goto done;
760 if (c->opt_container) {
761 ou_str = SMB_STRDUP(c->opt_container);
762 } else {
763 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
766 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
768 if (ADS_ERR_OK(status)) {
769 d_printf(_("Group %s added\n"), argv[0]);
770 rc = 0;
771 } else {
772 d_fprintf(stderr, _("Could not add group %s: %s\n"), argv[0],
773 ads_errstr(status));
776 done:
777 if (res)
778 ads_msgfree(ads, res);
779 ads_destroy(&ads);
780 SAFE_FREE(ou_str);
781 return rc;
784 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
786 ADS_STRUCT *ads;
787 ADS_STATUS rc;
788 LDAPMessage *res = NULL;
789 char *groupdn;
791 if (argc < 1 || c->display_usage) {
792 return net_ads_group_usage(c, argc, argv);
795 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
796 return -1;
799 rc = ads_find_user_acct(ads, &res, argv[0]);
800 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
801 d_printf(_("Group %s does not exist.\n"), argv[0]);
802 ads_msgfree(ads, res);
803 ads_destroy(&ads);
804 return -1;
806 groupdn = ads_get_dn(ads, talloc_tos(), res);
807 ads_msgfree(ads, res);
808 rc = ads_del_dn(ads, groupdn);
809 TALLOC_FREE(groupdn);
810 if (ADS_ERR_OK(rc)) {
811 d_printf(_("Group %s deleted\n"), argv[0]);
812 ads_destroy(&ads);
813 return 0;
815 d_fprintf(stderr, _("Error deleting group %s: %s\n"), argv[0],
816 ads_errstr(rc));
817 ads_destroy(&ads);
818 return -1;
821 int net_ads_group(struct net_context *c, int argc, const char **argv)
823 struct functable func[] = {
825 "add",
826 ads_group_add,
827 NET_TRANSPORT_ADS,
828 N_("Add an AD group"),
829 N_("net ads group add\n"
830 " Add an AD group")
833 "delete",
834 ads_group_delete,
835 NET_TRANSPORT_ADS,
836 N_("Delete an AD group"),
837 N_("net ads group delete\n"
838 " Delete an AD group")
840 {NULL, NULL, 0, NULL, NULL}
842 ADS_STRUCT *ads;
843 ADS_STATUS rc;
844 const char *shortattrs[] = {"sAMAccountName", NULL};
845 const char *longattrs[] = {"sAMAccountName", "description", NULL};
846 char *disp_fields[2] = {NULL, NULL};
848 if (argc == 0) {
849 if (c->display_usage) {
850 d_printf(_("Usage:\n"
851 "net ads group\n"
852 " List AD groups\n"));
853 net_display_usage_from_functable(func);
854 return 0;
857 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
858 return -1;
861 if (c->opt_long_list_entries)
862 d_printf(_("\nGroup name Comment"
863 "\n-----------------------------\n"));
864 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
865 LDAP_SCOPE_SUBTREE,
866 "(objectCategory=group)",
867 c->opt_long_list_entries ? longattrs :
868 shortattrs, usergrp_display,
869 disp_fields);
871 ads_destroy(&ads);
872 return ADS_ERR_OK(rc) ? 0 : -1;
874 return net_run_function(c, argc, argv, "net ads group", func);
877 static int net_ads_status(struct net_context *c, int argc, const char **argv)
879 ADS_STRUCT *ads;
880 ADS_STATUS rc;
881 LDAPMessage *res;
883 if (c->display_usage) {
884 d_printf(_("Usage:\n"
885 "net ads status\n"
886 " Display machine account details\n"));
887 return 0;
890 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
891 return -1;
894 rc = ads_find_machine_acct(ads, &res, global_myname());
895 if (!ADS_ERR_OK(rc)) {
896 d_fprintf(stderr, _("ads_find_machine_acct: %s\n"), ads_errstr(rc));
897 ads_destroy(&ads);
898 return -1;
901 if (ads_count_replies(ads, res) == 0) {
902 d_fprintf(stderr, _("No machine account for '%s' found\n"), global_myname());
903 ads_destroy(&ads);
904 return -1;
907 ads_dump(ads, res);
908 ads_destroy(&ads);
909 return 0;
912 /*******************************************************************
913 Leave an AD domain. Windows XP disables the machine account.
914 We'll try the same. The old code would do an LDAP delete.
915 That only worked using the machine creds because added the machine
916 with full control to the computer object's ACL.
917 *******************************************************************/
919 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
921 TALLOC_CTX *ctx;
922 struct libnet_UnjoinCtx *r = NULL;
923 WERROR werr;
925 if (c->display_usage) {
926 d_printf(_("Usage:\n"
927 "net ads leave\n"
928 " Leave an AD domain\n"));
929 return 0;
932 if (!*lp_realm()) {
933 d_fprintf(stderr, _("No realm set, are we joined ?\n"));
934 return -1;
937 if (!(ctx = talloc_init("net_ads_leave"))) {
938 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
939 return -1;
942 if (!c->opt_kerberos) {
943 use_in_memory_ccache();
946 werr = libnet_init_UnjoinCtx(ctx, &r);
947 if (!W_ERROR_IS_OK(werr)) {
948 d_fprintf(stderr, _("Could not initialise unjoin context.\n"));
949 return -1;
952 r->in.debug = true;
953 r->in.use_kerberos = c->opt_kerberos;
954 r->in.dc_name = c->opt_host;
955 r->in.domain_name = lp_realm();
956 r->in.admin_account = c->opt_user_name;
957 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
958 r->in.modify_config = lp_config_backend_is_registry();
960 /* Try to delete it, but if that fails, disable it. The
961 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE really means "disable */
962 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
963 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
964 r->in.delete_machine_account = true;
966 werr = libnet_Unjoin(ctx, r);
967 if (!W_ERROR_IS_OK(werr)) {
968 d_printf(_("Failed to leave domain: %s\n"),
969 r->out.error_string ? r->out.error_string :
970 get_friendly_werror_msg(werr));
971 goto done;
974 if (r->out.deleted_machine_account) {
975 d_printf(_("Deleted account for '%s' in realm '%s'\n"),
976 r->in.machine_name, r->out.dns_domain_name);
977 goto done;
980 /* We couldn't delete it - see if the disable succeeded. */
981 if (r->out.disabled_machine_account) {
982 d_printf(_("Disabled account for '%s' in realm '%s'\n"),
983 r->in.machine_name, r->out.dns_domain_name);
984 werr = WERR_OK;
985 goto done;
988 /* Based on what we requseted, we shouldn't get here, but if
989 we did, it means the secrets were removed, and therefore
990 we have left the domain */
991 d_fprintf(stderr, _("Machine '%s' Left domain '%s'\n"),
992 r->in.machine_name, r->out.dns_domain_name);
994 done:
995 TALLOC_FREE(r);
996 TALLOC_FREE(ctx);
998 if (W_ERROR_IS_OK(werr)) {
999 return 0;
1002 return -1;
1005 static NTSTATUS net_ads_join_ok(struct net_context *c)
1007 ADS_STRUCT *ads = NULL;
1008 ADS_STATUS status;
1010 if (!secrets_init()) {
1011 DEBUG(1,("Failed to initialise secrets database\n"));
1012 return NT_STATUS_ACCESS_DENIED;
1015 net_use_krb_machine_account(c);
1017 status = ads_startup(c, true, &ads);
1018 if (!ADS_ERR_OK(status)) {
1019 return ads_ntstatus(status);
1022 ads_destroy(&ads);
1023 return NT_STATUS_OK;
1027 check that an existing join is OK
1029 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
1031 NTSTATUS status;
1032 use_in_memory_ccache();
1034 if (c->display_usage) {
1035 d_printf(_("Usage:\n"
1036 "net ads testjoin\n"
1037 " Test if the existing join is ok\n"));
1038 return 0;
1041 /* Display success or failure */
1042 status = net_ads_join_ok(c);
1043 if (!NT_STATUS_IS_OK(status)) {
1044 fprintf(stderr, _("Join to domain is not valid: %s\n"),
1045 get_friendly_nt_error_msg(status));
1046 return -1;
1049 printf(_("Join is OK\n"));
1050 return 0;
1053 /*******************************************************************
1054 Simple configu checks before beginning the join
1055 ********************************************************************/
1057 static WERROR check_ads_config( void )
1059 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1060 d_printf(_("Host is not configured as a member server.\n"));
1061 return WERR_INVALID_DOMAIN_ROLE;
1064 if (strlen(global_myname()) > 15) {
1065 d_printf(_("Our netbios name can be at most 15 chars long, "
1066 "\"%s\" is %u chars long\n"), global_myname(),
1067 (unsigned int)strlen(global_myname()));
1068 return WERR_INVALID_COMPUTERNAME;
1071 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1072 d_fprintf(stderr, _("realm must be set in in %s for ADS "
1073 "join to succeed.\n"), get_dyn_CONFIGFILE());
1074 return WERR_INVALID_PARAM;
1077 return WERR_OK;
1080 /*******************************************************************
1081 Send a DNS update request
1082 *******************************************************************/
1084 #if defined(WITH_DNS_UPDATES)
1085 #include "dns.h"
1086 DNS_ERROR DoDNSUpdate(char *pszServerName,
1087 const char *pszDomainName, const char *pszHostName,
1088 const struct sockaddr_storage *sslist,
1089 size_t num_addrs );
1091 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1092 const char *machine_name,
1093 const struct sockaddr_storage *addrs,
1094 int num_addrs)
1096 struct dns_rr_ns *nameservers = NULL;
1097 int ns_count = 0;
1098 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1099 DNS_ERROR dns_err;
1100 fstring dns_server;
1101 const char *dnsdomain = NULL;
1102 char *root_domain = NULL;
1104 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1105 d_printf(_("No DNS domain configured for %s. "
1106 "Unable to perform DNS Update.\n"), machine_name);
1107 status = NT_STATUS_INVALID_PARAMETER;
1108 goto done;
1110 dnsdomain++;
1112 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1113 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1114 /* Child domains often do not have NS records. Look
1115 for the NS record for the forest root domain
1116 (rootDomainNamingContext in therootDSE) */
1118 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1119 LDAPMessage *msg = NULL;
1120 char *root_dn;
1121 ADS_STATUS ads_status;
1123 if ( !ads->ldap.ld ) {
1124 ads_status = ads_connect( ads );
1125 if ( !ADS_ERR_OK(ads_status) ) {
1126 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1127 goto done;
1131 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1132 "(objectclass=*)", rootname_attrs, &msg);
1133 if (!ADS_ERR_OK(ads_status)) {
1134 goto done;
1137 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1138 if ( !root_dn ) {
1139 ads_msgfree( ads, msg );
1140 goto done;
1143 root_domain = ads_build_domain( root_dn );
1145 /* cleanup */
1146 ads_msgfree( ads, msg );
1148 /* try again for NS servers */
1150 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1152 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1153 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1154 "realm\n", ads->config.realm));
1155 goto done;
1158 dnsdomain = root_domain;
1162 /* Now perform the dns update - we'll try non-secure and if we fail,
1163 we'll follow it up with a secure update */
1165 fstrcpy( dns_server, nameservers[0].hostname );
1167 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1168 if (!ERR_DNS_IS_OK(dns_err)) {
1169 status = NT_STATUS_UNSUCCESSFUL;
1172 done:
1174 SAFE_FREE( root_domain );
1176 return status;
1179 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1181 int num_addrs;
1182 struct sockaddr_storage *iplist = NULL;
1183 fstring machine_name;
1184 NTSTATUS status;
1186 name_to_fqdn( machine_name, global_myname() );
1187 strlower_m( machine_name );
1189 /* Get our ip address (not the 127.0.0.x address but a real ip
1190 * address) */
1192 num_addrs = get_my_ip_address( &iplist );
1193 if ( num_addrs <= 0 ) {
1194 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1195 "addresses!\n"));
1196 return NT_STATUS_INVALID_PARAMETER;
1199 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1200 iplist, num_addrs);
1201 SAFE_FREE( iplist );
1202 return status;
1204 #endif
1207 /*******************************************************************
1208 ********************************************************************/
1210 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1212 d_printf(_("net ads join [options]\n"
1213 "Valid options:\n"));
1214 d_printf(_(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n"
1215 " The deault UPN is in the form host/netbiosname@REALM.\n"));
1216 d_printf(_(" createcomputer=OU Precreate the computer account in a specific OU.\n"
1217 " The OU string read from top to bottom without RDNs and delimited by a '/'.\n"
1218 " E.g. \"createcomputer=Computers/Servers/Unix\"\n"
1219 " NB: A backslash '\\' is used as escape at multiple levels and may\n"
1220 " need to be doubled or even quadrupled. It is not used as a separator.\n"));
1221 d_printf(_(" osName=string Set the operatingSystem attribute during the join.\n"));
1222 d_printf(_(" osVer=string Set the operatingSystemVersion attribute during the join.\n"
1223 " NB: osName and osVer must be specified together for either to take effect.\n"
1224 " Also, the operatingSystemService attribute is also set when along with\n"
1225 " the two other attributes.\n"));
1227 return -1;
1230 /*******************************************************************
1231 ********************************************************************/
1233 int net_ads_join(struct net_context *c, int argc, const char **argv)
1235 TALLOC_CTX *ctx = NULL;
1236 struct libnet_JoinCtx *r = NULL;
1237 const char *domain = lp_realm();
1238 WERROR werr = WERR_SETUP_NOT_JOINED;
1239 bool createupn = false;
1240 const char *machineupn = NULL;
1241 const char *create_in_ou = NULL;
1242 int i;
1243 const char *os_name = NULL;
1244 const char *os_version = NULL;
1245 bool modify_config = lp_config_backend_is_registry();
1247 if (c->display_usage)
1248 return net_ads_join_usage(c, argc, argv);
1250 if (!modify_config) {
1252 werr = check_ads_config();
1253 if (!W_ERROR_IS_OK(werr)) {
1254 d_fprintf(stderr, _("Invalid configuration. Exiting....\n"));
1255 goto fail;
1259 if (!(ctx = talloc_init("net_ads_join"))) {
1260 d_fprintf(stderr, _("Could not initialise talloc context.\n"));
1261 werr = WERR_NOMEM;
1262 goto fail;
1265 if (!c->opt_kerberos) {
1266 use_in_memory_ccache();
1269 werr = libnet_init_JoinCtx(ctx, &r);
1270 if (!W_ERROR_IS_OK(werr)) {
1271 goto fail;
1274 /* process additional command line args */
1276 for ( i=0; i<argc; i++ ) {
1277 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1278 createupn = true;
1279 machineupn = get_string_param(argv[i]);
1281 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1282 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1283 d_fprintf(stderr, _("Please supply a valid OU path.\n"));
1284 werr = WERR_INVALID_PARAM;
1285 goto fail;
1288 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1289 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1290 d_fprintf(stderr, _("Please supply a operating system name.\n"));
1291 werr = WERR_INVALID_PARAM;
1292 goto fail;
1295 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1296 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1297 d_fprintf(stderr, _("Please supply a valid operating system version.\n"));
1298 werr = WERR_INVALID_PARAM;
1299 goto fail;
1302 else {
1303 domain = argv[i];
1307 if (!*domain) {
1308 d_fprintf(stderr, _("Please supply a valid domain name\n"));
1309 werr = WERR_INVALID_PARAM;
1310 goto fail;
1313 /* Do the domain join here */
1315 r->in.domain_name = domain;
1316 r->in.create_upn = createupn;
1317 r->in.upn = machineupn;
1318 r->in.account_ou = create_in_ou;
1319 r->in.os_name = os_name;
1320 r->in.os_version = os_version;
1321 r->in.dc_name = c->opt_host;
1322 r->in.admin_account = c->opt_user_name;
1323 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1324 r->in.debug = true;
1325 r->in.use_kerberos = c->opt_kerberos;
1326 r->in.modify_config = modify_config;
1327 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1328 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1329 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1331 werr = libnet_Join(ctx, r);
1332 if (!W_ERROR_IS_OK(werr)) {
1333 goto fail;
1336 /* Check the short name of the domain */
1338 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1339 d_printf(_("The workgroup in %s does not match the short\n"
1340 "domain name obtained from the server.\n"
1341 "Using the name [%s] from the server.\n"
1342 "You should set \"workgroup = %s\" in %s.\n"),
1343 get_dyn_CONFIGFILE(), r->out.netbios_domain_name,
1344 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1347 d_printf(_("Using short domain name -- %s\n"), r->out.netbios_domain_name);
1349 if (r->out.dns_domain_name) {
1350 d_printf(_("Joined '%s' to realm '%s'\n"), r->in.machine_name,
1351 r->out.dns_domain_name);
1352 } else {
1353 d_printf(_("Joined '%s' to domain '%s'\n"), r->in.machine_name,
1354 r->out.netbios_domain_name);
1357 #if defined(WITH_DNS_UPDATES)
1358 if (r->out.domain_is_ad) {
1359 /* We enter this block with user creds */
1360 ADS_STRUCT *ads_dns = NULL;
1362 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1363 /* kinit with the machine password */
1365 use_in_memory_ccache();
1366 if (asprintf( &ads_dns->auth.user_name, "%s$", global_myname()) == -1) {
1367 goto fail;
1369 ads_dns->auth.password = secrets_fetch_machine_password(
1370 r->out.netbios_domain_name, NULL, NULL );
1371 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1372 strupper_m(ads_dns->auth.realm );
1373 ads_kinit_password( ads_dns );
1376 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1377 d_fprintf( stderr, _("DNS update failed!\n") );
1380 /* exit from this block using machine creds */
1381 ads_destroy(&ads_dns);
1383 #endif
1384 TALLOC_FREE(r);
1385 TALLOC_FREE( ctx );
1387 return 0;
1389 fail:
1390 /* issue an overall failure message at the end. */
1391 d_printf(_("Failed to join domain: %s\n"),
1392 r && r->out.error_string ? r->out.error_string :
1393 get_friendly_werror_msg(werr));
1394 TALLOC_FREE( ctx );
1396 return -1;
1399 /*******************************************************************
1400 ********************************************************************/
1402 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1404 #if defined(WITH_DNS_UPDATES)
1405 ADS_STRUCT *ads;
1406 ADS_STATUS status;
1407 TALLOC_CTX *ctx;
1409 #ifdef DEVELOPER
1410 talloc_enable_leak_report();
1411 #endif
1413 if (argc > 0 || c->display_usage) {
1414 d_printf(_("Usage:\n"
1415 "net ads dns register\n"
1416 " Register hostname with DNS\n"));
1417 return -1;
1420 if (!(ctx = talloc_init("net_ads_dns"))) {
1421 d_fprintf(stderr, _("Could not initialise talloc context\n"));
1422 return -1;
1425 status = ads_startup(c, true, &ads);
1426 if ( !ADS_ERR_OK(status) ) {
1427 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1428 TALLOC_FREE(ctx);
1429 return -1;
1432 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1433 d_fprintf( stderr, _("DNS update failed!\n") );
1434 ads_destroy( &ads );
1435 TALLOC_FREE( ctx );
1436 return -1;
1439 d_fprintf( stderr, _("Successfully registered hostname with DNS\n") );
1441 ads_destroy(&ads);
1442 TALLOC_FREE( ctx );
1444 return 0;
1445 #else
1446 d_fprintf(stderr,
1447 _("DNS update support not enabled at compile time!\n"));
1448 return -1;
1449 #endif
1452 #if defined(WITH_DNS_UPDATES)
1453 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1454 #endif
1456 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1458 #if defined(WITH_DNS_UPDATES)
1459 DNS_ERROR err;
1461 #ifdef DEVELOPER
1462 talloc_enable_leak_report();
1463 #endif
1465 if (argc != 2 || c->display_usage) {
1466 d_printf(_("Usage:\n"
1467 "net ads dns gethostbyname <server> <name>\n"
1468 " Look up hostname from the AD\n"
1469 " server\tName server to use\n"
1470 " name\tName to look up\n"));
1471 return -1;
1474 err = do_gethostbyname(argv[0], argv[1]);
1476 d_printf(_("do_gethostbyname returned %d\n"), ERROR_DNS_V(err));
1477 #endif
1478 return 0;
1481 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1483 struct functable func[] = {
1485 "register",
1486 net_ads_dns_register,
1487 NET_TRANSPORT_ADS,
1488 N_("Add host dns entry to AD"),
1489 N_("net ads dns register\n"
1490 " Add host dns entry to AD")
1493 "gethostbyname",
1494 net_ads_dns_gethostbyname,
1495 NET_TRANSPORT_ADS,
1496 N_("Look up host"),
1497 N_("net ads dns gethostbyname\n"
1498 " Look up host")
1500 {NULL, NULL, 0, NULL, NULL}
1503 return net_run_function(c, argc, argv, "net ads dns", func);
1506 /*******************************************************************
1507 ********************************************************************/
1509 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1511 d_printf(_(
1512 "\nnet ads printer search <printer>"
1513 "\n\tsearch for a printer in the directory\n"
1514 "\nnet ads printer info <printer> <server>"
1515 "\n\tlookup info in directory for printer on server"
1516 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1517 "\nnet ads printer publish <printername>"
1518 "\n\tpublish printer in directory"
1519 "\n\t(note: printer name is required)\n"
1520 "\nnet ads printer remove <printername>"
1521 "\n\tremove printer from directory"
1522 "\n\t(note: printer name is required)\n"));
1523 return -1;
1526 /*******************************************************************
1527 ********************************************************************/
1529 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1531 ADS_STRUCT *ads;
1532 ADS_STATUS rc;
1533 LDAPMessage *res = NULL;
1535 if (c->display_usage) {
1536 d_printf(_("Usage:\n"
1537 "net ads printer search\n"
1538 " List printers in the AD\n"));
1539 return 0;
1542 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1543 return -1;
1546 rc = ads_find_printers(ads, &res);
1548 if (!ADS_ERR_OK(rc)) {
1549 d_fprintf(stderr, _("ads_find_printer: %s\n"), ads_errstr(rc));
1550 ads_msgfree(ads, res);
1551 ads_destroy(&ads);
1552 return -1;
1555 if (ads_count_replies(ads, res) == 0) {
1556 d_fprintf(stderr, _("No results found\n"));
1557 ads_msgfree(ads, res);
1558 ads_destroy(&ads);
1559 return -1;
1562 ads_dump(ads, res);
1563 ads_msgfree(ads, res);
1564 ads_destroy(&ads);
1565 return 0;
1568 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1570 ADS_STRUCT *ads;
1571 ADS_STATUS rc;
1572 const char *servername, *printername;
1573 LDAPMessage *res = NULL;
1575 if (c->display_usage) {
1576 d_printf(_("Usage:\n"
1577 "net ads printer info [printername [servername]]\n"
1578 " Display printer info from AD\n"
1579 " printername\tPrinter name or wildcard\n"
1580 " servername\tName of the print server\n"));
1581 return 0;
1584 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1585 return -1;
1588 if (argc > 0) {
1589 printername = argv[0];
1590 } else {
1591 printername = "*";
1594 if (argc > 1) {
1595 servername = argv[1];
1596 } else {
1597 servername = global_myname();
1600 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1602 if (!ADS_ERR_OK(rc)) {
1603 d_fprintf(stderr, _("Server '%s' not found: %s\n"),
1604 servername, ads_errstr(rc));
1605 ads_msgfree(ads, res);
1606 ads_destroy(&ads);
1607 return -1;
1610 if (ads_count_replies(ads, res) == 0) {
1611 d_fprintf(stderr, _("Printer '%s' not found\n"), printername);
1612 ads_msgfree(ads, res);
1613 ads_destroy(&ads);
1614 return -1;
1617 ads_dump(ads, res);
1618 ads_msgfree(ads, res);
1619 ads_destroy(&ads);
1621 return 0;
1624 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1626 ADS_STRUCT *ads;
1627 ADS_STATUS rc;
1628 const char *servername, *printername;
1629 struct cli_state *cli;
1630 struct rpc_pipe_client *pipe_hnd;
1631 struct sockaddr_storage server_ss;
1632 NTSTATUS nt_status;
1633 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1634 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1635 char *prt_dn, *srv_dn, **srv_cn;
1636 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1637 LDAPMessage *res = NULL;
1639 if (argc < 1 || c->display_usage) {
1640 d_printf(_("Usage:\n"
1641 "net ads printer publish <printername> [servername]\n"
1642 " Publish printer in AD\n"
1643 " printername\tName of the printer\n"
1644 " servername\tName of the print server\n"));
1645 talloc_destroy(mem_ctx);
1646 return -1;
1649 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1650 talloc_destroy(mem_ctx);
1651 return -1;
1654 printername = argv[0];
1656 if (argc == 2) {
1657 servername = argv[1];
1658 } else {
1659 servername = global_myname();
1662 /* Get printer data from SPOOLSS */
1664 resolve_name(servername, &server_ss, 0x20, false);
1666 nt_status = cli_full_connection(&cli, global_myname(), servername,
1667 &server_ss, 0,
1668 "IPC$", "IPC",
1669 c->opt_user_name, c->opt_workgroup,
1670 c->opt_password ? c->opt_password : "",
1671 CLI_FULL_CONNECTION_USE_KERBEROS,
1672 Undefined, NULL);
1674 if (NT_STATUS_IS_ERR(nt_status)) {
1675 d_fprintf(stderr, _("Unable to open a connnection to %s to "
1676 "obtain data for %s\n"),
1677 servername, printername);
1678 ads_destroy(&ads);
1679 talloc_destroy(mem_ctx);
1680 return -1;
1683 /* Publish on AD server */
1685 ads_find_machine_acct(ads, &res, servername);
1687 if (ads_count_replies(ads, res) == 0) {
1688 d_fprintf(stderr, _("Could not find machine account for server "
1689 "%s\n"),
1690 servername);
1691 ads_destroy(&ads);
1692 talloc_destroy(mem_ctx);
1693 return -1;
1696 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1697 srv_cn = ldap_explode_dn(srv_dn, 1);
1699 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1700 printername_escaped = escape_rdn_val_string_alloc(printername);
1701 if (!srv_cn_escaped || !printername_escaped) {
1702 SAFE_FREE(srv_cn_escaped);
1703 SAFE_FREE(printername_escaped);
1704 d_fprintf(stderr, _("Internal error, out of memory!"));
1705 ads_destroy(&ads);
1706 talloc_destroy(mem_ctx);
1707 return -1;
1710 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1711 SAFE_FREE(srv_cn_escaped);
1712 SAFE_FREE(printername_escaped);
1713 d_fprintf(stderr, _("Internal error, out of memory!"));
1714 ads_destroy(&ads);
1715 talloc_destroy(mem_ctx);
1716 return -1;
1719 SAFE_FREE(srv_cn_escaped);
1720 SAFE_FREE(printername_escaped);
1722 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
1723 if (!NT_STATUS_IS_OK(nt_status)) {
1724 d_fprintf(stderr, _("Unable to open a connnection to the spoolss pipe on %s\n"),
1725 servername);
1726 SAFE_FREE(prt_dn);
1727 ads_destroy(&ads);
1728 talloc_destroy(mem_ctx);
1729 return -1;
1732 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1733 printername))) {
1734 SAFE_FREE(prt_dn);
1735 ads_destroy(&ads);
1736 talloc_destroy(mem_ctx);
1737 return -1;
1740 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1741 if (!ADS_ERR_OK(rc)) {
1742 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1743 SAFE_FREE(prt_dn);
1744 ads_destroy(&ads);
1745 talloc_destroy(mem_ctx);
1746 return -1;
1749 d_printf("published printer\n");
1750 SAFE_FREE(prt_dn);
1751 ads_destroy(&ads);
1752 talloc_destroy(mem_ctx);
1754 return 0;
1757 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1759 ADS_STRUCT *ads;
1760 ADS_STATUS rc;
1761 const char *servername;
1762 char *prt_dn;
1763 LDAPMessage *res = NULL;
1765 if (argc < 1 || c->display_usage) {
1766 d_printf(_("Usage:\n"
1767 "net ads printer remove <printername> [servername]\n"
1768 " Remove a printer from the AD\n"
1769 " printername\tName of the printer\n"
1770 " servername\tName of the print server\n"));
1771 return -1;
1774 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1775 return -1;
1778 if (argc > 1) {
1779 servername = argv[1];
1780 } else {
1781 servername = global_myname();
1784 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1786 if (!ADS_ERR_OK(rc)) {
1787 d_fprintf(stderr, _("ads_find_printer_on_server: %s\n"), ads_errstr(rc));
1788 ads_msgfree(ads, res);
1789 ads_destroy(&ads);
1790 return -1;
1793 if (ads_count_replies(ads, res) == 0) {
1794 d_fprintf(stderr, _("Printer '%s' not found\n"), argv[1]);
1795 ads_msgfree(ads, res);
1796 ads_destroy(&ads);
1797 return -1;
1800 prt_dn = ads_get_dn(ads, talloc_tos(), res);
1801 ads_msgfree(ads, res);
1802 rc = ads_del_dn(ads, prt_dn);
1803 TALLOC_FREE(prt_dn);
1805 if (!ADS_ERR_OK(rc)) {
1806 d_fprintf(stderr, _("ads_del_dn: %s\n"), ads_errstr(rc));
1807 ads_destroy(&ads);
1808 return -1;
1811 ads_destroy(&ads);
1812 return 0;
1815 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1817 struct functable func[] = {
1819 "search",
1820 net_ads_printer_search,
1821 NET_TRANSPORT_ADS,
1822 N_("Search for a printer"),
1823 N_("net ads printer search\n"
1824 " Search for a printer")
1827 "info",
1828 net_ads_printer_info,
1829 NET_TRANSPORT_ADS,
1830 N_("Display printer information"),
1831 N_("net ads printer info\n"
1832 " Display printer information")
1835 "publish",
1836 net_ads_printer_publish,
1837 NET_TRANSPORT_ADS,
1838 N_("Publish a printer"),
1839 N_("net ads printer publish\n"
1840 " Publish a printer")
1843 "remove",
1844 net_ads_printer_remove,
1845 NET_TRANSPORT_ADS,
1846 N_("Delete a printer"),
1847 N_("net ads printer remove\n"
1848 " Delete a printer")
1850 {NULL, NULL, 0, NULL, NULL}
1853 return net_run_function(c, argc, argv, "net ads printer", func);
1857 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1859 ADS_STRUCT *ads;
1860 const char *auth_principal = c->opt_user_name;
1861 const char *auth_password = c->opt_password;
1862 char *realm = NULL;
1863 char *new_password = NULL;
1864 char *chr, *prompt;
1865 const char *user;
1866 ADS_STATUS ret;
1868 if (c->display_usage) {
1869 d_printf(_("Usage:\n"
1870 "net ads password <username>\n"
1871 " Change password for user\n"
1872 " username\tName of user to change password for\n"));
1873 return 0;
1876 if (c->opt_user_name == NULL || c->opt_password == NULL) {
1877 d_fprintf(stderr, _("You must supply an administrator "
1878 "username/password\n"));
1879 return -1;
1882 if (argc < 1) {
1883 d_fprintf(stderr, _("ERROR: You must say which username to "
1884 "change password for\n"));
1885 return -1;
1888 user = argv[0];
1889 if (!strchr_m(user, '@')) {
1890 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
1891 return -1;
1893 user = chr;
1896 use_in_memory_ccache();
1897 chr = strchr_m(auth_principal, '@');
1898 if (chr) {
1899 realm = ++chr;
1900 } else {
1901 realm = lp_realm();
1904 /* use the realm so we can eventually change passwords for users
1905 in realms other than default */
1906 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1907 return -1;
1910 /* we don't actually need a full connect, but it's the easy way to
1911 fill in the KDC's addresss */
1912 ads_connect(ads);
1914 if (!ads->config.realm) {
1915 d_fprintf(stderr, _("Didn't find the kerberos server!\n"));
1916 ads_destroy(&ads);
1917 return -1;
1920 if (argv[1]) {
1921 new_password = (char *)argv[1];
1922 } else {
1923 if (asprintf(&prompt, _("Enter new password for %s:"), user) == -1) {
1924 return -1;
1926 new_password = getpass(prompt);
1927 free(prompt);
1930 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1931 auth_password, user, new_password, ads->auth.time_offset);
1932 if (!ADS_ERR_OK(ret)) {
1933 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
1934 ads_destroy(&ads);
1935 return -1;
1938 d_printf(_("Password change for %s completed.\n"), user);
1939 ads_destroy(&ads);
1941 return 0;
1944 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1946 ADS_STRUCT *ads;
1947 char *host_principal;
1948 fstring my_name;
1949 ADS_STATUS ret;
1951 if (c->display_usage) {
1952 d_printf(_("Usage:\n"
1953 "net ads changetrustpw\n"
1954 " Change the machine account's trust password\n"));
1955 return 0;
1958 if (!secrets_init()) {
1959 DEBUG(1,("Failed to initialise secrets database\n"));
1960 return -1;
1963 net_use_krb_machine_account(c);
1965 use_in_memory_ccache();
1967 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1968 return -1;
1971 fstrcpy(my_name, global_myname());
1972 strlower_m(my_name);
1973 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
1974 ads_destroy(&ads);
1975 return -1;
1977 d_printf(_("Changing password for principal: %s\n"), host_principal);
1979 ret = ads_change_trust_account_password(ads, host_principal);
1981 if (!ADS_ERR_OK(ret)) {
1982 d_fprintf(stderr, _("Password change failed: %s\n"), ads_errstr(ret));
1983 ads_destroy(&ads);
1984 SAFE_FREE(host_principal);
1985 return -1;
1988 d_printf(_("Password change for principal %s succeeded.\n"), host_principal);
1990 if (USE_SYSTEM_KEYTAB) {
1991 d_printf(_("Attempting to update system keytab with new password.\n"));
1992 if (ads_keytab_create_default(ads)) {
1993 d_printf(_("Failed to update system keytab.\n"));
1997 ads_destroy(&ads);
1998 SAFE_FREE(host_principal);
2000 return 0;
2004 help for net ads search
2006 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
2008 d_printf(_(
2009 "\nnet ads search <expression> <attributes...>\n"
2010 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
2011 "The expression is a standard LDAP search expression, and the\n"
2012 "attributes are a list of LDAP fields to show in the results.\n\n"
2013 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
2015 net_common_flags_usage(c, argc, argv);
2016 return -1;
2021 general ADS search function. Useful in diagnosing problems in ADS
2023 static int net_ads_search(struct net_context *c, int argc, const char **argv)
2025 ADS_STRUCT *ads;
2026 ADS_STATUS rc;
2027 const char *ldap_exp;
2028 const char **attrs;
2029 LDAPMessage *res = NULL;
2031 if (argc < 1 || c->display_usage) {
2032 return net_ads_search_usage(c, argc, argv);
2035 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2036 return -1;
2039 ldap_exp = argv[0];
2040 attrs = (argv + 1);
2042 rc = ads_do_search_all(ads, ads->config.bind_path,
2043 LDAP_SCOPE_SUBTREE,
2044 ldap_exp, attrs, &res);
2045 if (!ADS_ERR_OK(rc)) {
2046 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2047 ads_destroy(&ads);
2048 return -1;
2051 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2053 /* dump the results */
2054 ads_dump(ads, res);
2056 ads_msgfree(ads, res);
2057 ads_destroy(&ads);
2059 return 0;
2064 help for net ads search
2066 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2068 d_printf(_(
2069 "\nnet ads dn <dn> <attributes...>\n"
2070 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2071 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2072 "to show in the results\n\n"
2073 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2074 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2076 net_common_flags_usage(c, argc, argv);
2077 return -1;
2082 general ADS search function. Useful in diagnosing problems in ADS
2084 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2086 ADS_STRUCT *ads;
2087 ADS_STATUS rc;
2088 const char *dn;
2089 const char **attrs;
2090 LDAPMessage *res = NULL;
2092 if (argc < 1 || c->display_usage) {
2093 return net_ads_dn_usage(c, argc, argv);
2096 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2097 return -1;
2100 dn = argv[0];
2101 attrs = (argv + 1);
2103 rc = ads_do_search_all(ads, dn,
2104 LDAP_SCOPE_BASE,
2105 "(objectclass=*)", attrs, &res);
2106 if (!ADS_ERR_OK(rc)) {
2107 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2108 ads_destroy(&ads);
2109 return -1;
2112 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2114 /* dump the results */
2115 ads_dump(ads, res);
2117 ads_msgfree(ads, res);
2118 ads_destroy(&ads);
2120 return 0;
2124 help for net ads sid search
2126 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2128 d_printf(_(
2129 "\nnet ads sid <sid> <attributes...>\n"
2130 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2131 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2132 "to show in the results\n\n"
2133 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2135 net_common_flags_usage(c, argc, argv);
2136 return -1;
2141 general ADS search function. Useful in diagnosing problems in ADS
2143 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2145 ADS_STRUCT *ads;
2146 ADS_STATUS rc;
2147 const char *sid_string;
2148 const char **attrs;
2149 LDAPMessage *res = NULL;
2150 DOM_SID sid;
2152 if (argc < 1 || c->display_usage) {
2153 return net_ads_sid_usage(c, argc, argv);
2156 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2157 return -1;
2160 sid_string = argv[0];
2161 attrs = (argv + 1);
2163 if (!string_to_sid(&sid, sid_string)) {
2164 d_fprintf(stderr, _("could not convert sid\n"));
2165 ads_destroy(&ads);
2166 return -1;
2169 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2170 if (!ADS_ERR_OK(rc)) {
2171 d_fprintf(stderr, _("search failed: %s\n"), ads_errstr(rc));
2172 ads_destroy(&ads);
2173 return -1;
2176 d_printf(_("Got %d replies\n\n"), ads_count_replies(ads, res));
2178 /* dump the results */
2179 ads_dump(ads, res);
2181 ads_msgfree(ads, res);
2182 ads_destroy(&ads);
2184 return 0;
2187 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2189 int ret;
2190 ADS_STRUCT *ads;
2192 if (c->display_usage) {
2193 d_printf(_("Usage:\n"
2194 "net ads keytab flush\n"
2195 " Delete the whole keytab\n"));
2196 return 0;
2199 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2200 return -1;
2202 ret = ads_keytab_flush(ads);
2203 ads_destroy(&ads);
2204 return ret;
2207 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2209 int i;
2210 int ret = 0;
2211 ADS_STRUCT *ads;
2213 if (c->display_usage) {
2214 d_printf(_("Usage:\n"
2215 "net ads keytab add <principal> [principal ...]\n"
2216 " Add principals to local keytab\n"
2217 " principal\tKerberos principal to add to "
2218 "keytab\n"));
2219 return 0;
2222 d_printf(_("Processing principals to add...\n"));
2223 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2224 return -1;
2226 for (i = 0; i < argc; i++) {
2227 ret |= ads_keytab_add_entry(ads, argv[i]);
2229 ads_destroy(&ads);
2230 return ret;
2233 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2235 ADS_STRUCT *ads;
2236 int ret;
2238 if (c->display_usage) {
2239 d_printf(_("Usage:\n"
2240 "net ads keytab create\n"
2241 " Create new default keytab\n"));
2242 return 0;
2245 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2246 return -1;
2248 ret = ads_keytab_create_default(ads);
2249 ads_destroy(&ads);
2250 return ret;
2253 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2255 const char *keytab = NULL;
2257 if (c->display_usage) {
2258 d_printf(_("Usage:\n"
2259 "net ads keytab list [keytab]\n"
2260 " List a local keytab\n"
2261 " keytab\tKeytab to list\n"));
2262 return 0;
2265 if (argc >= 1) {
2266 keytab = argv[0];
2269 return ads_keytab_list(keytab);
2273 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2275 struct functable func[] = {
2277 "add",
2278 net_ads_keytab_add,
2279 NET_TRANSPORT_ADS,
2280 N_("Add a service principal"),
2281 N_("net ads keytab add\n"
2282 " Add a service principal")
2285 "create",
2286 net_ads_keytab_create,
2287 NET_TRANSPORT_ADS,
2288 N_("Create a fresh keytab"),
2289 N_("net ads keytab create\n"
2290 " Create a fresh keytab")
2293 "flush",
2294 net_ads_keytab_flush,
2295 NET_TRANSPORT_ADS,
2296 N_("Remove all keytab entries"),
2297 N_("net ads keytab flush\n"
2298 " Remove all keytab entries")
2301 "list",
2302 net_ads_keytab_list,
2303 NET_TRANSPORT_ADS,
2304 N_("List a keytab"),
2305 N_("net ads keytab list\n"
2306 " List a keytab")
2308 {NULL, NULL, 0, NULL, NULL}
2311 if (!USE_KERBEROS_KEYTAB) {
2312 d_printf(_("\nWarning: \"kerberos method\" must be set to a "
2313 "keytab method to use keytab functions.\n"));
2316 return net_run_function(c, argc, argv, "net ads keytab", func);
2319 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2321 int ret = -1;
2323 if (c->display_usage) {
2324 d_printf(_("Usage:\n"
2325 "net ads kerberos renew\n"
2326 " Renew TGT from existing credential cache\n"));
2327 return 0;
2330 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2331 if (ret) {
2332 d_printf(_("failed to renew kerberos ticket: %s\n"),
2333 error_message(ret));
2335 return ret;
2338 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2340 struct PAC_DATA *pac = NULL;
2341 struct PAC_LOGON_INFO *info = NULL;
2342 TALLOC_CTX *mem_ctx = NULL;
2343 NTSTATUS status;
2344 int ret = -1;
2346 if (c->display_usage) {
2347 d_printf(_("Usage:\n"
2348 "net ads kerberos pac\n"
2349 " Dump the Kerberos PAC\n"));
2350 return 0;
2353 mem_ctx = talloc_init("net_ads_kerberos_pac");
2354 if (!mem_ctx) {
2355 goto out;
2358 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2360 status = kerberos_return_pac(mem_ctx,
2361 c->opt_user_name,
2362 c->opt_password,
2364 NULL,
2365 NULL,
2366 NULL,
2367 true,
2368 true,
2369 2592000, /* one month */
2370 &pac);
2371 if (!NT_STATUS_IS_OK(status)) {
2372 d_printf(_("failed to query kerberos PAC: %s\n"),
2373 nt_errstr(status));
2374 goto out;
2377 info = get_logon_info_from_pac(pac);
2378 if (info) {
2379 const char *s;
2380 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2381 d_printf(_("The Pac: %s\n"), s);
2384 ret = 0;
2385 out:
2386 TALLOC_FREE(mem_ctx);
2387 return ret;
2390 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2392 TALLOC_CTX *mem_ctx = NULL;
2393 int ret = -1;
2394 NTSTATUS status;
2396 if (c->display_usage) {
2397 d_printf(_("Usage:\n"
2398 "net ads kerberos kinit\n"
2399 " Get Ticket Granting Ticket (TGT) for the user\n"));
2400 return 0;
2403 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2404 if (!mem_ctx) {
2405 goto out;
2408 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2410 ret = kerberos_kinit_password_ext(c->opt_user_name,
2411 c->opt_password,
2413 NULL,
2414 NULL,
2415 NULL,
2416 true,
2417 true,
2418 2592000, /* one month */
2419 &status);
2420 if (ret) {
2421 d_printf(_("failed to kinit password: %s\n"),
2422 nt_errstr(status));
2424 out:
2425 return ret;
2428 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2430 struct functable func[] = {
2432 "kinit",
2433 net_ads_kerberos_kinit,
2434 NET_TRANSPORT_ADS,
2435 N_("Retrieve Ticket Granting Ticket (TGT)"),
2436 N_("net ads kerberos kinit\n"
2437 " Receive Ticket Granting Ticket (TGT)")
2440 "renew",
2441 net_ads_kerberos_renew,
2442 NET_TRANSPORT_ADS,
2443 N_("Renew Ticket Granting Ticket from credential cache"),
2444 N_("net ads kerberos renew\n"
2445 " Renew Ticket Granting Ticket (TGT) from "
2446 "credential cache")
2449 "pac",
2450 net_ads_kerberos_pac,
2451 NET_TRANSPORT_ADS,
2452 N_("Dump Kerberos PAC"),
2453 N_("net ads kerberos pac\n"
2454 " Dump Kerberos PAC")
2456 {NULL, NULL, 0, NULL, NULL}
2459 return net_run_function(c, argc, argv, "net ads kerberos", func);
2462 int net_ads(struct net_context *c, int argc, const char **argv)
2464 struct functable func[] = {
2466 "info",
2467 net_ads_info,
2468 NET_TRANSPORT_ADS,
2469 N_("Display details on remote ADS server"),
2470 N_("net ads info\n"
2471 " Display details on remote ADS server")
2474 "join",
2475 net_ads_join,
2476 NET_TRANSPORT_ADS,
2477 N_("Join the local machine to ADS realm"),
2478 N_("net ads join\n"
2479 " Join the local machine to ADS realm")
2482 "testjoin",
2483 net_ads_testjoin,
2484 NET_TRANSPORT_ADS,
2485 N_("Validate machine account"),
2486 N_("net ads testjoin\n"
2487 " Validate machine account")
2490 "leave",
2491 net_ads_leave,
2492 NET_TRANSPORT_ADS,
2493 N_("Remove the local machine from ADS"),
2494 N_("net ads leave\n"
2495 " Remove the local machine from ADS")
2498 "status",
2499 net_ads_status,
2500 NET_TRANSPORT_ADS,
2501 N_("Display machine account details"),
2502 N_("net ads status\n"
2503 " Display machine account details")
2506 "user",
2507 net_ads_user,
2508 NET_TRANSPORT_ADS,
2509 N_("List/modify users"),
2510 N_("net ads user\n"
2511 " List/modify users")
2514 "group",
2515 net_ads_group,
2516 NET_TRANSPORT_ADS,
2517 N_("List/modify groups"),
2518 N_("net ads group\n"
2519 " List/modify groups")
2522 "dns",
2523 net_ads_dns,
2524 NET_TRANSPORT_ADS,
2525 N_("Issue dynamic DNS update"),
2526 N_("net ads dns\n"
2527 " Issue dynamic DNS update")
2530 "password",
2531 net_ads_password,
2532 NET_TRANSPORT_ADS,
2533 N_("Change user passwords"),
2534 N_("net ads password\n"
2535 " Change user passwords")
2538 "changetrustpw",
2539 net_ads_changetrustpw,
2540 NET_TRANSPORT_ADS,
2541 N_("Change trust account password"),
2542 N_("net ads changetrustpw\n"
2543 " Change trust account password")
2546 "printer",
2547 net_ads_printer,
2548 NET_TRANSPORT_ADS,
2549 N_("List/modify printer entries"),
2550 N_("net ads printer\n"
2551 " List/modify printer entries")
2554 "search",
2555 net_ads_search,
2556 NET_TRANSPORT_ADS,
2557 N_("Issue LDAP search using filter"),
2558 N_("net ads search\n"
2559 " Issue LDAP search using filter")
2562 "dn",
2563 net_ads_dn,
2564 NET_TRANSPORT_ADS,
2565 N_("Issue LDAP search by DN"),
2566 N_("net ads dn\n"
2567 " Issue LDAP search by DN")
2570 "sid",
2571 net_ads_sid,
2572 NET_TRANSPORT_ADS,
2573 N_("Issue LDAP search by SID"),
2574 N_("net ads sid\n"
2575 " Issue LDAP search by SID")
2578 "workgroup",
2579 net_ads_workgroup,
2580 NET_TRANSPORT_ADS,
2581 N_("Display workgroup name"),
2582 N_("net ads workgroup\n"
2583 " Display the workgroup name")
2586 "lookup",
2587 net_ads_lookup,
2588 NET_TRANSPORT_ADS,
2589 N_("Perfom CLDAP query on DC"),
2590 N_("net ads lookup\n"
2591 " Find the ADS DC using CLDAP lookups")
2594 "keytab",
2595 net_ads_keytab,
2596 NET_TRANSPORT_ADS,
2597 N_("Manage local keytab file"),
2598 N_("net ads keytab\n"
2599 " Manage local keytab file")
2602 "gpo",
2603 net_ads_gpo,
2604 NET_TRANSPORT_ADS,
2605 N_("Manage group policy objects"),
2606 N_("net ads gpo\n"
2607 " Manage group policy objects")
2610 "kerberos",
2611 net_ads_kerberos,
2612 NET_TRANSPORT_ADS,
2613 N_("Manage kerberos keytab"),
2614 N_("net ads kerberos\n"
2615 " Manage kerberos keytab")
2617 {NULL, NULL, 0, NULL, NULL}
2620 return net_run_function(c, argc, argv, "net ads", func);
2623 #else
2625 static int net_ads_noads(void)
2627 d_fprintf(stderr, _("ADS support not compiled in\n"));
2628 return -1;
2631 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2633 return net_ads_noads();
2636 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2638 return net_ads_noads();
2641 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2643 return net_ads_noads();
2646 int net_ads_join(struct net_context *c, int argc, const char **argv)
2648 return net_ads_noads();
2651 int net_ads_user(struct net_context *c, int argc, const char **argv)
2653 return net_ads_noads();
2656 int net_ads_group(struct net_context *c, int argc, const char **argv)
2658 return net_ads_noads();
2661 /* this one shouldn't display a message */
2662 int net_ads_check(struct net_context *c)
2664 return -1;
2667 int net_ads_check_our_domain(struct net_context *c)
2669 return -1;
2672 int net_ads(struct net_context *c, int argc, const char **argv)
2674 return net_ads_noads();
2677 #endif /* WITH_ADS */