s3-net: fix "net ads testjoin".
[Samba.git] / source3 / utils / net_ads.c
blob588f57f030daa4876444fbbab1053847c88ba61d
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 retry:
235 if (need_password) {
236 set_cmdline_auth_info_getpass(c->auth_info);
239 if (get_cmdline_auth_info_got_pass(c->auth_info)) {
240 use_in_memory_ccache();
241 SAFE_FREE(ads->auth.password);
242 ads->auth.password = smb_xstrdup(
243 get_cmdline_auth_info_password(c->auth_info));
246 ads->auth.flags |= auth_flags;
247 SAFE_FREE(ads->auth.user_name);
248 ads->auth.user_name = smb_xstrdup(
249 get_cmdline_auth_info_username(c->auth_info));
252 * If the username is of the form "name@realm",
253 * extract the realm and convert to upper case.
254 * This is only used to establish the connection.
256 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
257 *cp++ = '\0';
258 SAFE_FREE(ads->auth.realm);
259 ads->auth.realm = smb_xstrdup(cp);
260 strupper_m(ads->auth.realm);
263 status = ads_connect(ads);
265 if (!ADS_ERR_OK(status)) {
267 if (NT_STATUS_EQUAL(ads_ntstatus(status),
268 NT_STATUS_NO_LOGON_SERVERS)) {
269 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
270 ads_destroy(&ads);
271 return status;
274 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
275 need_password = true;
276 second_time = true;
277 goto retry;
278 } else {
279 ads_destroy(&ads);
280 return status;
284 /* when contacting our own domain, make sure we use the closest DC.
285 * This is done by reconnecting to ADS because only the first call to
286 * ads_connect will give us our own sitename */
288 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
290 tried_closest_dc = true; /* avoid loop */
292 if (!ads_closest_dc(ads)) {
294 namecache_delete(ads->server.realm, 0x1C);
295 namecache_delete(ads->server.workgroup, 0x1C);
297 ads_destroy(&ads);
298 ads = NULL;
300 goto retry_connect;
304 *ads_ret = ads;
305 return status;
308 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
310 return ads_startup_int(c, only_own_domain, 0, ads);
313 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
315 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
319 Check to see if connection can be made via ads.
320 ads_startup() stores the password in opt_password if it needs to so
321 that rpc or rap can use it without re-prompting.
323 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
325 ADS_STRUCT *ads;
326 ADS_STATUS status;
328 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
329 return -1;
332 ads->auth.flags |= ADS_AUTH_NO_BIND;
334 status = ads_connect(ads);
335 if ( !ADS_ERR_OK(status) ) {
336 return -1;
339 ads_destroy(&ads);
340 return 0;
343 int net_ads_check_our_domain(struct net_context *c)
345 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
348 int net_ads_check(struct net_context *c)
350 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
354 determine the netbios workgroup name for a domain
356 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
358 ADS_STRUCT *ads;
359 char addr[INET6_ADDRSTRLEN];
360 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
362 if (c->display_usage) {
363 d_printf("Usage:\n"
364 "net ads workgroup\n"
365 " Print the workgroup name\n");
366 return 0;
369 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
370 d_fprintf(stderr, "Didn't find the cldap server!\n");
371 return -1;
374 if (!ads->config.realm) {
375 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
376 ads->ldap.port = 389;
379 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
380 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
381 d_fprintf(stderr, "CLDAP query failed!\n");
382 ads_destroy(&ads);
383 return -1;
386 d_printf("Workgroup: %s\n", reply.domain);
388 ads_destroy(&ads);
390 return 0;
395 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
397 char **disp_fields = (char **) data_area;
399 if (!field) { /* must be end of record */
400 if (disp_fields[0]) {
401 if (!strchr_m(disp_fields[0], '$')) {
402 if (disp_fields[1])
403 d_printf("%-21.21s %s\n",
404 disp_fields[0], disp_fields[1]);
405 else
406 d_printf("%s\n", disp_fields[0]);
409 SAFE_FREE(disp_fields[0]);
410 SAFE_FREE(disp_fields[1]);
411 return true;
413 if (!values) /* must be new field, indicate string field */
414 return true;
415 if (StrCaseCmp(field, "sAMAccountName") == 0) {
416 disp_fields[0] = SMB_STRDUP((char *) values[0]);
418 if (StrCaseCmp(field, "description") == 0)
419 disp_fields[1] = SMB_STRDUP((char *) values[0]);
420 return true;
423 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
425 return net_user_usage(c, argc, argv);
428 static int ads_user_add(struct net_context *c, int argc, const char **argv)
430 ADS_STRUCT *ads;
431 ADS_STATUS status;
432 char *upn, *userdn;
433 LDAPMessage *res=NULL;
434 int rc = -1;
435 char *ou_str = NULL;
437 if (argc < 1 || c->display_usage)
438 return net_ads_user_usage(c, argc, argv);
440 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
441 return -1;
444 status = ads_find_user_acct(ads, &res, argv[0]);
446 if (!ADS_ERR_OK(status)) {
447 d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
448 goto done;
451 if (ads_count_replies(ads, res)) {
452 d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
453 goto done;
456 if (c->opt_container) {
457 ou_str = SMB_STRDUP(c->opt_container);
458 } else {
459 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
462 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
464 if (!ADS_ERR_OK(status)) {
465 d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
466 ads_errstr(status));
467 goto done;
470 /* if no password is to be set, we're done */
471 if (argc == 1) {
472 d_printf("User %s added\n", argv[0]);
473 rc = 0;
474 goto done;
477 /* try setting the password */
478 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
479 goto done;
481 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
482 ads->auth.time_offset);
483 SAFE_FREE(upn);
484 if (ADS_ERR_OK(status)) {
485 d_printf("User %s added\n", argv[0]);
486 rc = 0;
487 goto done;
490 /* password didn't set, delete account */
491 d_fprintf(stderr, "Could not add user %s. Error setting password %s\n",
492 argv[0], ads_errstr(status));
493 ads_msgfree(ads, res);
494 status=ads_find_user_acct(ads, &res, argv[0]);
495 if (ADS_ERR_OK(status)) {
496 userdn = ads_get_dn(ads, talloc_tos(), res);
497 ads_del_dn(ads, userdn);
498 TALLOC_FREE(userdn);
501 done:
502 if (res)
503 ads_msgfree(ads, res);
504 ads_destroy(&ads);
505 SAFE_FREE(ou_str);
506 return rc;
509 static int ads_user_info(struct net_context *c, int argc, const char **argv)
511 ADS_STRUCT *ads;
512 ADS_STATUS rc;
513 LDAPMessage *res;
514 const char *attrs[] = {"memberOf", NULL};
515 char *searchstring=NULL;
516 char **grouplist;
517 char *escaped_user;
519 if (argc < 1 || c->display_usage) {
520 return net_ads_user_usage(c, argc, argv);
523 escaped_user = escape_ldap_string_alloc(argv[0]);
525 if (!escaped_user) {
526 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
527 return -1;
530 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
531 SAFE_FREE(escaped_user);
532 return -1;
535 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
536 SAFE_FREE(escaped_user);
537 return -1;
539 rc = ads_search(ads, &res, searchstring, attrs);
540 SAFE_FREE(searchstring);
542 if (!ADS_ERR_OK(rc)) {
543 d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
544 ads_destroy(&ads);
545 SAFE_FREE(escaped_user);
546 return -1;
549 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
550 (LDAPMessage *)res, "memberOf");
552 if (grouplist) {
553 int i;
554 char **groupname;
555 for (i=0;grouplist[i];i++) {
556 groupname = ldap_explode_dn(grouplist[i], 1);
557 d_printf("%s\n", groupname[0]);
558 ldap_value_free(groupname);
560 ldap_value_free(grouplist);
563 ads_msgfree(ads, res);
564 ads_destroy(&ads);
565 SAFE_FREE(escaped_user);
566 return 0;
569 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
571 ADS_STRUCT *ads;
572 ADS_STATUS rc;
573 LDAPMessage *res = NULL;
574 char *userdn;
576 if (argc < 1) {
577 return net_ads_user_usage(c, argc, argv);
580 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
581 return -1;
584 rc = ads_find_user_acct(ads, &res, argv[0]);
585 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
586 d_printf("User %s does not exist.\n", argv[0]);
587 ads_msgfree(ads, res);
588 ads_destroy(&ads);
589 return -1;
591 userdn = ads_get_dn(ads, talloc_tos(), res);
592 ads_msgfree(ads, res);
593 rc = ads_del_dn(ads, userdn);
594 TALLOC_FREE(userdn);
595 if (ADS_ERR_OK(rc)) {
596 d_printf("User %s deleted\n", argv[0]);
597 ads_destroy(&ads);
598 return 0;
600 d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
601 ads_errstr(rc));
602 ads_destroy(&ads);
603 return -1;
606 int net_ads_user(struct net_context *c, int argc, const char **argv)
608 struct functable func[] = {
610 "add",
611 ads_user_add,
612 NET_TRANSPORT_ADS,
613 "Add an AD user",
614 "net ads user add\n"
615 " Add an AD user"
618 "info",
619 ads_user_info,
620 NET_TRANSPORT_ADS,
621 "Display information about an AD user",
622 "net ads user info\n"
623 " Display information about an AD user"
626 "delete",
627 ads_user_delete,
628 NET_TRANSPORT_ADS,
629 "Delete an AD user",
630 "net ads user delete\n"
631 " Delete an AD user"
633 {NULL, NULL, 0, NULL, NULL}
635 ADS_STRUCT *ads;
636 ADS_STATUS rc;
637 const char *shortattrs[] = {"sAMAccountName", NULL};
638 const char *longattrs[] = {"sAMAccountName", "description", NULL};
639 char *disp_fields[2] = {NULL, NULL};
641 if (argc == 0) {
642 if (c->display_usage) {
643 d_printf("Usage:\n");
644 d_printf("net ads user\n"
645 " List AD users\n");
646 net_display_usage_from_functable(func);
647 return 0;
650 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
651 return -1;
654 if (c->opt_long_list_entries)
655 d_printf("\nUser name Comment"
656 "\n-----------------------------\n");
658 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
659 LDAP_SCOPE_SUBTREE,
660 "(objectCategory=user)",
661 c->opt_long_list_entries ? longattrs :
662 shortattrs, usergrp_display,
663 disp_fields);
664 ads_destroy(&ads);
665 return ADS_ERR_OK(rc) ? 0 : -1;
668 return net_run_function(c, argc, argv, "net ads user", func);
671 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
673 return net_group_usage(c, argc, argv);
676 static int ads_group_add(struct net_context *c, int argc, const char **argv)
678 ADS_STRUCT *ads;
679 ADS_STATUS status;
680 LDAPMessage *res=NULL;
681 int rc = -1;
682 char *ou_str = NULL;
684 if (argc < 1 || c->display_usage) {
685 return net_ads_group_usage(c, argc, argv);
688 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
689 return -1;
692 status = ads_find_user_acct(ads, &res, argv[0]);
694 if (!ADS_ERR_OK(status)) {
695 d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
696 goto done;
699 if (ads_count_replies(ads, res)) {
700 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
701 goto done;
704 if (c->opt_container) {
705 ou_str = SMB_STRDUP(c->opt_container);
706 } else {
707 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
710 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
712 if (ADS_ERR_OK(status)) {
713 d_printf("Group %s added\n", argv[0]);
714 rc = 0;
715 } else {
716 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
717 ads_errstr(status));
720 done:
721 if (res)
722 ads_msgfree(ads, res);
723 ads_destroy(&ads);
724 SAFE_FREE(ou_str);
725 return rc;
728 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
730 ADS_STRUCT *ads;
731 ADS_STATUS rc;
732 LDAPMessage *res = NULL;
733 char *groupdn;
735 if (argc < 1 || c->display_usage) {
736 return net_ads_group_usage(c, argc, argv);
739 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
740 return -1;
743 rc = ads_find_user_acct(ads, &res, argv[0]);
744 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
745 d_printf("Group %s does not exist.\n", argv[0]);
746 ads_msgfree(ads, res);
747 ads_destroy(&ads);
748 return -1;
750 groupdn = ads_get_dn(ads, talloc_tos(), res);
751 ads_msgfree(ads, res);
752 rc = ads_del_dn(ads, groupdn);
753 TALLOC_FREE(groupdn);
754 if (ADS_ERR_OK(rc)) {
755 d_printf("Group %s deleted\n", argv[0]);
756 ads_destroy(&ads);
757 return 0;
759 d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
760 ads_errstr(rc));
761 ads_destroy(&ads);
762 return -1;
765 int net_ads_group(struct net_context *c, int argc, const char **argv)
767 struct functable func[] = {
769 "add",
770 ads_group_add,
771 NET_TRANSPORT_ADS,
772 "Add an AD group",
773 "net ads group add\n"
774 " Add an AD group"
777 "delete",
778 ads_group_delete,
779 NET_TRANSPORT_ADS,
780 "Delete an AD group",
781 "net ads group delete\n"
782 " Delete an AD group"
784 {NULL, NULL, 0, NULL, NULL}
786 ADS_STRUCT *ads;
787 ADS_STATUS rc;
788 const char *shortattrs[] = {"sAMAccountName", NULL};
789 const char *longattrs[] = {"sAMAccountName", "description", NULL};
790 char *disp_fields[2] = {NULL, NULL};
792 if (argc == 0) {
793 if (c->display_usage) {
794 d_printf("Usage:\n");
795 d_printf("net ads group\n"
796 " List AD groups\n");
797 net_display_usage_from_functable(func);
798 return 0;
801 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
802 return -1;
805 if (c->opt_long_list_entries)
806 d_printf("\nGroup name Comment"
807 "\n-----------------------------\n");
808 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
809 LDAP_SCOPE_SUBTREE,
810 "(objectCategory=group)",
811 c->opt_long_list_entries ? longattrs :
812 shortattrs, usergrp_display,
813 disp_fields);
815 ads_destroy(&ads);
816 return ADS_ERR_OK(rc) ? 0 : -1;
818 return net_run_function(c, argc, argv, "net ads group", func);
821 static int net_ads_status(struct net_context *c, int argc, const char **argv)
823 ADS_STRUCT *ads;
824 ADS_STATUS rc;
825 LDAPMessage *res;
827 if (c->display_usage) {
828 d_printf("Usage:\n"
829 "net ads status\n"
830 " Display machine account details\n");
831 return 0;
834 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
835 return -1;
838 rc = ads_find_machine_acct(ads, &res, global_myname());
839 if (!ADS_ERR_OK(rc)) {
840 d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
841 ads_destroy(&ads);
842 return -1;
845 if (ads_count_replies(ads, res) == 0) {
846 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
847 ads_destroy(&ads);
848 return -1;
851 ads_dump(ads, res);
852 ads_destroy(&ads);
853 return 0;
856 /*******************************************************************
857 Leave an AD domain. Windows XP disables the machine account.
858 We'll try the same. The old code would do an LDAP delete.
859 That only worked using the machine creds because added the machine
860 with full control to the computer object's ACL.
861 *******************************************************************/
863 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
865 TALLOC_CTX *ctx;
866 struct libnet_UnjoinCtx *r = NULL;
867 WERROR werr;
868 struct user_auth_info *ai = c->auth_info;
870 if (c->display_usage) {
871 d_printf("Usage:\n"
872 "net ads leave\n"
873 " Leave an AD domain\n");
874 return 0;
877 if (!*lp_realm()) {
878 d_fprintf(stderr, "No realm set, are we joined ?\n");
879 return -1;
882 if (!(ctx = talloc_init("net_ads_leave"))) {
883 d_fprintf(stderr, "Could not initialise talloc context.\n");
884 return -1;
887 if (!get_cmdline_auth_info_use_kerberos(ai)) {
888 use_in_memory_ccache();
891 werr = libnet_init_UnjoinCtx(ctx, &r);
892 if (!W_ERROR_IS_OK(werr)) {
893 d_fprintf(stderr, "Could not initialise unjoin context.\n");
894 return -1;
897 set_cmdline_auth_info_getpass(ai);
899 r->in.debug = true;
900 r->in.use_kerberos = get_cmdline_auth_info_use_kerberos(ai);
901 r->in.dc_name = c->opt_host;
902 r->in.domain_name = lp_realm();
903 r->in.admin_account = get_cmdline_auth_info_username(ai);
904 r->in.admin_password = get_cmdline_auth_info_password(ai);
905 r->in.modify_config = lp_config_backend_is_registry();
906 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
907 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
909 werr = libnet_Unjoin(ctx, r);
910 if (!W_ERROR_IS_OK(werr)) {
911 d_printf("Failed to leave domain: %s\n",
912 r->out.error_string ? r->out.error_string :
913 get_friendly_werror_msg(werr));
914 goto done;
917 if (W_ERROR_IS_OK(werr)) {
918 d_printf("Deleted account for '%s' in realm '%s'\n",
919 r->in.machine_name, r->out.dns_domain_name);
920 goto done;
923 /* We couldn't delete it - see if the disable succeeded. */
924 if (r->out.disabled_machine_account) {
925 d_printf("Disabled account for '%s' in realm '%s'\n",
926 r->in.machine_name, r->out.dns_domain_name);
927 werr = WERR_OK;
928 goto done;
931 d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
932 r->in.machine_name, r->out.dns_domain_name);
934 done:
935 TALLOC_FREE(r);
936 TALLOC_FREE(ctx);
938 if (W_ERROR_IS_OK(werr)) {
939 return 0;
942 return -1;
945 static NTSTATUS net_ads_join_ok(struct net_context *c)
947 ADS_STRUCT *ads = NULL;
948 ADS_STATUS status;
950 if (!secrets_init()) {
951 DEBUG(1,("Failed to initialise secrets database\n"));
952 return NT_STATUS_ACCESS_DENIED;
955 set_cmdline_auth_info_use_machine_account(c->auth_info);
956 set_cmdline_auth_info_machine_account_creds(c->auth_info);
958 status = ads_startup(c, true, &ads);
959 if (!ADS_ERR_OK(status)) {
960 return ads_ntstatus(status);
963 ads_destroy(&ads);
964 return NT_STATUS_OK;
968 check that an existing join is OK
970 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
972 NTSTATUS status;
973 use_in_memory_ccache();
975 if (c->display_usage) {
976 d_printf("Usage:\n"
977 "net ads testjoin\n"
978 " Test if the existing join is ok\n");
979 return 0;
982 /* Display success or failure */
983 status = net_ads_join_ok(c);
984 if (!NT_STATUS_IS_OK(status)) {
985 fprintf(stderr,"Join to domain is not valid: %s\n",
986 get_friendly_nt_error_msg(status));
987 return -1;
990 printf("Join is OK\n");
991 return 0;
994 /*******************************************************************
995 Simple configu checks before beginning the join
996 ********************************************************************/
998 static WERROR check_ads_config( void )
1000 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1001 d_printf("Host is not configured as a member server.\n");
1002 return WERR_INVALID_DOMAIN_ROLE;
1005 if (strlen(global_myname()) > 15) {
1006 d_printf("Our netbios name can be at most 15 chars long, "
1007 "\"%s\" is %u chars long\n", global_myname(),
1008 (unsigned int)strlen(global_myname()));
1009 return WERR_INVALID_COMPUTERNAME;
1012 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1013 d_fprintf(stderr, "realm must be set in in %s for ADS "
1014 "join to succeed.\n", get_dyn_CONFIGFILE());
1015 return WERR_INVALID_PARAM;
1018 return WERR_OK;
1021 /*******************************************************************
1022 Send a DNS update request
1023 *******************************************************************/
1025 #if defined(WITH_DNS_UPDATES)
1026 #include "dns.h"
1027 DNS_ERROR DoDNSUpdate(char *pszServerName,
1028 const char *pszDomainName, const char *pszHostName,
1029 const struct sockaddr_storage *sslist,
1030 size_t num_addrs );
1032 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1033 const char *machine_name,
1034 const struct sockaddr_storage *addrs,
1035 int num_addrs)
1037 struct dns_rr_ns *nameservers = NULL;
1038 int ns_count = 0;
1039 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1040 DNS_ERROR dns_err;
1041 fstring dns_server;
1042 const char *dnsdomain = NULL;
1043 char *root_domain = NULL;
1045 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1046 d_printf("No DNS domain configured for %s. "
1047 "Unable to perform DNS Update.\n", machine_name);
1048 status = NT_STATUS_INVALID_PARAMETER;
1049 goto done;
1051 dnsdomain++;
1053 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1054 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1055 /* Child domains often do not have NS records. Look
1056 for the NS record for the forest root domain
1057 (rootDomainNamingContext in therootDSE) */
1059 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1060 LDAPMessage *msg = NULL;
1061 char *root_dn;
1062 ADS_STATUS ads_status;
1064 if ( !ads->ldap.ld ) {
1065 ads_status = ads_connect( ads );
1066 if ( !ADS_ERR_OK(ads_status) ) {
1067 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1068 goto done;
1072 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1073 "(objectclass=*)", rootname_attrs, &msg);
1074 if (!ADS_ERR_OK(ads_status)) {
1075 goto done;
1078 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1079 if ( !root_dn ) {
1080 ads_msgfree( ads, msg );
1081 goto done;
1084 root_domain = ads_build_domain( root_dn );
1086 /* cleanup */
1087 ads_msgfree( ads, msg );
1089 /* try again for NS servers */
1091 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1093 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1094 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1095 "realm\n", ads->config.realm));
1096 goto done;
1099 dnsdomain = root_domain;
1103 /* Now perform the dns update - we'll try non-secure and if we fail,
1104 we'll follow it up with a secure update */
1106 fstrcpy( dns_server, nameservers[0].hostname );
1108 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1109 if (!ERR_DNS_IS_OK(dns_err)) {
1110 status = NT_STATUS_UNSUCCESSFUL;
1113 done:
1115 SAFE_FREE( root_domain );
1117 return status;
1120 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1122 int num_addrs;
1123 struct sockaddr_storage *iplist = NULL;
1124 fstring machine_name;
1125 NTSTATUS status;
1127 name_to_fqdn( machine_name, global_myname() );
1128 strlower_m( machine_name );
1130 /* Get our ip address (not the 127.0.0.x address but a real ip
1131 * address) */
1133 num_addrs = get_my_ip_address( &iplist );
1134 if ( num_addrs <= 0 ) {
1135 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1136 "addresses!\n"));
1137 return NT_STATUS_INVALID_PARAMETER;
1140 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1141 iplist, num_addrs);
1142 SAFE_FREE( iplist );
1143 return status;
1145 #endif
1148 /*******************************************************************
1149 ********************************************************************/
1151 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1153 d_printf("net ads join [options]\n");
1154 d_printf("Valid options:\n");
1155 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1156 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1157 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1158 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1159 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1160 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1161 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1162 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1163 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1164 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1165 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1166 d_printf(" the two other attributes.\n");
1168 return -1;
1171 /*******************************************************************
1172 ********************************************************************/
1174 int net_ads_join(struct net_context *c, int argc, const char **argv)
1176 TALLOC_CTX *ctx = NULL;
1177 struct libnet_JoinCtx *r = NULL;
1178 const char *domain = lp_realm();
1179 WERROR werr = WERR_SETUP_NOT_JOINED;
1180 bool createupn = false;
1181 const char *machineupn = NULL;
1182 const char *create_in_ou = NULL;
1183 int i;
1184 const char *os_name = NULL;
1185 const char *os_version = NULL;
1186 bool modify_config = lp_config_backend_is_registry();
1187 struct user_auth_info *ai = c->auth_info;;
1189 if (c->display_usage)
1190 return net_ads_join_usage(c, argc, argv);
1192 if (!modify_config) {
1194 werr = check_ads_config();
1195 if (!W_ERROR_IS_OK(werr)) {
1196 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1197 goto fail;
1201 if (!(ctx = talloc_init("net_ads_join"))) {
1202 d_fprintf(stderr, "Could not initialise talloc context.\n");
1203 werr = WERR_NOMEM;
1204 goto fail;
1207 if (!get_cmdline_auth_info_use_kerberos(ai)) {
1208 use_in_memory_ccache();
1211 werr = libnet_init_JoinCtx(ctx, &r);
1212 if (!W_ERROR_IS_OK(werr)) {
1213 goto fail;
1216 /* process additional command line args */
1218 for ( i=0; i<argc; i++ ) {
1219 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1220 createupn = true;
1221 machineupn = get_string_param(argv[i]);
1223 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1224 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1225 d_fprintf(stderr, "Please supply a valid OU path.\n");
1226 werr = WERR_INVALID_PARAM;
1227 goto fail;
1230 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1231 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1232 d_fprintf(stderr, "Please supply a operating system name.\n");
1233 werr = WERR_INVALID_PARAM;
1234 goto fail;
1237 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1238 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1239 d_fprintf(stderr, "Please supply a valid operating system version.\n");
1240 werr = WERR_INVALID_PARAM;
1241 goto fail;
1244 else {
1245 domain = argv[i];
1249 if (!*domain) {
1250 d_fprintf(stderr, "Please supply a valid domain name\n");
1251 werr = WERR_INVALID_PARAM;
1252 goto fail;
1255 /* Do the domain join here */
1257 set_cmdline_auth_info_getpass(ai);
1259 r->in.domain_name = domain;
1260 r->in.create_upn = createupn;
1261 r->in.upn = machineupn;
1262 r->in.account_ou = create_in_ou;
1263 r->in.os_name = os_name;
1264 r->in.os_version = os_version;
1265 r->in.dc_name = c->opt_host;
1266 r->in.admin_account = get_cmdline_auth_info_username(ai);
1267 r->in.admin_password = get_cmdline_auth_info_password(ai);
1268 r->in.debug = true;
1269 r->in.use_kerberos = get_cmdline_auth_info_use_kerberos(ai);
1270 r->in.modify_config = modify_config;
1271 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1272 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1273 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1275 werr = libnet_Join(ctx, r);
1276 if (!W_ERROR_IS_OK(werr)) {
1277 goto fail;
1280 /* Check the short name of the domain */
1282 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1283 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1284 d_printf("domain name obtained from the server.\n");
1285 d_printf("Using the name [%s] from the server.\n", r->out.netbios_domain_name);
1286 d_printf("You should set \"workgroup = %s\" in %s.\n",
1287 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1290 d_printf("Using short domain name -- %s\n", r->out.netbios_domain_name);
1292 if (r->out.dns_domain_name) {
1293 d_printf("Joined '%s' to realm '%s'\n", r->in.machine_name,
1294 r->out.dns_domain_name);
1295 } else {
1296 d_printf("Joined '%s' to domain '%s'\n", r->in.machine_name,
1297 r->out.netbios_domain_name);
1300 #if defined(WITH_DNS_UPDATES)
1301 if (r->out.domain_is_ad) {
1302 /* We enter this block with user creds */
1303 ADS_STRUCT *ads_dns = NULL;
1305 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1306 /* kinit with the machine password */
1308 use_in_memory_ccache();
1309 if (asprintf( &ads_dns->auth.user_name, "%s$", global_myname()) == -1) {
1310 goto fail;
1312 ads_dns->auth.password = secrets_fetch_machine_password(
1313 r->out.netbios_domain_name, NULL, NULL );
1314 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1315 strupper_m(ads_dns->auth.realm );
1316 ads_kinit_password( ads_dns );
1319 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1320 d_fprintf( stderr, "DNS update failed!\n" );
1323 /* exit from this block using machine creds */
1324 ads_destroy(&ads_dns);
1326 #endif
1327 TALLOC_FREE(r);
1328 TALLOC_FREE( ctx );
1330 return 0;
1332 fail:
1333 /* issue an overall failure message at the end. */
1334 d_printf("Failed to join domain: %s\n",
1335 r && r->out.error_string ? r->out.error_string :
1336 get_friendly_werror_msg(werr));
1337 TALLOC_FREE( ctx );
1339 return -1;
1342 /*******************************************************************
1343 ********************************************************************/
1345 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1347 #if defined(WITH_DNS_UPDATES)
1348 ADS_STRUCT *ads;
1349 ADS_STATUS status;
1350 TALLOC_CTX *ctx;
1352 #ifdef DEVELOPER
1353 talloc_enable_leak_report();
1354 #endif
1356 if (argc > 0 || c->display_usage) {
1357 d_printf("Usage:\n"
1358 "net ads dns register\n"
1359 " Register hostname with DNS\n");
1360 return -1;
1363 if (!(ctx = talloc_init("net_ads_dns"))) {
1364 d_fprintf(stderr, "Could not initialise talloc context\n");
1365 return -1;
1368 status = ads_startup(c, true, &ads);
1369 if ( !ADS_ERR_OK(status) ) {
1370 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1371 TALLOC_FREE(ctx);
1372 return -1;
1375 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1376 d_fprintf( stderr, "DNS update failed!\n" );
1377 ads_destroy( &ads );
1378 TALLOC_FREE( ctx );
1379 return -1;
1382 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1384 ads_destroy(&ads);
1385 TALLOC_FREE( ctx );
1387 return 0;
1388 #else
1389 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1390 return -1;
1391 #endif
1394 #if defined(WITH_DNS_UPDATES)
1395 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1396 #endif
1398 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1400 #if defined(WITH_DNS_UPDATES)
1401 DNS_ERROR err;
1403 #ifdef DEVELOPER
1404 talloc_enable_leak_report();
1405 #endif
1407 if (argc != 2 || c->display_usage) {
1408 d_printf("Usage:\n"
1409 "net ads dns gethostbyname <server> <name>\n"
1410 " Look up hostname from the AD\n"
1411 " server\tName server to use\n"
1412 " name\tName to look up\n");
1413 return -1;
1416 err = do_gethostbyname(argv[0], argv[1]);
1418 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1419 #endif
1420 return 0;
1423 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1425 struct functable func[] = {
1427 "register",
1428 net_ads_dns_register,
1429 NET_TRANSPORT_ADS,
1430 "Add host dns entry to AD",
1431 "net ads dns register\n"
1432 " Add host dns entry to AD"
1435 "gethostbyname",
1436 net_ads_dns_gethostbyname,
1437 NET_TRANSPORT_ADS,
1438 "Look up host",
1439 "net ads dns gethostbyname\n"
1440 " Look up host"
1442 {NULL, NULL, 0, NULL, NULL}
1445 return net_run_function(c, argc, argv, "net ads dns", func);
1448 /*******************************************************************
1449 ********************************************************************/
1451 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1453 d_printf(
1454 "\nnet ads printer search <printer>"
1455 "\n\tsearch for a printer in the directory\n"
1456 "\nnet ads printer info <printer> <server>"
1457 "\n\tlookup info in directory for printer on server"
1458 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1459 "\nnet ads printer publish <printername>"
1460 "\n\tpublish printer in directory"
1461 "\n\t(note: printer name is required)\n"
1462 "\nnet ads printer remove <printername>"
1463 "\n\tremove printer from directory"
1464 "\n\t(note: printer name is required)\n");
1465 return -1;
1468 /*******************************************************************
1469 ********************************************************************/
1471 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1473 ADS_STRUCT *ads;
1474 ADS_STATUS rc;
1475 LDAPMessage *res = NULL;
1477 if (c->display_usage) {
1478 d_printf("Usage:\n"
1479 "net ads printer search\n"
1480 " List printers in the AD\n");
1481 return 0;
1484 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1485 return -1;
1488 rc = ads_find_printers(ads, &res);
1490 if (!ADS_ERR_OK(rc)) {
1491 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1492 ads_msgfree(ads, res);
1493 ads_destroy(&ads);
1494 return -1;
1497 if (ads_count_replies(ads, res) == 0) {
1498 d_fprintf(stderr, "No results found\n");
1499 ads_msgfree(ads, res);
1500 ads_destroy(&ads);
1501 return -1;
1504 ads_dump(ads, res);
1505 ads_msgfree(ads, res);
1506 ads_destroy(&ads);
1507 return 0;
1510 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1512 ADS_STRUCT *ads;
1513 ADS_STATUS rc;
1514 const char *servername, *printername;
1515 LDAPMessage *res = NULL;
1517 if (c->display_usage) {
1518 d_printf("Usage:\n"
1519 "net ads printer info [printername [servername]]\n"
1520 " Display printer info from AD\n"
1521 " printername\tPrinter name or wildcard\n"
1522 " servername\tName of the print server\n");
1523 return 0;
1526 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1527 return -1;
1530 if (argc > 0) {
1531 printername = argv[0];
1532 } else {
1533 printername = "*";
1536 if (argc > 1) {
1537 servername = argv[1];
1538 } else {
1539 servername = global_myname();
1542 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1544 if (!ADS_ERR_OK(rc)) {
1545 d_fprintf(stderr, "Server '%s' not found: %s\n",
1546 servername, ads_errstr(rc));
1547 ads_msgfree(ads, res);
1548 ads_destroy(&ads);
1549 return -1;
1552 if (ads_count_replies(ads, res) == 0) {
1553 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1554 ads_msgfree(ads, res);
1555 ads_destroy(&ads);
1556 return -1;
1559 ads_dump(ads, res);
1560 ads_msgfree(ads, res);
1561 ads_destroy(&ads);
1563 return 0;
1566 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1568 ADS_STRUCT *ads;
1569 ADS_STATUS rc;
1570 const char *servername, *printername;
1571 struct cli_state *cli;
1572 struct rpc_pipe_client *pipe_hnd;
1573 struct sockaddr_storage server_ss;
1574 NTSTATUS nt_status;
1575 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1576 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1577 char *prt_dn, *srv_dn, **srv_cn;
1578 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1579 LDAPMessage *res = NULL;
1580 struct user_auth_info *ai = c->auth_info;
1582 if (argc < 1 || c->display_usage) {
1583 d_printf("Usage:\n"
1584 "net ads printer publish <printername> [servername]\n"
1585 " Publish printer in AD\n"
1586 " printername\tName of the printer\n"
1587 " servername\tName of the print server\n");
1588 talloc_destroy(mem_ctx);
1589 return -1;
1592 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1593 talloc_destroy(mem_ctx);
1594 return -1;
1597 printername = argv[0];
1599 if (argc == 2) {
1600 servername = argv[1];
1601 } else {
1602 servername = global_myname();
1605 /* Get printer data from SPOOLSS */
1607 resolve_name(servername, &server_ss, 0x20);
1609 nt_status = cli_full_connection(&cli, global_myname(), servername,
1610 &server_ss, 0,
1611 "IPC$", "IPC",
1612 get_cmdline_auth_info_username(ai),
1613 c->opt_workgroup,
1614 get_cmdline_auth_info_password(ai),
1615 CLI_FULL_CONNECTION_USE_KERBEROS,
1616 Undefined, NULL);
1618 if (NT_STATUS_IS_ERR(nt_status)) {
1619 d_fprintf(stderr, "Unable to open a connnection to %s to obtain data "
1620 "for %s\n", servername, printername);
1621 ads_destroy(&ads);
1622 talloc_destroy(mem_ctx);
1623 return -1;
1626 /* Publish on AD server */
1628 ads_find_machine_acct(ads, &res, servername);
1630 if (ads_count_replies(ads, res) == 0) {
1631 d_fprintf(stderr, "Could not find machine account for server %s\n",
1632 servername);
1633 ads_destroy(&ads);
1634 talloc_destroy(mem_ctx);
1635 return -1;
1638 srv_dn = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res);
1639 srv_cn = ldap_explode_dn(srv_dn, 1);
1641 srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn[0]);
1642 printername_escaped = escape_rdn_val_string_alloc(printername);
1643 if (!srv_cn_escaped || !printername_escaped) {
1644 SAFE_FREE(srv_cn_escaped);
1645 SAFE_FREE(printername_escaped);
1646 d_fprintf(stderr, "Internal error, out of memory!");
1647 ads_destroy(&ads);
1648 talloc_destroy(mem_ctx);
1649 return -1;
1652 if (asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, printername_escaped, srv_dn) == -1) {
1653 SAFE_FREE(srv_cn_escaped);
1654 SAFE_FREE(printername_escaped);
1655 d_fprintf(stderr, "Internal error, out of memory!");
1656 ads_destroy(&ads);
1657 talloc_destroy(mem_ctx);
1658 return -1;
1661 SAFE_FREE(srv_cn_escaped);
1662 SAFE_FREE(printername_escaped);
1664 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_spoolss.syntax_id, &pipe_hnd);
1665 if (!NT_STATUS_IS_OK(nt_status)) {
1666 d_fprintf(stderr, "Unable to open a connnection to the spoolss pipe on %s\n",
1667 servername);
1668 SAFE_FREE(prt_dn);
1669 ads_destroy(&ads);
1670 talloc_destroy(mem_ctx);
1671 return -1;
1674 if (!W_ERROR_IS_OK(get_remote_printer_publishing_data(pipe_hnd, mem_ctx, &mods,
1675 printername))) {
1676 SAFE_FREE(prt_dn);
1677 ads_destroy(&ads);
1678 talloc_destroy(mem_ctx);
1679 return -1;
1682 rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods);
1683 if (!ADS_ERR_OK(rc)) {
1684 d_fprintf(stderr, "ads_publish_printer: %s\n", ads_errstr(rc));
1685 SAFE_FREE(prt_dn);
1686 ads_destroy(&ads);
1687 talloc_destroy(mem_ctx);
1688 return -1;
1691 d_printf("published printer\n");
1692 SAFE_FREE(prt_dn);
1693 ads_destroy(&ads);
1694 talloc_destroy(mem_ctx);
1696 return 0;
1699 static int net_ads_printer_remove(struct net_context *c, int argc, const char **argv)
1701 ADS_STRUCT *ads;
1702 ADS_STATUS rc;
1703 const char *servername;
1704 char *prt_dn;
1705 LDAPMessage *res = NULL;
1707 if (argc < 1 || c->display_usage) {
1708 d_printf("Usage:\n"
1709 "net ads printer remove <printername> [servername]\n"
1710 " Remove a printer from the AD\n"
1711 " printername\tName of the printer\n"
1712 " servername\tName of the print server\n");
1713 return -1;
1716 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1717 return -1;
1720 if (argc > 1) {
1721 servername = argv[1];
1722 } else {
1723 servername = global_myname();
1726 rc = ads_find_printer_on_server(ads, &res, argv[0], servername);
1728 if (!ADS_ERR_OK(rc)) {
1729 d_fprintf(stderr, "ads_find_printer_on_server: %s\n", ads_errstr(rc));
1730 ads_msgfree(ads, res);
1731 ads_destroy(&ads);
1732 return -1;
1735 if (ads_count_replies(ads, res) == 0) {
1736 d_fprintf(stderr, "Printer '%s' not found\n", argv[1]);
1737 ads_msgfree(ads, res);
1738 ads_destroy(&ads);
1739 return -1;
1742 prt_dn = ads_get_dn(ads, talloc_tos(), res);
1743 ads_msgfree(ads, res);
1744 rc = ads_del_dn(ads, prt_dn);
1745 TALLOC_FREE(prt_dn);
1747 if (!ADS_ERR_OK(rc)) {
1748 d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc));
1749 ads_destroy(&ads);
1750 return -1;
1753 ads_destroy(&ads);
1754 return 0;
1757 static int net_ads_printer(struct net_context *c, int argc, const char **argv)
1759 struct functable func[] = {
1761 "search",
1762 net_ads_printer_search,
1763 NET_TRANSPORT_ADS,
1764 "Search for a printer",
1765 "net ads printer search\n"
1766 " Search for a printer"
1769 "info",
1770 net_ads_printer_info,
1771 NET_TRANSPORT_ADS,
1772 "Display printer information",
1773 "net ads printer info\n"
1774 " Display printer information"
1777 "publish",
1778 net_ads_printer_publish,
1779 NET_TRANSPORT_ADS,
1780 "Publish a printer",
1781 "net ads printer publish\n"
1782 " Publish a printer"
1785 "remove",
1786 net_ads_printer_remove,
1787 NET_TRANSPORT_ADS,
1788 "Delete a printer",
1789 "net ads printer remove\n"
1790 " Delete a printer"
1792 {NULL, NULL, 0, NULL, NULL}
1795 return net_run_function(c, argc, argv, "net ads printer", func);
1799 static int net_ads_password(struct net_context *c, int argc, const char **argv)
1801 ADS_STRUCT *ads;
1802 const char *auth_principal;
1803 const char *auth_password;
1804 char *realm = NULL;
1805 char *new_password = NULL;
1806 char *chr, *prompt;
1807 const char *user;
1808 ADS_STATUS ret;
1810 if (c->display_usage) {
1811 d_printf("Usage:\n"
1812 "net ads password <username>\n"
1813 " Change password for user\n"
1814 " username\tName of user to change password for\n");
1815 return 0;
1818 auth_principal = get_cmdline_auth_info_username(c->auth_info);
1819 set_cmdline_auth_info_getpass(c->auth_info);
1820 auth_password = get_cmdline_auth_info_password(c->auth_info);
1822 if (argc < 1) {
1823 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1824 return -1;
1827 user = argv[0];
1828 if (!strchr_m(user, '@')) {
1829 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
1830 return -1;
1832 user = chr;
1835 use_in_memory_ccache();
1836 chr = strchr_m(auth_principal, '@');
1837 if (chr) {
1838 realm = ++chr;
1839 } else {
1840 realm = lp_realm();
1843 /* use the realm so we can eventually change passwords for users
1844 in realms other than default */
1845 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1846 return -1;
1849 /* we don't actually need a full connect, but it's the easy way to
1850 fill in the KDC's addresss */
1851 ads_connect(ads);
1853 if (!ads->config.realm) {
1854 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1855 ads_destroy(&ads);
1856 return -1;
1859 if (argv[1]) {
1860 new_password = (char *)argv[1];
1861 } else {
1862 if (asprintf(&prompt, "Enter new password for %s:", user) == -1) {
1863 return -1;
1865 new_password = getpass(prompt);
1866 free(prompt);
1869 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1870 auth_password, user, new_password, ads->auth.time_offset);
1871 if (!ADS_ERR_OK(ret)) {
1872 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1873 ads_destroy(&ads);
1874 return -1;
1877 d_printf("Password change for %s completed.\n", user);
1878 ads_destroy(&ads);
1880 return 0;
1883 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1885 ADS_STRUCT *ads;
1886 char *host_principal;
1887 fstring my_name;
1888 ADS_STATUS ret;
1890 if (c->display_usage) {
1891 d_printf("Usage:\n"
1892 "net ads changetrustpw\n"
1893 " Change the machine account's trust password\n");
1894 return 0;
1897 if (!secrets_init()) {
1898 DEBUG(1,("Failed to initialise secrets database\n"));
1899 return -1;
1902 set_cmdline_auth_info_use_machine_account(c->auth_info);
1904 use_in_memory_ccache();
1906 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1907 return -1;
1910 fstrcpy(my_name, global_myname());
1911 strlower_m(my_name);
1912 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
1913 ads_destroy(&ads);
1914 return -1;
1916 d_printf("Changing password for principal: %s\n", host_principal);
1918 ret = ads_change_trust_account_password(ads, host_principal);
1920 if (!ADS_ERR_OK(ret)) {
1921 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1922 ads_destroy(&ads);
1923 SAFE_FREE(host_principal);
1924 return -1;
1927 d_printf("Password change for principal %s succeeded.\n", host_principal);
1929 if (USE_SYSTEM_KEYTAB) {
1930 d_printf("Attempting to update system keytab with new password.\n");
1931 if (ads_keytab_create_default(ads)) {
1932 d_printf("Failed to update system keytab.\n");
1936 ads_destroy(&ads);
1937 SAFE_FREE(host_principal);
1939 return 0;
1943 help for net ads search
1945 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
1947 d_printf(
1948 "\nnet ads search <expression> <attributes...>\n"
1949 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
1950 "The expression is a standard LDAP search expression, and the\n"
1951 "attributes are a list of LDAP fields to show in the results.\n\n"
1952 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1954 net_common_flags_usage(c, argc, argv);
1955 return -1;
1960 general ADS search function. Useful in diagnosing problems in ADS
1962 static int net_ads_search(struct net_context *c, int argc, const char **argv)
1964 ADS_STRUCT *ads;
1965 ADS_STATUS rc;
1966 const char *ldap_exp;
1967 const char **attrs;
1968 LDAPMessage *res = NULL;
1970 if (argc < 1 || c->display_usage) {
1971 return net_ads_search_usage(c, argc, argv);
1974 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1975 return -1;
1978 ldap_exp = argv[0];
1979 attrs = (argv + 1);
1981 rc = ads_do_search_all(ads, ads->config.bind_path,
1982 LDAP_SCOPE_SUBTREE,
1983 ldap_exp, attrs, &res);
1984 if (!ADS_ERR_OK(rc)) {
1985 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1986 ads_destroy(&ads);
1987 return -1;
1990 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1992 /* dump the results */
1993 ads_dump(ads, res);
1995 ads_msgfree(ads, res);
1996 ads_destroy(&ads);
1998 return 0;
2003 help for net ads search
2005 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2007 d_printf(
2008 "\nnet ads dn <dn> <attributes...>\n"
2009 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2010 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2011 "to show in the results\n\n"
2012 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2013 "Note: the DN must be provided properly escaped. See RFC 4514 for details\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_dn(struct net_context *c, int argc, const char **argv)
2025 ADS_STRUCT *ads;
2026 ADS_STATUS rc;
2027 const char *dn;
2028 const char **attrs;
2029 LDAPMessage *res = NULL;
2031 if (argc < 1 || c->display_usage) {
2032 return net_ads_dn_usage(c, argc, argv);
2035 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2036 return -1;
2039 dn = argv[0];
2040 attrs = (argv + 1);
2042 rc = ads_do_search_all(ads, dn,
2043 LDAP_SCOPE_BASE,
2044 "(objectclass=*)", 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;
2063 help for net ads sid search
2065 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2067 d_printf(
2068 "\nnet ads sid <sid> <attributes...>\n"
2069 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2070 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2071 "to show in the results\n\n"
2072 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2074 net_common_flags_usage(c, argc, argv);
2075 return -1;
2080 general ADS search function. Useful in diagnosing problems in ADS
2082 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2084 ADS_STRUCT *ads;
2085 ADS_STATUS rc;
2086 const char *sid_string;
2087 const char **attrs;
2088 LDAPMessage *res = NULL;
2089 DOM_SID sid;
2091 if (argc < 1 || c->display_usage) {
2092 return net_ads_sid_usage(c, argc, argv);
2095 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2096 return -1;
2099 sid_string = argv[0];
2100 attrs = (argv + 1);
2102 if (!string_to_sid(&sid, sid_string)) {
2103 d_fprintf(stderr, "could not convert sid\n");
2104 ads_destroy(&ads);
2105 return -1;
2108 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2109 if (!ADS_ERR_OK(rc)) {
2110 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2111 ads_destroy(&ads);
2112 return -1;
2115 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2117 /* dump the results */
2118 ads_dump(ads, res);
2120 ads_msgfree(ads, res);
2121 ads_destroy(&ads);
2123 return 0;
2126 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2128 int ret;
2129 ADS_STRUCT *ads;
2131 if (c->display_usage) {
2132 d_printf("Usage:\n"
2133 "net ads keytab flush\n"
2134 " Delete the whole keytab\n");
2135 return 0;
2138 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2139 return -1;
2141 ret = ads_keytab_flush(ads);
2142 ads_destroy(&ads);
2143 return ret;
2146 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2148 int i;
2149 int ret = 0;
2150 ADS_STRUCT *ads;
2152 if (c->display_usage) {
2153 d_printf("Usage:\n"
2154 "net ads keytab add <principal> [principal ...]\n"
2155 " Add principals to local keytab\n"
2156 " principal\tKerberos principal to add to "
2157 "keytab\n");
2158 return 0;
2161 d_printf("Processing principals to add...\n");
2162 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2163 return -1;
2165 for (i = 0; i < argc; i++) {
2166 ret |= ads_keytab_add_entry(ads, argv[i]);
2168 ads_destroy(&ads);
2169 return ret;
2172 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2174 ADS_STRUCT *ads;
2175 int ret;
2177 if (c->display_usage) {
2178 d_printf("Usage:\n"
2179 "net ads keytab create\n"
2180 " Create new default keytab\n");
2181 return 0;
2184 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2185 return -1;
2187 ret = ads_keytab_create_default(ads);
2188 ads_destroy(&ads);
2189 return ret;
2192 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2194 const char *keytab = NULL;
2196 if (c->display_usage) {
2197 d_printf("Usage:\n"
2198 "net ads keytab list [keytab]\n"
2199 " List a local keytab\n"
2200 " keytab\tKeytab to list\n");
2201 return 0;
2204 if (argc >= 1) {
2205 keytab = argv[0];
2208 return ads_keytab_list(keytab);
2212 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2214 struct functable func[] = {
2216 "add",
2217 net_ads_keytab_add,
2218 NET_TRANSPORT_ADS,
2219 "Add a service principal",
2220 "net ads keytab add\n"
2221 " Add a service principal"
2224 "create",
2225 net_ads_keytab_create,
2226 NET_TRANSPORT_ADS,
2227 "Create a fresh keytab",
2228 "net ads keytab create\n"
2229 " Create a fresh keytab"
2232 "flush",
2233 net_ads_keytab_flush,
2234 NET_TRANSPORT_ADS,
2235 "Remove all keytab entries",
2236 "net ads keytab flush\n"
2237 " Remove all keytab entries"
2240 "list",
2241 net_ads_keytab_list,
2242 NET_TRANSPORT_ADS,
2243 "List a keytab",
2244 "net ads keytab list\n"
2245 " List a keytab"
2247 {NULL, NULL, 0, NULL, NULL}
2250 if (!USE_KERBEROS_KEYTAB) {
2251 d_printf("\nWarning: \"kerberos method\" must be set to a "
2252 "keytab method to use keytab functions.\n");
2255 return net_run_function(c, argc, argv, "net ads keytab", func);
2258 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2260 int ret = -1;
2262 if (c->display_usage) {
2263 d_printf("Usage:\n"
2264 "net ads kerberos renew\n"
2265 " Renew TGT from existing credential cache\n");
2266 return 0;
2269 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2270 if (ret) {
2271 d_printf("failed to renew kerberos ticket: %s\n",
2272 error_message(ret));
2274 return ret;
2277 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2279 struct PAC_DATA *pac = NULL;
2280 struct PAC_LOGON_INFO *info = NULL;
2281 TALLOC_CTX *mem_ctx = NULL;
2282 NTSTATUS status;
2283 int ret = -1;
2284 struct user_auth_info *ai = c->auth_info;
2286 if (c->display_usage) {
2287 d_printf("Usage:\n"
2288 "net ads kerberos pac\n"
2289 " Dump the Kerberos PAC\n");
2290 return 0;
2293 mem_ctx = talloc_init("net_ads_kerberos_pac");
2294 if (!mem_ctx) {
2295 goto out;
2298 set_cmdline_auth_info_getpass(ai);
2300 status = kerberos_return_pac(mem_ctx,
2301 get_cmdline_auth_info_username(ai),
2302 get_cmdline_auth_info_password(ai),
2304 NULL,
2305 NULL,
2306 NULL,
2307 true,
2308 true,
2309 2592000, /* one month */
2310 &pac);
2311 if (!NT_STATUS_IS_OK(status)) {
2312 d_printf("failed to query kerberos PAC: %s\n",
2313 nt_errstr(status));
2314 goto out;
2317 info = get_logon_info_from_pac(pac);
2318 if (info) {
2319 const char *s;
2320 s = NDR_PRINT_STRUCT_STRING(mem_ctx, PAC_LOGON_INFO, info);
2321 d_printf("The Pac: %s\n", s);
2324 ret = 0;
2325 out:
2326 TALLOC_FREE(mem_ctx);
2327 return ret;
2330 static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char **argv)
2332 TALLOC_CTX *mem_ctx = NULL;
2333 int ret = -1;
2334 NTSTATUS status;
2335 struct user_auth_info *ai = c->auth_info;
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 set_cmdline_auth_info_getpass(ai);
2351 ret = kerberos_kinit_password_ext(get_cmdline_auth_info_username(ai),
2352 get_cmdline_auth_info_password(ai),
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 */