s3:libads Make ads_get_dn() take a talloc context
[Samba.git] / source3 / utils / net_ads.c
blob8ff0cdfcf428f8ea31590001887a53f1af94ce43
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"
27 #ifdef HAVE_ADS
29 /* when we do not have sufficient input parameters to contact a remote domain
30 * we always fall back to our own realm - Guenther*/
32 static const char *assume_own_realm(struct net_context *c)
34 if (!c->opt_host && strequal(lp_workgroup(), c->opt_target_workgroup)) {
35 return lp_realm();
38 return NULL;
42 do a cldap netlogon query
44 static int net_ads_cldap_netlogon(struct net_context *c, ADS_STRUCT *ads)
46 char addr[INET6_ADDRSTRLEN];
47 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
49 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
50 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
51 d_fprintf(stderr, "CLDAP query failed!\n");
52 return -1;
55 d_printf("Information for Domain Controller: %s\n\n",
56 addr);
58 d_printf("Response Type: ");
59 switch (reply.command) {
60 case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
61 d_printf("LOGON_SAM_LOGON_USER_UNKNOWN_EX\n");
62 break;
63 case LOGON_SAM_LOGON_RESPONSE_EX:
64 d_printf("LOGON_SAM_LOGON_RESPONSE_EX\n");
65 break;
66 default:
67 d_printf("0x%x\n", reply.command);
68 break;
71 d_printf("GUID: %s\n", GUID_string(talloc_tos(), &reply.domain_uuid));
73 d_printf("Flags:\n"
74 "\tIs a PDC: %s\n"
75 "\tIs a GC of the forest: %s\n"
76 "\tIs an LDAP server: %s\n"
77 "\tSupports DS: %s\n"
78 "\tIs running a KDC: %s\n"
79 "\tIs running time services: %s\n"
80 "\tIs the closest DC: %s\n"
81 "\tIs writable: %s\n"
82 "\tHas a hardware clock: %s\n"
83 "\tIs a non-domain NC serviced by LDAP server: %s\n"
84 "\tIs NT6 DC that has some secrets: %s\n"
85 "\tIs NT6 DC that has all secrets: %s\n",
86 (reply.server_type & NBT_SERVER_PDC) ? "yes" : "no",
87 (reply.server_type & NBT_SERVER_GC) ? "yes" : "no",
88 (reply.server_type & NBT_SERVER_LDAP) ? "yes" : "no",
89 (reply.server_type & NBT_SERVER_DS) ? "yes" : "no",
90 (reply.server_type & NBT_SERVER_KDC) ? "yes" : "no",
91 (reply.server_type & NBT_SERVER_TIMESERV) ? "yes" : "no",
92 (reply.server_type & NBT_SERVER_CLOSEST) ? "yes" : "no",
93 (reply.server_type & NBT_SERVER_WRITABLE) ? "yes" : "no",
94 (reply.server_type & NBT_SERVER_GOOD_TIMESERV) ? "yes" : "no",
95 (reply.server_type & NBT_SERVER_NDNC) ? "yes" : "no",
96 (reply.server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) ? "yes" : "no",
97 (reply.server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) ? "yes" : "no");
100 printf("Forest:\t\t\t%s\n", reply.forest);
101 printf("Domain:\t\t\t%s\n", reply.dns_domain);
102 printf("Domain Controller:\t%s\n", reply.pdc_dns_name);
104 printf("Pre-Win2k Domain:\t%s\n", reply.domain);
105 printf("Pre-Win2k Hostname:\t%s\n", reply.pdc_name);
107 if (*reply.user_name) printf("User name:\t%s\n", reply.user_name);
109 printf("Server Site Name :\t\t%s\n", reply.server_site);
110 printf("Client Site Name :\t\t%s\n", reply.client_site);
112 d_printf("NT Version: %d\n", reply.nt_version);
113 d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
114 d_printf("LM20 Token: %.2x\n", reply.lm20_token);
116 return 0;
120 this implements the CLDAP based netlogon lookup requests
121 for finding the domain controller of a ADS domain
123 static int net_ads_lookup(struct net_context *c, int argc, const char **argv)
125 ADS_STRUCT *ads;
126 int ret;
128 if (c->display_usage) {
129 d_printf("Usage:\n"
130 "net ads lookup\n"
131 " Find the ADS DC using CLDAP lookup.\n");
132 return 0;
135 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
136 d_fprintf(stderr, "Didn't find the cldap server!\n");
137 ads_destroy(&ads);
138 return -1;
141 if (!ads->config.realm) {
142 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
143 ads->ldap.port = 389;
146 ret = net_ads_cldap_netlogon(c, ads);
147 ads_destroy(&ads);
148 return ret;
153 static int net_ads_info(struct net_context *c, int argc, const char **argv)
155 ADS_STRUCT *ads;
156 char addr[INET6_ADDRSTRLEN];
158 if (c->display_usage) {
159 d_printf("Usage:\n"
160 "net ads info\n"
161 " Display information about an Active Directory "
162 "server.\n");
163 return 0;
166 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
167 d_fprintf(stderr, "Didn't find the ldap server!\n");
168 return -1;
171 if (!ads || !ads->config.realm) {
172 d_fprintf(stderr, "Didn't find the ldap server!\n");
173 ads_destroy(&ads);
174 return -1;
177 /* Try to set the server's current time since we didn't do a full
178 TCP LDAP session initially */
180 if ( !ADS_ERR_OK(ads_current_time( ads )) ) {
181 d_fprintf( stderr, "Failed to get server's current time!\n");
184 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
186 d_printf("LDAP server: %s\n", addr);
187 d_printf("LDAP server name: %s\n", ads->config.ldap_server_name);
188 d_printf("Realm: %s\n", ads->config.realm);
189 d_printf("Bind Path: %s\n", ads->config.bind_path);
190 d_printf("LDAP port: %d\n", ads->ldap.port);
191 d_printf("Server time: %s\n",
192 http_timestring(talloc_tos(), ads->config.current_time));
194 d_printf("KDC server: %s\n", ads->auth.kdc_server );
195 d_printf("Server time offset: %d\n", ads->auth.time_offset );
197 ads_destroy(&ads);
198 return 0;
201 static void use_in_memory_ccache(void) {
202 /* Use in-memory credentials cache so we do not interfere with
203 * existing credentials */
204 setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1);
207 static ADS_STATUS ads_startup_int(struct net_context *c, bool only_own_domain,
208 uint32 auth_flags, ADS_STRUCT **ads_ret)
210 ADS_STRUCT *ads = NULL;
211 ADS_STATUS status;
212 bool need_password = false;
213 bool second_time = false;
214 char *cp;
215 const char *realm = NULL;
216 bool tried_closest_dc = false;
218 /* lp_realm() should be handled by a command line param,
219 However, the join requires that realm be set in smb.conf
220 and compares our realm with the remote server's so this is
221 ok until someone needs more flexibility */
223 *ads_ret = NULL;
225 retry_connect:
226 if (only_own_domain) {
227 realm = lp_realm();
228 } else {
229 realm = assume_own_realm(c);
232 ads = ads_init(realm, c->opt_target_workgroup, c->opt_host);
234 if (!c->opt_user_name) {
235 c->opt_user_name = "administrator";
238 if (c->opt_user_specified) {
239 need_password = true;
242 retry:
243 if (!c->opt_password && need_password && !c->opt_machine_pass) {
244 c->opt_password = net_prompt_pass(c, c->opt_user_name);
245 if (!c->opt_password) {
246 ads_destroy(&ads);
247 return ADS_ERROR(LDAP_NO_MEMORY);
251 if (c->opt_password) {
252 use_in_memory_ccache();
253 SAFE_FREE(ads->auth.password);
254 ads->auth.password = smb_xstrdup(c->opt_password);
257 ads->auth.flags |= auth_flags;
258 SAFE_FREE(ads->auth.user_name);
259 ads->auth.user_name = smb_xstrdup(c->opt_user_name);
262 * If the username is of the form "name@realm",
263 * extract the realm and convert to upper case.
264 * This is only used to establish the connection.
266 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
267 *cp++ = '\0';
268 SAFE_FREE(ads->auth.realm);
269 ads->auth.realm = smb_xstrdup(cp);
270 strupper_m(ads->auth.realm);
273 status = ads_connect(ads);
275 if (!ADS_ERR_OK(status)) {
277 if (NT_STATUS_EQUAL(ads_ntstatus(status),
278 NT_STATUS_NO_LOGON_SERVERS)) {
279 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
280 ads_destroy(&ads);
281 return status;
284 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
285 need_password = true;
286 second_time = true;
287 goto retry;
288 } else {
289 ads_destroy(&ads);
290 return status;
294 /* when contacting our own domain, make sure we use the closest DC.
295 * This is done by reconnecting to ADS because only the first call to
296 * ads_connect will give us our own sitename */
298 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
300 tried_closest_dc = true; /* avoid loop */
302 if (!ads_closest_dc(ads)) {
304 namecache_delete(ads->server.realm, 0x1C);
305 namecache_delete(ads->server.workgroup, 0x1C);
307 ads_destroy(&ads);
308 ads = NULL;
310 goto retry_connect;
314 *ads_ret = ads;
315 return status;
318 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
320 return ads_startup_int(c, only_own_domain, 0, ads);
323 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
325 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
329 Check to see if connection can be made via ads.
330 ads_startup() stores the password in opt_password if it needs to so
331 that rpc or rap can use it without re-prompting.
333 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
335 ADS_STRUCT *ads;
336 ADS_STATUS status;
338 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
339 return -1;
342 ads->auth.flags |= ADS_AUTH_NO_BIND;
344 status = ads_connect(ads);
345 if ( !ADS_ERR_OK(status) ) {
346 return -1;
349 ads_destroy(&ads);
350 return 0;
353 int net_ads_check_our_domain(struct net_context *c)
355 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
358 int net_ads_check(struct net_context *c)
360 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
364 determine the netbios workgroup name for a domain
366 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
368 ADS_STRUCT *ads;
369 char addr[INET6_ADDRSTRLEN];
370 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
372 if (c->display_usage) {
373 d_printf("Usage:\n"
374 "net ads workgroup\n"
375 " Print the workgroup name\n");
376 return 0;
379 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
380 d_fprintf(stderr, "Didn't find the cldap server!\n");
381 return -1;
384 if (!ads->config.realm) {
385 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
386 ads->ldap.port = 389;
389 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
390 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
391 d_fprintf(stderr, "CLDAP query failed!\n");
392 ads_destroy(&ads);
393 return -1;
396 d_printf("Workgroup: %s\n", reply.domain);
398 ads_destroy(&ads);
400 return 0;
405 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
407 char **disp_fields = (char **) data_area;
409 if (!field) { /* must be end of record */
410 if (disp_fields[0]) {
411 if (!strchr_m(disp_fields[0], '$')) {
412 if (disp_fields[1])
413 d_printf("%-21.21s %s\n",
414 disp_fields[0], disp_fields[1]);
415 else
416 d_printf("%s\n", disp_fields[0]);
419 SAFE_FREE(disp_fields[0]);
420 SAFE_FREE(disp_fields[1]);
421 return true;
423 if (!values) /* must be new field, indicate string field */
424 return true;
425 if (StrCaseCmp(field, "sAMAccountName") == 0) {
426 disp_fields[0] = SMB_STRDUP((char *) values[0]);
428 if (StrCaseCmp(field, "description") == 0)
429 disp_fields[1] = SMB_STRDUP((char *) values[0]);
430 return true;
433 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
435 return net_user_usage(c, argc, argv);
438 static int ads_user_add(struct net_context *c, int argc, const char **argv)
440 ADS_STRUCT *ads;
441 ADS_STATUS status;
442 char *upn, *userdn;
443 LDAPMessage *res=NULL;
444 int rc = -1;
445 char *ou_str = NULL;
447 if (argc < 1 || c->display_usage)
448 return net_ads_user_usage(c, argc, argv);
450 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
451 return -1;
454 status = ads_find_user_acct(ads, &res, argv[0]);
456 if (!ADS_ERR_OK(status)) {
457 d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
458 goto done;
461 if (ads_count_replies(ads, res)) {
462 d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
463 goto done;
466 if (c->opt_container) {
467 ou_str = SMB_STRDUP(c->opt_container);
468 } else {
469 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
472 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
474 if (!ADS_ERR_OK(status)) {
475 d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
476 ads_errstr(status));
477 goto done;
480 /* if no password is to be set, we're done */
481 if (argc == 1) {
482 d_printf("User %s added\n", argv[0]);
483 rc = 0;
484 goto done;
487 /* try setting the password */
488 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
489 goto done;
491 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
492 ads->auth.time_offset);
493 SAFE_FREE(upn);
494 if (ADS_ERR_OK(status)) {
495 d_printf("User %s added\n", argv[0]);
496 rc = 0;
497 goto done;
500 /* password didn't set, delete account */
501 d_fprintf(stderr, "Could not add user %s. Error setting password %s\n",
502 argv[0], ads_errstr(status));
503 ads_msgfree(ads, res);
504 status=ads_find_user_acct(ads, &res, argv[0]);
505 if (ADS_ERR_OK(status)) {
506 userdn = ads_get_dn(ads, NULL, res);
507 ads_del_dn(ads, userdn);
508 TALLOC_FREE(userdn);
511 done:
512 if (res)
513 ads_msgfree(ads, res);
514 ads_destroy(&ads);
515 SAFE_FREE(ou_str);
516 return rc;
519 static int ads_user_info(struct net_context *c, int argc, const char **argv)
521 ADS_STRUCT *ads;
522 ADS_STATUS rc;
523 LDAPMessage *res;
524 const char *attrs[] = {"memberOf", NULL};
525 char *searchstring=NULL;
526 char **grouplist;
527 char *escaped_user;
529 if (argc < 1 || c->display_usage) {
530 return net_ads_user_usage(c, argc, argv);
533 escaped_user = escape_ldap_string_alloc(argv[0]);
535 if (!escaped_user) {
536 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
537 return -1;
540 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
541 SAFE_FREE(escaped_user);
542 return -1;
545 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
546 SAFE_FREE(escaped_user);
547 return -1;
549 rc = ads_search(ads, &res, searchstring, attrs);
550 SAFE_FREE(searchstring);
552 if (!ADS_ERR_OK(rc)) {
553 d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
554 ads_destroy(&ads);
555 SAFE_FREE(escaped_user);
556 return -1;
559 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
560 (LDAPMessage *)res, "memberOf");
562 if (grouplist) {
563 int i;
564 char **groupname;
565 for (i=0;grouplist[i];i++) {
566 groupname = ldap_explode_dn(grouplist[i], 1);
567 d_printf("%s\n", groupname[0]);
568 ldap_value_free(groupname);
570 ldap_value_free(grouplist);
573 ads_msgfree(ads, res);
574 ads_destroy(&ads);
575 SAFE_FREE(escaped_user);
576 return 0;
579 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
581 ADS_STRUCT *ads;
582 ADS_STATUS rc;
583 LDAPMessage *res = NULL;
584 char *userdn;
586 if (argc < 1) {
587 return net_ads_user_usage(c, argc, argv);
590 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
591 return -1;
594 rc = ads_find_user_acct(ads, &res, argv[0]);
595 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
596 d_printf("User %s does not exist.\n", argv[0]);
597 ads_msgfree(ads, res);
598 ads_destroy(&ads);
599 return -1;
601 userdn = ads_get_dn(ads, NULL, res);
602 ads_msgfree(ads, res);
603 rc = ads_del_dn(ads, userdn);
604 TALLOC_FREE(userdn);
605 if (ADS_ERR_OK(rc)) {
606 d_printf("User %s deleted\n", argv[0]);
607 ads_destroy(&ads);
608 return 0;
610 d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
611 ads_errstr(rc));
612 ads_destroy(&ads);
613 return -1;
616 int net_ads_user(struct net_context *c, int argc, const char **argv)
618 struct functable func[] = {
620 "add",
621 ads_user_add,
622 NET_TRANSPORT_ADS,
623 "Add an AD user",
624 "net ads user add\n"
625 " Add an AD user"
628 "info",
629 ads_user_info,
630 NET_TRANSPORT_ADS,
631 "Display information about an AD user",
632 "net ads user info\n"
633 " Display information about an AD user"
636 "delete",
637 ads_user_delete,
638 NET_TRANSPORT_ADS,
639 "Delete an AD user",
640 "net ads user delete\n"
641 " Delete an AD user"
643 {NULL, NULL, 0, NULL, NULL}
645 ADS_STRUCT *ads;
646 ADS_STATUS rc;
647 const char *shortattrs[] = {"sAMAccountName", NULL};
648 const char *longattrs[] = {"sAMAccountName", "description", NULL};
649 char *disp_fields[2] = {NULL, NULL};
651 if (argc == 0) {
652 if (c->display_usage) {
653 d_printf("Usage:\n");
654 d_printf("net ads user\n"
655 " List AD users\n");
656 net_display_usage_from_functable(func);
657 return 0;
660 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
661 return -1;
664 if (c->opt_long_list_entries)
665 d_printf("\nUser name Comment"
666 "\n-----------------------------\n");
668 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
669 LDAP_SCOPE_SUBTREE,
670 "(objectCategory=user)",
671 c->opt_long_list_entries ? longattrs :
672 shortattrs, usergrp_display,
673 disp_fields);
674 ads_destroy(&ads);
675 return ADS_ERR_OK(rc) ? 0 : -1;
678 return net_run_function(c, argc, argv, "net ads user", func);
681 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
683 return net_group_usage(c, argc, argv);
686 static int ads_group_add(struct net_context *c, int argc, const char **argv)
688 ADS_STRUCT *ads;
689 ADS_STATUS status;
690 LDAPMessage *res=NULL;
691 int rc = -1;
692 char *ou_str = NULL;
694 if (argc < 1 || c->display_usage) {
695 return net_ads_group_usage(c, argc, argv);
698 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
699 return -1;
702 status = ads_find_user_acct(ads, &res, argv[0]);
704 if (!ADS_ERR_OK(status)) {
705 d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
706 goto done;
709 if (ads_count_replies(ads, res)) {
710 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
711 goto done;
714 if (c->opt_container) {
715 ou_str = SMB_STRDUP(c->opt_container);
716 } else {
717 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
720 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
722 if (ADS_ERR_OK(status)) {
723 d_printf("Group %s added\n", argv[0]);
724 rc = 0;
725 } else {
726 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
727 ads_errstr(status));
730 done:
731 if (res)
732 ads_msgfree(ads, res);
733 ads_destroy(&ads);
734 SAFE_FREE(ou_str);
735 return rc;
738 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
740 ADS_STRUCT *ads;
741 ADS_STATUS rc;
742 LDAPMessage *res = NULL;
743 char *groupdn;
745 if (argc < 1 || c->display_usage) {
746 return net_ads_group_usage(c, argc, argv);
749 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
750 return -1;
753 rc = ads_find_user_acct(ads, &res, argv[0]);
754 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
755 d_printf("Group %s does not exist.\n", argv[0]);
756 ads_msgfree(ads, res);
757 ads_destroy(&ads);
758 return -1;
760 groupdn = ads_get_dn(ads, NULL, res);
761 ads_msgfree(ads, res);
762 rc = ads_del_dn(ads, groupdn);
763 TALLOC_FREE(groupdn);
764 if (ADS_ERR_OK(rc)) {
765 d_printf("Group %s deleted\n", argv[0]);
766 ads_destroy(&ads);
767 return 0;
769 d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
770 ads_errstr(rc));
771 ads_destroy(&ads);
772 return -1;
775 int net_ads_group(struct net_context *c, int argc, const char **argv)
777 struct functable func[] = {
779 "add",
780 ads_group_add,
781 NET_TRANSPORT_ADS,
782 "Add an AD group",
783 "net ads group add\n"
784 " Add an AD group"
787 "delete",
788 ads_group_delete,
789 NET_TRANSPORT_ADS,
790 "Delete an AD group",
791 "net ads group delete\n"
792 " Delete an AD group"
794 {NULL, NULL, 0, NULL, NULL}
796 ADS_STRUCT *ads;
797 ADS_STATUS rc;
798 const char *shortattrs[] = {"sAMAccountName", NULL};
799 const char *longattrs[] = {"sAMAccountName", "description", NULL};
800 char *disp_fields[2] = {NULL, NULL};
802 if (argc == 0) {
803 if (c->display_usage) {
804 d_printf("Usage:\n");
805 d_printf("net ads group\n"
806 " List AD groups\n");
807 net_display_usage_from_functable(func);
808 return 0;
811 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
812 return -1;
815 if (c->opt_long_list_entries)
816 d_printf("\nGroup name Comment"
817 "\n-----------------------------\n");
818 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
819 LDAP_SCOPE_SUBTREE,
820 "(objectCategory=group)",
821 c->opt_long_list_entries ? longattrs :
822 shortattrs, usergrp_display,
823 disp_fields);
825 ads_destroy(&ads);
826 return ADS_ERR_OK(rc) ? 0 : -1;
828 return net_run_function(c, argc, argv, "net ads group", func);
831 static int net_ads_status(struct net_context *c, int argc, const char **argv)
833 ADS_STRUCT *ads;
834 ADS_STATUS rc;
835 LDAPMessage *res;
837 if (c->display_usage) {
838 d_printf("Usage:\n"
839 "net ads status\n"
840 " Display machine account details\n");
841 return 0;
844 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
845 return -1;
848 rc = ads_find_machine_acct(ads, &res, global_myname());
849 if (!ADS_ERR_OK(rc)) {
850 d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
851 ads_destroy(&ads);
852 return -1;
855 if (ads_count_replies(ads, res) == 0) {
856 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
857 ads_destroy(&ads);
858 return -1;
861 ads_dump(ads, res);
862 ads_destroy(&ads);
863 return 0;
866 /*******************************************************************
867 Leave an AD domain. Windows XP disables the machine account.
868 We'll try the same. The old code would do an LDAP delete.
869 That only worked using the machine creds because added the machine
870 with full control to the computer object's ACL.
871 *******************************************************************/
873 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
875 TALLOC_CTX *ctx;
876 struct libnet_UnjoinCtx *r = NULL;
877 WERROR werr;
879 if (c->display_usage) {
880 d_printf("Usage:\n"
881 "net ads leave\n"
882 " Leave an AD domain\n");
883 return 0;
886 if (!*lp_realm()) {
887 d_fprintf(stderr, "No realm set, are we joined ?\n");
888 return -1;
891 if (!(ctx = talloc_init("net_ads_leave"))) {
892 d_fprintf(stderr, "Could not initialise talloc context.\n");
893 return -1;
896 if (!c->opt_kerberos) {
897 use_in_memory_ccache();
900 werr = libnet_init_UnjoinCtx(ctx, &r);
901 if (!W_ERROR_IS_OK(werr)) {
902 d_fprintf(stderr, "Could not initialise unjoin context.\n");
903 return -1;
906 r->in.debug = true;
907 r->in.use_kerberos = c->opt_kerberos;
908 r->in.dc_name = c->opt_host;
909 r->in.domain_name = lp_realm();
910 r->in.admin_account = c->opt_user_name;
911 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
912 r->in.modify_config = lp_config_backend_is_registry();
913 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
914 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
916 werr = libnet_Unjoin(ctx, r);
917 if (!W_ERROR_IS_OK(werr)) {
918 d_printf("Failed to leave domain: %s\n",
919 r->out.error_string ? r->out.error_string :
920 get_friendly_werror_msg(werr));
921 goto done;
924 if (W_ERROR_IS_OK(werr)) {
925 d_printf("Deleted account for '%s' in realm '%s'\n",
926 r->in.machine_name, r->out.dns_domain_name);
927 goto done;
930 /* We couldn't delete it - see if the disable succeeded. */
931 if (r->out.disabled_machine_account) {
932 d_printf("Disabled account for '%s' in realm '%s'\n",
933 r->in.machine_name, r->out.dns_domain_name);
934 werr = WERR_OK;
935 goto done;
938 d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
939 r->in.machine_name, r->out.dns_domain_name);
941 done:
942 TALLOC_FREE(r);
943 TALLOC_FREE(ctx);
945 if (W_ERROR_IS_OK(werr)) {
946 return 0;
949 return -1;
952 static NTSTATUS net_ads_join_ok(struct net_context *c)
954 ADS_STRUCT *ads = NULL;
955 ADS_STATUS status;
957 if (!secrets_init()) {
958 DEBUG(1,("Failed to initialise secrets database\n"));
959 return NT_STATUS_ACCESS_DENIED;
962 net_use_krb_machine_account(c);
964 status = ads_startup(c, true, &ads);
965 if (!ADS_ERR_OK(status)) {
966 return ads_ntstatus(status);
969 ads_destroy(&ads);
970 return NT_STATUS_OK;
974 check that an existing join is OK
976 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
978 NTSTATUS status;
979 use_in_memory_ccache();
981 if (c->display_usage) {
982 d_printf("Usage:\n"
983 "net ads testjoin\n"
984 " Test if the existing join is ok\n");
985 return 0;
988 /* Display success or failure */
989 status = net_ads_join_ok(c);
990 if (!NT_STATUS_IS_OK(status)) {
991 fprintf(stderr,"Join to domain is not valid: %s\n",
992 get_friendly_nt_error_msg(status));
993 return -1;
996 printf("Join is OK\n");
997 return 0;
1000 /*******************************************************************
1001 Simple configu checks before beginning the join
1002 ********************************************************************/
1004 static WERROR check_ads_config( void )
1006 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1007 d_printf("Host is not configured as a member server.\n");
1008 return WERR_INVALID_DOMAIN_ROLE;
1011 if (strlen(global_myname()) > 15) {
1012 d_printf("Our netbios name can be at most 15 chars long, "
1013 "\"%s\" is %u chars long\n", global_myname(),
1014 (unsigned int)strlen(global_myname()));
1015 return WERR_INVALID_COMPUTERNAME;
1018 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1019 d_fprintf(stderr, "realm must be set in in %s for ADS "
1020 "join to succeed.\n", get_dyn_CONFIGFILE());
1021 return WERR_INVALID_PARAM;
1024 return WERR_OK;
1027 /*******************************************************************
1028 Send a DNS update request
1029 *******************************************************************/
1031 #if defined(WITH_DNS_UPDATES)
1032 #include "dns.h"
1033 DNS_ERROR DoDNSUpdate(char *pszServerName,
1034 const char *pszDomainName, const char *pszHostName,
1035 const struct sockaddr_storage *sslist,
1036 size_t num_addrs );
1038 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1039 const char *machine_name,
1040 const struct sockaddr_storage *addrs,
1041 int num_addrs)
1043 struct dns_rr_ns *nameservers = NULL;
1044 int ns_count = 0;
1045 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1046 DNS_ERROR dns_err;
1047 fstring dns_server;
1048 const char *dnsdomain = NULL;
1049 char *root_domain = NULL;
1051 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1052 d_printf("No DNS domain configured for %s. "
1053 "Unable to perform DNS Update.\n", machine_name);
1054 status = NT_STATUS_INVALID_PARAMETER;
1055 goto done;
1057 dnsdomain++;
1059 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1060 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1061 /* Child domains often do not have NS records. Look
1062 for the NS record for the forest root domain
1063 (rootDomainNamingContext in therootDSE) */
1065 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1066 LDAPMessage *msg = NULL;
1067 char *root_dn;
1068 ADS_STATUS ads_status;
1070 if ( !ads->ldap.ld ) {
1071 ads_status = ads_connect( ads );
1072 if ( !ADS_ERR_OK(ads_status) ) {
1073 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1074 goto done;
1078 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1079 "(objectclass=*)", rootname_attrs, &msg);
1080 if (!ADS_ERR_OK(ads_status)) {
1081 goto done;
1084 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1085 if ( !root_dn ) {
1086 ads_msgfree( ads, msg );
1087 goto done;
1090 root_domain = ads_build_domain( root_dn );
1092 /* cleanup */
1093 ads_msgfree( ads, msg );
1095 /* try again for NS servers */
1097 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1099 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1100 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1101 "realm\n", ads->config.realm));
1102 goto done;
1105 dnsdomain = root_domain;
1109 /* Now perform the dns update - we'll try non-secure and if we fail,
1110 we'll follow it up with a secure update */
1112 fstrcpy( dns_server, nameservers[0].hostname );
1114 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1115 if (!ERR_DNS_IS_OK(dns_err)) {
1116 status = NT_STATUS_UNSUCCESSFUL;
1119 done:
1121 SAFE_FREE( root_domain );
1123 return status;
1126 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1128 int num_addrs;
1129 struct sockaddr_storage *iplist = NULL;
1130 fstring machine_name;
1131 NTSTATUS status;
1133 name_to_fqdn( machine_name, global_myname() );
1134 strlower_m( machine_name );
1136 /* Get our ip address (not the 127.0.0.x address but a real ip
1137 * address) */
1139 num_addrs = get_my_ip_address( &iplist );
1140 if ( num_addrs <= 0 ) {
1141 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1142 "addresses!\n"));
1143 return NT_STATUS_INVALID_PARAMETER;
1146 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1147 iplist, num_addrs);
1148 SAFE_FREE( iplist );
1149 return status;
1151 #endif
1154 /*******************************************************************
1155 ********************************************************************/
1157 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1159 d_printf("net ads join [options]\n");
1160 d_printf("Valid options:\n");
1161 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1162 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1163 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1164 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1165 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1166 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1167 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1168 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1169 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1170 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1171 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1172 d_printf(" the two other attributes.\n");
1174 return -1;
1177 /*******************************************************************
1178 ********************************************************************/
1180 int net_ads_join(struct net_context *c, int argc, const char **argv)
1182 TALLOC_CTX *ctx = NULL;
1183 struct libnet_JoinCtx *r = NULL;
1184 const char *domain = lp_realm();
1185 WERROR werr = WERR_SETUP_NOT_JOINED;
1186 bool createupn = false;
1187 const char *machineupn = NULL;
1188 const char *create_in_ou = NULL;
1189 int i;
1190 const char *os_name = NULL;
1191 const char *os_version = NULL;
1192 bool modify_config = lp_config_backend_is_registry();
1194 if (c->display_usage)
1195 return net_ads_join_usage(c, argc, argv);
1197 if (!modify_config) {
1199 werr = check_ads_config();
1200 if (!W_ERROR_IS_OK(werr)) {
1201 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1202 goto fail;
1206 if (!(ctx = talloc_init("net_ads_join"))) {
1207 d_fprintf(stderr, "Could not initialise talloc context.\n");
1208 werr = WERR_NOMEM;
1209 goto fail;
1212 if (!c->opt_kerberos) {
1213 use_in_memory_ccache();
1216 werr = libnet_init_JoinCtx(ctx, &r);
1217 if (!W_ERROR_IS_OK(werr)) {
1218 goto fail;
1221 /* process additional command line args */
1223 for ( i=0; i<argc; i++ ) {
1224 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1225 createupn = true;
1226 machineupn = get_string_param(argv[i]);
1228 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1229 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1230 d_fprintf(stderr, "Please supply a valid OU path.\n");
1231 werr = WERR_INVALID_PARAM;
1232 goto fail;
1235 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1236 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1237 d_fprintf(stderr, "Please supply a operating system name.\n");
1238 werr = WERR_INVALID_PARAM;
1239 goto fail;
1242 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1243 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1244 d_fprintf(stderr, "Please supply a valid operating system version.\n");
1245 werr = WERR_INVALID_PARAM;
1246 goto fail;
1249 else {
1250 domain = argv[i];
1254 if (!*domain) {
1255 d_fprintf(stderr, "Please supply a valid domain name\n");
1256 werr = WERR_INVALID_PARAM;
1257 goto fail;
1260 /* Do the domain join here */
1262 r->in.domain_name = domain;
1263 r->in.create_upn = createupn;
1264 r->in.upn = machineupn;
1265 r->in.account_ou = create_in_ou;
1266 r->in.os_name = os_name;
1267 r->in.os_version = os_version;
1268 r->in.dc_name = c->opt_host;
1269 r->in.admin_account = c->opt_user_name;
1270 r->in.admin_password = net_prompt_pass(c, c->opt_user_name);
1271 r->in.debug = true;
1272 r->in.use_kerberos = c->opt_kerberos;
1273 r->in.modify_config = modify_config;
1274 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1275 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1276 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1278 werr = libnet_Join(ctx, r);
1279 if (!W_ERROR_IS_OK(werr)) {
1280 goto fail;
1283 /* Check the short name of the domain */
1285 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1286 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1287 d_printf("domain name obtained from the server.\n");
1288 d_printf("Using the name [%s] from the server.\n", r->out.netbios_domain_name);
1289 d_printf("You should set \"workgroup = %s\" in %s.\n",
1290 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1293 d_printf("Using short domain name -- %s\n", r->out.netbios_domain_name);
1295 if (r->out.dns_domain_name) {
1296 d_printf("Joined '%s' to realm '%s'\n", r->in.machine_name,
1297 r->out.dns_domain_name);
1298 } else {
1299 d_printf("Joined '%s' to domain '%s'\n", r->in.machine_name,
1300 r->out.netbios_domain_name);
1303 #if defined(WITH_DNS_UPDATES)
1304 if (r->out.domain_is_ad) {
1305 /* We enter this block with user creds */
1306 ADS_STRUCT *ads_dns = NULL;
1308 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1309 /* kinit with the machine password */
1311 use_in_memory_ccache();
1312 if (asprintf( &ads_dns->auth.user_name, "%s$", global_myname()) == -1) {
1313 goto fail;
1315 ads_dns->auth.password = secrets_fetch_machine_password(
1316 r->out.netbios_domain_name, NULL, NULL );
1317 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1318 strupper_m(ads_dns->auth.realm );
1319 ads_kinit_password( ads_dns );
1322 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1323 d_fprintf( stderr, "DNS update failed!\n" );
1326 /* exit from this block using machine creds */
1327 ads_destroy(&ads_dns);
1329 #endif
1330 TALLOC_FREE(r);
1331 TALLOC_FREE( ctx );
1333 return 0;
1335 fail:
1336 /* issue an overall failure message at the end. */
1337 d_printf("Failed to join domain: %s\n",
1338 r && r->out.error_string ? r->out.error_string :
1339 get_friendly_werror_msg(werr));
1340 TALLOC_FREE( ctx );
1342 return -1;
1345 /*******************************************************************
1346 ********************************************************************/
1348 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1350 #if defined(WITH_DNS_UPDATES)
1351 ADS_STRUCT *ads;
1352 ADS_STATUS status;
1353 TALLOC_CTX *ctx;
1355 #ifdef DEVELOPER
1356 talloc_enable_leak_report();
1357 #endif
1359 if (argc > 0 || c->display_usage) {
1360 d_printf("Usage:\n"
1361 "net ads dns register\n"
1362 " Register hostname with DNS\n");
1363 return -1;
1366 if (!(ctx = talloc_init("net_ads_dns"))) {
1367 d_fprintf(stderr, "Could not initialise talloc context\n");
1368 return -1;
1371 status = ads_startup(c, true, &ads);
1372 if ( !ADS_ERR_OK(status) ) {
1373 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1374 TALLOC_FREE(ctx);
1375 return -1;
1378 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1379 d_fprintf( stderr, "DNS update failed!\n" );
1380 ads_destroy( &ads );
1381 TALLOC_FREE( ctx );
1382 return -1;
1385 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1387 ads_destroy(&ads);
1388 TALLOC_FREE( ctx );
1390 return 0;
1391 #else
1392 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1393 return -1;
1394 #endif
1397 #if defined(WITH_DNS_UPDATES)
1398 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1399 #endif
1401 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1403 #if defined(WITH_DNS_UPDATES)
1404 DNS_ERROR err;
1406 #ifdef DEVELOPER
1407 talloc_enable_leak_report();
1408 #endif
1410 if (argc != 2 || c->display_usage) {
1411 d_printf("Usage:\n"
1412 "net ads dns gethostbyname <server> <name>\n"
1413 " Look up hostname from the AD\n"
1414 " server\tName server to use\n"
1415 " name\tName to look up\n");
1416 return -1;
1419 err = do_gethostbyname(argv[0], argv[1]);
1421 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1422 #endif
1423 return 0;
1426 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1428 struct functable func[] = {
1430 "register",
1431 net_ads_dns_register,
1432 NET_TRANSPORT_ADS,
1433 "Add host dns entry to AD",
1434 "net ads dns register\n"
1435 " Add host dns entry to AD"
1438 "gethostbyname",
1439 net_ads_dns_gethostbyname,
1440 NET_TRANSPORT_ADS,
1441 "Look up host",
1442 "net ads dns gethostbyname\n"
1443 " Look up host"
1445 {NULL, NULL, 0, NULL, NULL}
1448 return net_run_function(c, argc, argv, "net ads dns", func);
1451 /*******************************************************************
1452 ********************************************************************/
1454 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1456 d_printf(
1457 "\nnet ads printer search <printer>"
1458 "\n\tsearch for a printer in the directory\n"
1459 "\nnet ads printer info <printer> <server>"
1460 "\n\tlookup info in directory for printer on server"
1461 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1462 "\nnet ads printer publish <printername>"
1463 "\n\tpublish printer in directory"
1464 "\n\t(note: printer name is required)\n"
1465 "\nnet ads printer remove <printername>"
1466 "\n\tremove printer from directory"
1467 "\n\t(note: printer name is required)\n");
1468 return -1;
1471 /*******************************************************************
1472 ********************************************************************/
1474 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1476 ADS_STRUCT *ads;
1477 ADS_STATUS rc;
1478 LDAPMessage *res = NULL;
1480 if (c->display_usage) {
1481 d_printf("Usage:\n"
1482 "net ads printer search\n"
1483 " List printers in the AD\n");
1484 return 0;
1487 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1488 return -1;
1491 rc = ads_find_printers(ads, &res);
1493 if (!ADS_ERR_OK(rc)) {
1494 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1495 ads_msgfree(ads, res);
1496 ads_destroy(&ads);
1497 return -1;
1500 if (ads_count_replies(ads, res) == 0) {
1501 d_fprintf(stderr, "No results found\n");
1502 ads_msgfree(ads, res);
1503 ads_destroy(&ads);
1504 return -1;
1507 ads_dump(ads, res);
1508 ads_msgfree(ads, res);
1509 ads_destroy(&ads);
1510 return 0;
1513 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1515 ADS_STRUCT *ads;
1516 ADS_STATUS rc;
1517 const char *servername, *printername;
1518 LDAPMessage *res = NULL;
1520 if (c->display_usage) {
1521 d_printf("Usage:\n"
1522 "net ads printer info [printername [servername]]\n"
1523 " Display printer info from AD\n"
1524 " printername\tPrinter name or wildcard\n"
1525 " servername\tName of the print server\n");
1526 return 0;
1529 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1530 return -1;
1533 if (argc > 0) {
1534 printername = argv[0];
1535 } else {
1536 printername = "*";
1539 if (argc > 1) {
1540 servername = argv[1];
1541 } else {
1542 servername = global_myname();
1545 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1547 if (!ADS_ERR_OK(rc)) {
1548 d_fprintf(stderr, "Server '%s' not found: %s\n",
1549 servername, 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, "Printer '%s' not found\n", printername);
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);
1566 return 0;
1569 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1571 ADS_STRUCT *ads;
1572 ADS_STATUS rc;
1573 const char *servername, *printername;
1574 struct cli_state *cli;
1575 struct rpc_pipe_client *pipe_hnd;
1576 struct sockaddr_storage server_ss;
1577 NTSTATUS nt_status;
1578 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1579 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1580 char *prt_dn, *srv_dn, **srv_cn;
1581 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1582 LDAPMessage *res = NULL;
1584 if (argc < 1 || c->display_usage) {
1585 d_printf("Usage:\n"
1586 "net ads printer publish <printername> [servername]\n"
1587 " Publish printer in AD\n"
1588 " printername\tName of the printer\n"
1589 " servername\tName of the print server\n");
1590 talloc_destroy(mem_ctx);
1591 return -1;
1594 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1595 talloc_destroy(mem_ctx);
1596 return -1;
1599 printername = argv[0];
1601 if (argc == 2) {
1602 servername = argv[1];
1603 } else {
1604 servername = global_myname();
1607 /* Get printer data from SPOOLSS */
1609 resolve_name(servername, &server_ss, 0x20);
1611 nt_status = cli_full_connection(&cli, global_myname(), servername,
1612 &server_ss, 0,
1613 "IPC$", "IPC",
1614 c->opt_user_name, c->opt_workgroup,
1615 c->opt_password ? c->opt_password : "",
1616 CLI_FULL_CONNECTION_USE_KERBEROS,
1617 Undefined, NULL);
1619 if (NT_STATUS_IS_ERR(nt_status)) {
1620 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1621 "for %s\n", servername, printername);
1622 ads_destroy(&ads);
1623 talloc_destroy(mem_ctx);
1624 return -1;
1627 /* Publish on AD server */
1629 ads_find_machine_acct(ads, &res, servername);
1631 if (ads_count_replies(ads, res) == 0) {
1632 d_fprintf(stderr, "Could not find machine account for server %s\n",
1633 servername);
1634 ads_destroy(&ads);
1635 talloc_destroy(mem_ctx);
1636 return -1;
1639 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1640 srv_cn = ldap_explode_dn(srv_dn, 1);
1642 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1643 printername_escaped = escape_rdn_val_string_alloc(printername);
1644 if (!srv_cn_escaped || !printername_escaped) {
1645 SAFE_FREE(srv_cn_escaped);
1646 SAFE_FREE(printername_escaped);
1647 d_fprintf(stderr, "Internal error, out of memory!");
1648 ads_destroy(&ads);
1649 talloc_destroy(mem_ctx);
1650 return -1;
1653 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1654 SAFE_FREE(srv_cn_escaped);
1655 SAFE_FREE(printername_escaped);
1656 d_fprintf(stderr, "Internal error, out of memory!");
1657 ads_destroy(&ads);
1658 talloc_destroy(mem_ctx);
1659 return -1;
1662 SAFE_FREE(srv_cn_escaped);
1663 SAFE_FREE(printername_escaped);
1665 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
1666 if (!NT_STATUS_IS_OK(nt_status)) {
1667 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1668 servername);
1669 SAFE_FREE(prt_dn);
1670 ads_destroy(&ads);
1671 talloc_destroy(mem_ctx);
1672 return -1;
1675 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1676 printername))) {
1677 SAFE_FREE(prt_dn);
1678 ads_destroy(&ads);
1679 talloc_destroy(mem_ctx);
1680 return -1;
1683 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1684 if (!ADS_ERR_OK(rc)) {
1685 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1686 SAFE_FREE(prt_dn);
1687 ads_destroy(&ads);
1688 talloc_destroy(mem_ctx);
1689 return -1;
1692 d_printf("published printer\n");
1693 SAFE_FREE(prt_dn);
1694 ads_destroy(&ads);
1695 talloc_destroy(mem_ctx);
1697 return 0;
1700 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1702 ADS_STRUCT *ads;
1703 ADS_STATUS rc;
1704 const char *servername;
1705 char *prt_dn;
1706 LDAPMessage *res = NULL;
1708 if (argc < 1 || c->display_usage) {
1709 d_printf("Usage:\n"
1710 "net ads printer remove <printername> [servername]\n"
1711 " Remove a printer from the AD\n"
1712 " printername\tName of the printer\n"
1713 " servername\tName of the print server\n");
1714 return -1;
1717 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1718 return -1;
1721 if (argc > 1) {
1722 servername = argv[1];
1723 } else {
1724 servername = global_myname();
1727 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1729 if (!ADS_ERR_OK(rc)) {
1730 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1731 ads_msgfree(ads, res);
1732 ads_destroy(&ads);
1733 return -1;
1736 if (ads_count_replies(ads, res) == 0) {
1737 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1738 ads_msgfree(ads, res);
1739 ads_destroy(&ads);
1740 return -1;
1743 prt_dn = ads_get_dn(ads, NULL, res);
1744 ads_msgfree(ads, res);
1745 rc = ads_del_dn(ads, prt_dn);
1746 TALLOC_FREE(prt_dn);
1748 if (!ADS_ERR_OK(rc)) {
1749 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1750 ads_destroy(&ads);
1751 return -1;
1754 ads_destroy(&ads);
1755 return 0;
1758 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1760 struct functable func[] = {
1762 "search",
1763 net_ads_printer_search,
1764 NET_TRANSPORT_ADS,
1765 "Search for a printer",
1766 "net ads printer search\n"
1767 " Search for a printer"
1770 "info",
1771 net_ads_printer_info,
1772 NET_TRANSPORT_ADS,
1773 "Display printer information",
1774 "net ads printer info\n"
1775 " Display printer information"
1778 "publish",
1779 net_ads_printer_publish,
1780 NET_TRANSPORT_ADS,
1781 "Publish a printer",
1782 "net ads printer publish\n"
1783 " Publish a printer"
1786 "remove",
1787 net_ads_printer_remove,
1788 NET_TRANSPORT_ADS,
1789 "Delete a printer",
1790 "net ads printer remove\n"
1791 " Delete a printer"
1793 {NULL, NULL, 0, NULL, NULL}
1796 return net_run_function(c, argc, argv, "net ads printer", func);
1800 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1802 ADS_STRUCT *ads;
1803 const char *auth_principal = c->opt_user_name;
1804 const char *auth_password = c->opt_password;
1805 char *realm = NULL;
1806 char *new_password = NULL;
1807 char *chr, *prompt;
1808 const char *user;
1809 ADS_STATUS ret;
1811 if (c->display_usage) {
1812 d_printf("Usage:\n"
1813 "net ads password <username>\n"
1814 " Change password for user\n"
1815 " username\tName of user to change password for\n");
1816 return 0;
1819 if (c->opt_user_name == NULL || c->opt_password == NULL) {
1820 d_fprintf(stderr, "You must supply an administrator username/password\n");
1821 return -1;
1824 if (argc < 1) {
1825 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1826 return -1;
1829 user = argv[0];
1830 if (!strchr_m(user, '@')) {
1831 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
1832 return -1;
1834 user = chr;
1837 use_in_memory_ccache();
1838 chr = strchr_m(auth_principal, '@');
1839 if (chr) {
1840 realm = ++chr;
1841 } else {
1842 realm = lp_realm();
1845 /* use the realm so we can eventually change passwords for users
1846 in realms other than default */
1847 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1848 return -1;
1851 /* we don't actually need a full connect, but it's the easy way to
1852 fill in the KDC's addresss */
1853 ads_connect(ads);
1855 if (!ads->config.realm) {
1856 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1857 ads_destroy(&ads);
1858 return -1;
1861 if (argv[1]) {
1862 new_password = (char *)argv[1];
1863 } else {
1864 if (asprintf(&prompt, "Enter new password for %s:", user) == -1) {
1865 return -1;
1867 new_password = getpass(prompt);
1868 free(prompt);
1871 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1872 auth_password, user, new_password, ads->auth.time_offset);
1873 if (!ADS_ERR_OK(ret)) {
1874 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1875 ads_destroy(&ads);
1876 return -1;
1879 d_printf("Password change for %s completed.\n", user);
1880 ads_destroy(&ads);
1882 return 0;
1885 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1887 ADS_STRUCT *ads;
1888 char *host_principal;
1889 fstring my_name;
1890 ADS_STATUS ret;
1892 if (c->display_usage) {
1893 d_printf("Usage:\n"
1894 "net ads changetrustpw\n"
1895 " Change the machine account's trust password\n");
1896 return 0;
1899 if (!secrets_init()) {
1900 DEBUG(1,("Failed to initialise secrets database\n"));
1901 return -1;
1904 net_use_krb_machine_account(c);
1906 use_in_memory_ccache();
1908 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1909 return -1;
1912 fstrcpy(my_name, global_myname());
1913 strlower_m(my_name);
1914 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
1915 ads_destroy(&ads);
1916 return -1;
1918 d_printf("Changing password for principal: %s\n", host_principal);
1920 ret = ads_change_trust_account_password(ads, host_principal);
1922 if (!ADS_ERR_OK(ret)) {
1923 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1924 ads_destroy(&ads);
1925 SAFE_FREE(host_principal);
1926 return -1;
1929 d_printf("Password change for principal %s succeeded.\n", host_principal);
1931 if (USE_SYSTEM_KEYTAB) {
1932 d_printf("Attempting to update system keytab with new password.\n");
1933 if (ads_keytab_create_default(ads)) {
1934 d_printf("Failed to update system keytab.\n");
1938 ads_destroy(&ads);
1939 SAFE_FREE(host_principal);
1941 return 0;
1945 help for net ads search
1947 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
1949 d_printf(
1950 "\nnet ads search <expression> <attributes...>\n"
1951 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
1952 "The expression is a standard LDAP search expression, and the\n"
1953 "attributes are a list of LDAP fields to show in the results.\n\n"
1954 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1956 net_common_flags_usage(c, argc, argv);
1957 return -1;
1962 general ADS search function. Useful in diagnosing problems in ADS
1964 static int net_ads_search(struct net_context *c, int argc, const char **argv)
1966 ADS_STRUCT *ads;
1967 ADS_STATUS rc;
1968 const char *ldap_exp;
1969 const char **attrs;
1970 LDAPMessage *res = NULL;
1972 if (argc < 1 || c->display_usage) {
1973 return net_ads_search_usage(c, argc, argv);
1976 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1977 return -1;
1980 ldap_exp = argv[0];
1981 attrs = (argv + 1);
1983 rc = ads_do_search_all(ads, ads->config.bind_path,
1984 LDAP_SCOPE_SUBTREE,
1985 ldap_exp, attrs, &res);
1986 if (!ADS_ERR_OK(rc)) {
1987 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1988 ads_destroy(&ads);
1989 return -1;
1992 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1994 /* dump the results */
1995 ads_dump(ads, res);
1997 ads_msgfree(ads, res);
1998 ads_destroy(&ads);
2000 return 0;
2005 help for net ads search
2007 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2009 d_printf(
2010 "\nnet ads dn <dn> <attributes...>\n"
2011 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2012 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2013 "to show in the results\n\n"
2014 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2015 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2017 net_common_flags_usage(c, argc, argv);
2018 return -1;
2023 general ADS search function. Useful in diagnosing problems in ADS
2025 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2027 ADS_STRUCT *ads;
2028 ADS_STATUS rc;
2029 const char *dn;
2030 const char **attrs;
2031 LDAPMessage *res = NULL;
2033 if (argc < 1 || c->display_usage) {
2034 return net_ads_dn_usage(c, argc, argv);
2037 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2038 return -1;
2041 dn = argv[0];
2042 attrs = (argv + 1);
2044 rc = ads_do_search_all(ads, dn,
2045 LDAP_SCOPE_BASE,
2046 "(objectclass=*)", attrs, &res);
2047 if (!ADS_ERR_OK(rc)) {
2048 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2049 ads_destroy(&ads);
2050 return -1;
2053 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2055 /* dump the results */
2056 ads_dump(ads, res);
2058 ads_msgfree(ads, res);
2059 ads_destroy(&ads);
2061 return 0;
2065 help for net ads sid search
2067 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2069 d_printf(
2070 "\nnet ads sid <sid> <attributes...>\n"
2071 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2072 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2073 "to show in the results\n\n"
2074 "Example: net ads sid 'S-1-5-32' distinguishedName\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_sid(struct net_context *c, int argc, const char **argv)
2086 ADS_STRUCT *ads;
2087 ADS_STATUS rc;
2088 const char *sid_string;
2089 const char **attrs;
2090 LDAPMessage *res = NULL;
2091 DOM_SID sid;
2093 if (argc < 1 || c->display_usage) {
2094 return net_ads_sid_usage(c, argc, argv);
2097 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2098 return -1;
2101 sid_string = argv[0];
2102 attrs = (argv + 1);
2104 if (!string_to_sid(&sid, sid_string)) {
2105 d_fprintf(stderr, "could not convert sid\n");
2106 ads_destroy(&ads);
2107 return -1;
2110 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2111 if (!ADS_ERR_OK(rc)) {
2112 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2113 ads_destroy(&ads);
2114 return -1;
2117 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2119 /* dump the results */
2120 ads_dump(ads, res);
2122 ads_msgfree(ads, res);
2123 ads_destroy(&ads);
2125 return 0;
2128 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2130 int ret;
2131 ADS_STRUCT *ads;
2133 if (c->display_usage) {
2134 d_printf("Usage:\n"
2135 "net ads keytab flush\n"
2136 " Delete the whole keytab\n");
2137 return 0;
2140 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2141 return -1;
2143 ret = ads_keytab_flush(ads);
2144 ads_destroy(&ads);
2145 return ret;
2148 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2150 int i;
2151 int ret = 0;
2152 ADS_STRUCT *ads;
2154 if (c->display_usage) {
2155 d_printf("Usage:\n"
2156 "net ads keytab add <principal> [principal ...]\n"
2157 " Add principals to local keytab\n"
2158 " principal\tKerberos principal to add to "
2159 "keytab\n");
2160 return 0;
2163 d_printf("Processing principals to add...\n");
2164 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2165 return -1;
2167 for (i = 0; i < argc; i++) {
2168 ret |= ads_keytab_add_entry(ads, argv[i]);
2170 ads_destroy(&ads);
2171 return ret;
2174 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2176 ADS_STRUCT *ads;
2177 int ret;
2179 if (c->display_usage) {
2180 d_printf("Usage:\n"
2181 "net ads keytab create\n"
2182 " Create new default keytab\n");
2183 return 0;
2186 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2187 return -1;
2189 ret = ads_keytab_create_default(ads);
2190 ads_destroy(&ads);
2191 return ret;
2194 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2196 const char *keytab = NULL;
2198 if (c->display_usage) {
2199 d_printf("Usage:\n"
2200 "net ads keytab list [keytab]\n"
2201 " List a local keytab\n"
2202 " keytab\tKeytab to list\n");
2203 return 0;
2206 if (argc >= 1) {
2207 keytab = argv[0];
2210 return ads_keytab_list(keytab);
2214 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2216 struct functable func[] = {
2218 "add",
2219 net_ads_keytab_add,
2220 NET_TRANSPORT_ADS,
2221 "Add a service principal",
2222 "net ads keytab add\n"
2223 " Add a service principal"
2226 "create",
2227 net_ads_keytab_create,
2228 NET_TRANSPORT_ADS,
2229 "Create a fresh keytab",
2230 "net ads keytab create\n"
2231 " Create a fresh keytab"
2234 "flush",
2235 net_ads_keytab_flush,
2236 NET_TRANSPORT_ADS,
2237 "Remove all keytab entries",
2238 "net ads keytab flush\n"
2239 " Remove all keytab entries"
2242 "list",
2243 net_ads_keytab_list,
2244 NET_TRANSPORT_ADS,
2245 "List a keytab",
2246 "net ads keytab list\n"
2247 " List a keytab"
2249 {NULL, NULL, 0, NULL, NULL}
2252 if (!USE_KERBEROS_KEYTAB) {
2253 d_printf("\nWarning: \"kerberos method\" must be set to a "
2254 "keytab method to use keytab functions.\n");
2257 return net_run_function(c, argc, argv, "net ads keytab", func);
2260 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2262 int ret = -1;
2264 if (c->display_usage) {
2265 d_printf("Usage:\n"
2266 "net ads kerberos renew\n"
2267 " Renew TGT from existing credential cache\n");
2268 return 0;
2271 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2272 if (ret) {
2273 d_printf("failed to renew kerberos ticket: %s\n",
2274 error_message(ret));
2276 return ret;
2279 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2281 struct PAC_DATA *pac = NULL;
2282 struct PAC_LOGON_INFO *info = NULL;
2283 TALLOC_CTX *mem_ctx = NULL;
2284 NTSTATUS status;
2285 int ret = -1;
2287 if (c->display_usage) {
2288 d_printf("Usage:\n"
2289 "net ads kerberos pac\n"
2290 " Dump the Kerberos PAC\n");
2291 return 0;
2294 mem_ctx = talloc_init("net_ads_kerberos_pac");
2295 if (!mem_ctx) {
2296 goto out;
2299 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2301 status = kerberos_return_pac(mem_ctx,
2302 c->opt_user_name,
2303 c->opt_password,
2305 NULL,
2306 NULL,
2307 NULL,
2308 true,
2309 true,
2310 2592000, /* one month */
2311 &pac);
2312 if (!NT_STATUS_IS_OK(status)) {
2313 d_printf("failed to query kerberos PAC: %s\n",
2314 nt_errstr(status));
2315 goto out;
2318 info = get_logon_info_from_pac(pac);
2319 if (info) {
2320 const char *s;
2321 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2322 d_printf("The Pac: %s\n", s);
2325 ret = 0;
2326 out:
2327 TALLOC_FREE(mem_ctx);
2328 return ret;
2331 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2333 TALLOC_CTX *mem_ctx = NULL;
2334 int ret = -1;
2335 NTSTATUS status;
2337 if (c->display_usage) {
2338 d_printf("Usage:\n"
2339 "net ads kerberos kinit\n"
2340 " Get Ticket Granting Ticket (TGT) for the user\n");
2341 return 0;
2344 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2345 if (!mem_ctx) {
2346 goto out;
2349 c->opt_password = net_prompt_pass(c, c->opt_user_name);
2351 ret = kerberos_kinit_password_ext(c->opt_user_name,
2352 c->opt_password,
2354 NULL,
2355 NULL,
2356 NULL,
2357 true,
2358 true,
2359 2592000, /* one month */
2360 &status);
2361 if (ret) {
2362 d_printf("failed to kinit password: %s\n",
2363 nt_errstr(status));
2365 out:
2366 return ret;
2369 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2371 struct functable func[] = {
2373 "kinit",
2374 net_ads_kerberos_kinit,
2375 NET_TRANSPORT_ADS,
2376 "Retrieve Ticket Granting Ticket (TGT)",
2377 "net ads kerberos kinit\n"
2378 " Receive Ticket Granting Ticket (TGT)"
2381 "renew",
2382 net_ads_kerberos_renew,
2383 NET_TRANSPORT_ADS,
2384 "Renew Ticket Granting Ticket from credential cache"
2385 "net ads kerberos renew\n"
2386 " Renew Ticket Granting Ticket from credential cache"
2389 "pac",
2390 net_ads_kerberos_pac,
2391 NET_TRANSPORT_ADS,
2392 "Dump Kerberos PAC",
2393 "net ads kerberos pac\n"
2394 " Dump Kerberos PAC"
2396 {NULL, NULL, 0, NULL, NULL}
2399 return net_run_function(c, argc, argv, "net ads kerberos", func);
2402 int net_ads(struct net_context *c, int argc, const char **argv)
2404 struct functable func[] = {
2406 "info",
2407 net_ads_info,
2408 NET_TRANSPORT_ADS,
2409 "Display details on remote ADS server",
2410 "net ads info\n"
2411 " Display details on remote ADS server"
2414 "join",
2415 net_ads_join,
2416 NET_TRANSPORT_ADS,
2417 "Join the local machine to ADS realm",
2418 "net ads join\n"
2419 " Join the local machine to ADS realm"
2422 "testjoin",
2423 net_ads_testjoin,
2424 NET_TRANSPORT_ADS,
2425 "Validate machine account",
2426 "net ads testjoin\n"
2427 " Validate machine account"
2430 "leave",
2431 net_ads_leave,
2432 NET_TRANSPORT_ADS,
2433 "Remove the local machine from ADS",
2434 "net ads leave\n"
2435 " Remove the local machine from ADS"
2438 "status",
2439 net_ads_status,
2440 NET_TRANSPORT_ADS,
2441 "Display machine account details",
2442 "net ads status\n"
2443 " Display machine account details"
2446 "user",
2447 net_ads_user,
2448 NET_TRANSPORT_ADS,
2449 "List/modify users",
2450 "net ads user\n"
2451 " List/modify users"
2454 "group",
2455 net_ads_group,
2456 NET_TRANSPORT_ADS,
2457 "List/modify groups",
2458 "net ads group\n"
2459 " List/modify groups"
2462 "dns",
2463 net_ads_dns,
2464 NET_TRANSPORT_ADS,
2465 "Issue dynamic DNS update",
2466 "net ads dns\n"
2467 " Issue dynamic DNS update"
2470 "password",
2471 net_ads_password,
2472 NET_TRANSPORT_ADS,
2473 "Change user passwords",
2474 "net ads password\n"
2475 " Change user passwords"
2478 "changetrustpw",
2479 net_ads_changetrustpw,
2480 NET_TRANSPORT_ADS,
2481 "Change trust account password",
2482 "net ads changetrustpw\n"
2483 " Change trust account password"
2486 "printer",
2487 net_ads_printer,
2488 NET_TRANSPORT_ADS,
2489 "List/modify printer entries",
2490 "net ads printer\n"
2491 " List/modify printer entries"
2494 "search",
2495 net_ads_search,
2496 NET_TRANSPORT_ADS,
2497 "Issue LDAP search using filter",
2498 "net ads search\n"
2499 " Issue LDAP search using filter"
2502 "dn",
2503 net_ads_dn,
2504 NET_TRANSPORT_ADS,
2505 "Issue LDAP search by DN",
2506 "net ads dn\n"
2507 " Issue LDAP search by DN"
2510 "sid",
2511 net_ads_sid,
2512 NET_TRANSPORT_ADS,
2513 "Issue LDAP search by SID",
2514 "net ads sid\n"
2515 " Issue LDAP search by SID"
2518 "workgroup",
2519 net_ads_workgroup,
2520 NET_TRANSPORT_ADS,
2521 "Display workgroup name",
2522 "net ads workgroup\n"
2523 " Display the workgroup name"
2526 "lookup",
2527 net_ads_lookup,
2528 NET_TRANSPORT_ADS,
2529 "Perfom CLDAP query on DC",
2530 "net ads lookup\n"
2531 " Find the ADS DC using CLDAP lookups"
2534 "keytab",
2535 net_ads_keytab,
2536 NET_TRANSPORT_ADS,
2537 "Manage local keytab file",
2538 "net ads keytab\n"
2539 " Manage local keytab file"
2542 "gpo",
2543 net_ads_gpo,
2544 NET_TRANSPORT_ADS,
2545 "Manage group policy objects",
2546 "net ads gpo\n"
2547 " Manage group policy objects"
2550 "kerberos",
2551 net_ads_kerberos,
2552 NET_TRANSPORT_ADS,
2553 "Manage kerberos keytab",
2554 "net ads kerberos\n"
2555 " Manage kerberos keytab"
2557 {NULL, NULL, 0, NULL, NULL}
2560 return net_run_function(c, argc, argv, "net ads", func);
2563 #else
2565 static int net_ads_noads(void)
2567 d_fprintf(stderr, "ADS support not compiled in\n");
2568 return -1;
2571 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2573 return net_ads_noads();
2576 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2578 return net_ads_noads();
2581 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2583 return net_ads_noads();
2586 int net_ads_join(struct net_context *c, int argc, const char **argv)
2588 return net_ads_noads();
2591 int net_ads_user(struct net_context *c, int argc, const char **argv)
2593 return net_ads_noads();
2596 int net_ads_group(struct net_context *c, int argc, const char **argv)
2598 return net_ads_noads();
2601 /* this one shouldn't display a message */
2602 int net_ads_check(struct net_context *c)
2604 return -1;
2607 int net_ads_check_our_domain(struct net_context *c)
2609 return -1;
2612 int net_ads(struct net_context *c, int argc, const char **argv)
2614 return net_ads_noads();
2617 #endif /* WITH_ADS */