net: Only use the in memory ccache when not already using a kerberos ticket in net ads
[Samba/gebeck_regimport.git] / source3 / utils / net_ads.c
blob38b59d9cdfd59238e1fe7b167e4adc0e8d3bb1de
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 !get_cmdline_auth_info_use_kerberos(c->auth_info)) {
241 use_in_memory_ccache();
242 SAFE_FREE(ads->auth.password);
243 ads->auth.password = smb_xstrdup(
244 get_cmdline_auth_info_password(c->auth_info));
247 ads->auth.flags |= auth_flags;
248 SAFE_FREE(ads->auth.user_name);
249 ads->auth.user_name = smb_xstrdup(
250 get_cmdline_auth_info_username(c->auth_info));
253 * If the username is of the form "name@realm",
254 * extract the realm and convert to upper case.
255 * This is only used to establish the connection.
257 if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
258 *cp++ = '\0';
259 SAFE_FREE(ads->auth.realm);
260 ads->auth.realm = smb_xstrdup(cp);
261 strupper_m(ads->auth.realm);
264 status = ads_connect(ads);
266 if (!ADS_ERR_OK(status)) {
268 if (NT_STATUS_EQUAL(ads_ntstatus(status),
269 NT_STATUS_NO_LOGON_SERVERS)) {
270 DEBUG(0,("ads_connect: %s\n", ads_errstr(status)));
271 ads_destroy(&ads);
272 return status;
275 if (!need_password && !second_time && !(auth_flags & ADS_AUTH_NO_BIND)) {
276 need_password = true;
277 second_time = true;
278 goto retry;
279 } else {
280 ads_destroy(&ads);
281 return status;
285 /* when contacting our own domain, make sure we use the closest DC.
286 * This is done by reconnecting to ADS because only the first call to
287 * ads_connect will give us our own sitename */
289 if ((only_own_domain || !c->opt_host) && !tried_closest_dc) {
291 tried_closest_dc = true; /* avoid loop */
293 if (!ads_closest_dc(ads)) {
295 namecache_delete(ads->server.realm, 0x1C);
296 namecache_delete(ads->server.workgroup, 0x1C);
298 ads_destroy(&ads);
299 ads = NULL;
301 goto retry_connect;
305 *ads_ret = ads;
306 return status;
309 ADS_STATUS ads_startup(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
311 return ads_startup_int(c, only_own_domain, 0, ads);
314 ADS_STATUS ads_startup_nobind(struct net_context *c, bool only_own_domain, ADS_STRUCT **ads)
316 return ads_startup_int(c, only_own_domain, ADS_AUTH_NO_BIND, ads);
320 Check to see if connection can be made via ads.
321 ads_startup() stores the password in opt_password if it needs to so
322 that rpc or rap can use it without re-prompting.
324 static int net_ads_check_int(const char *realm, const char *workgroup, const char *host)
326 ADS_STRUCT *ads;
327 ADS_STATUS status;
329 if ( (ads = ads_init( realm, workgroup, host )) == NULL ) {
330 return -1;
333 ads->auth.flags |= ADS_AUTH_NO_BIND;
335 status = ads_connect(ads);
336 if ( !ADS_ERR_OK(status) ) {
337 return -1;
340 ads_destroy(&ads);
341 return 0;
344 int net_ads_check_our_domain(struct net_context *c)
346 return net_ads_check_int(lp_realm(), lp_workgroup(), NULL);
349 int net_ads_check(struct net_context *c)
351 return net_ads_check_int(NULL, c->opt_workgroup, c->opt_host);
355 determine the netbios workgroup name for a domain
357 static int net_ads_workgroup(struct net_context *c, int argc, const char **argv)
359 ADS_STRUCT *ads;
360 char addr[INET6_ADDRSTRLEN];
361 struct NETLOGON_SAM_LOGON_RESPONSE_EX reply;
363 if (c->display_usage) {
364 d_printf("Usage:\n"
365 "net ads workgroup\n"
366 " Print the workgroup name\n");
367 return 0;
370 if (!ADS_ERR_OK(ads_startup_nobind(c, false, &ads))) {
371 d_fprintf(stderr, "Didn't find the cldap server!\n");
372 return -1;
375 if (!ads->config.realm) {
376 ads->config.realm = CONST_DISCARD(char *, c->opt_target_workgroup);
377 ads->ldap.port = 389;
380 print_sockaddr(addr, sizeof(addr), &ads->ldap.ss);
381 if ( !ads_cldap_netlogon_5(talloc_tos(), addr, ads->server.realm, &reply ) ) {
382 d_fprintf(stderr, "CLDAP query failed!\n");
383 ads_destroy(&ads);
384 return -1;
387 d_printf("Workgroup: %s\n", reply.domain);
389 ads_destroy(&ads);
391 return 0;
396 static bool usergrp_display(ADS_STRUCT *ads, char *field, void **values, void *data_area)
398 char **disp_fields = (char **) data_area;
400 if (!field) { /* must be end of record */
401 if (disp_fields[0]) {
402 if (!strchr_m(disp_fields[0], '$')) {
403 if (disp_fields[1])
404 d_printf("%-21.21s %s\n",
405 disp_fields[0], disp_fields[1]);
406 else
407 d_printf("%s\n", disp_fields[0]);
410 SAFE_FREE(disp_fields[0]);
411 SAFE_FREE(disp_fields[1]);
412 return true;
414 if (!values) /* must be new field, indicate string field */
415 return true;
416 if (StrCaseCmp(field, "sAMAccountName") == 0) {
417 disp_fields[0] = SMB_STRDUP((char *) values[0]);
419 if (StrCaseCmp(field, "description") == 0)
420 disp_fields[1] = SMB_STRDUP((char *) values[0]);
421 return true;
424 static int net_ads_user_usage(struct net_context *c, int argc, const char **argv)
426 return net_user_usage(c, argc, argv);
429 static int ads_user_add(struct net_context *c, int argc, const char **argv)
431 ADS_STRUCT *ads;
432 ADS_STATUS status;
433 char *upn, *userdn;
434 LDAPMessage *res=NULL;
435 int rc = -1;
436 char *ou_str = NULL;
438 if (argc < 1 || c->display_usage)
439 return net_ads_user_usage(c, argc, argv);
441 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
442 return -1;
445 status = ads_find_user_acct(ads, &res, argv[0]);
447 if (!ADS_ERR_OK(status)) {
448 d_fprintf(stderr, "ads_user_add: %s\n", ads_errstr(status));
449 goto done;
452 if (ads_count_replies(ads, res)) {
453 d_fprintf(stderr, "ads_user_add: User %s already exists\n", argv[0]);
454 goto done;
457 if (c->opt_container) {
458 ou_str = SMB_STRDUP(c->opt_container);
459 } else {
460 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
463 status = ads_add_user_acct(ads, argv[0], ou_str, c->opt_comment);
465 if (!ADS_ERR_OK(status)) {
466 d_fprintf(stderr, "Could not add user %s: %s\n", argv[0],
467 ads_errstr(status));
468 goto done;
471 /* if no password is to be set, we're done */
472 if (argc == 1) {
473 d_printf("User %s added\n", argv[0]);
474 rc = 0;
475 goto done;
478 /* try setting the password */
479 if (asprintf(&upn, "%s@%s", argv[0], ads->config.realm) == -1) {
480 goto done;
482 status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1],
483 ads->auth.time_offset);
484 SAFE_FREE(upn);
485 if (ADS_ERR_OK(status)) {
486 d_printf("User %s added\n", argv[0]);
487 rc = 0;
488 goto done;
491 /* password didn't set, delete account */
492 d_fprintf(stderr, "Could not add user %s. Error setting password %s\n",
493 argv[0], ads_errstr(status));
494 ads_msgfree(ads, res);
495 status=ads_find_user_acct(ads, &res, argv[0]);
496 if (ADS_ERR_OK(status)) {
497 userdn = ads_get_dn(ads, talloc_tos(), res);
498 ads_del_dn(ads, userdn);
499 TALLOC_FREE(userdn);
502 done:
503 if (res)
504 ads_msgfree(ads, res);
505 ads_destroy(&ads);
506 SAFE_FREE(ou_str);
507 return rc;
510 static int ads_user_info(struct net_context *c, int argc, const char **argv)
512 ADS_STRUCT *ads;
513 ADS_STATUS rc;
514 LDAPMessage *res;
515 const char *attrs[] = {"memberOf", NULL};
516 char *searchstring=NULL;
517 char **grouplist;
518 char *escaped_user;
520 if (argc < 1 || c->display_usage) {
521 return net_ads_user_usage(c, argc, argv);
524 escaped_user = escape_ldap_string_alloc(argv[0]);
526 if (!escaped_user) {
527 d_fprintf(stderr, "ads_user_info: failed to escape user %s\n", argv[0]);
528 return -1;
531 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
532 SAFE_FREE(escaped_user);
533 return -1;
536 if (asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user) == -1) {
537 SAFE_FREE(escaped_user);
538 return -1;
540 rc = ads_search(ads, &res, searchstring, attrs);
541 SAFE_FREE(searchstring);
543 if (!ADS_ERR_OK(rc)) {
544 d_fprintf(stderr, "ads_search: %s\n", ads_errstr(rc));
545 ads_destroy(&ads);
546 SAFE_FREE(escaped_user);
547 return -1;
550 grouplist = ldap_get_values((LDAP *)ads->ldap.ld,
551 (LDAPMessage *)res, "memberOf");
553 if (grouplist) {
554 int i;
555 char **groupname;
556 for (i=0;grouplist[i];i++) {
557 groupname = ldap_explode_dn(grouplist[i], 1);
558 d_printf("%s\n", groupname[0]);
559 ldap_value_free(groupname);
561 ldap_value_free(grouplist);
564 ads_msgfree(ads, res);
565 ads_destroy(&ads);
566 SAFE_FREE(escaped_user);
567 return 0;
570 static int ads_user_delete(struct net_context *c, int argc, const char **argv)
572 ADS_STRUCT *ads;
573 ADS_STATUS rc;
574 LDAPMessage *res = NULL;
575 char *userdn;
577 if (argc < 1) {
578 return net_ads_user_usage(c, argc, argv);
581 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
582 return -1;
585 rc = ads_find_user_acct(ads, &res, argv[0]);
586 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
587 d_printf("User %s does not exist.\n", argv[0]);
588 ads_msgfree(ads, res);
589 ads_destroy(&ads);
590 return -1;
592 userdn = ads_get_dn(ads, talloc_tos(), res);
593 ads_msgfree(ads, res);
594 rc = ads_del_dn(ads, userdn);
595 TALLOC_FREE(userdn);
596 if (ADS_ERR_OK(rc)) {
597 d_printf("User %s deleted\n", argv[0]);
598 ads_destroy(&ads);
599 return 0;
601 d_fprintf(stderr, "Error deleting user %s: %s\n", argv[0],
602 ads_errstr(rc));
603 ads_destroy(&ads);
604 return -1;
607 int net_ads_user(struct net_context *c, int argc, const char **argv)
609 struct functable func[] = {
611 "add",
612 ads_user_add,
613 NET_TRANSPORT_ADS,
614 "Add an AD user",
615 "net ads user add\n"
616 " Add an AD user"
619 "info",
620 ads_user_info,
621 NET_TRANSPORT_ADS,
622 "Display information about an AD user",
623 "net ads user info\n"
624 " Display information about an AD user"
627 "delete",
628 ads_user_delete,
629 NET_TRANSPORT_ADS,
630 "Delete an AD user",
631 "net ads user delete\n"
632 " Delete an AD user"
634 {NULL, NULL, 0, NULL, NULL}
636 ADS_STRUCT *ads;
637 ADS_STATUS rc;
638 const char *shortattrs[] = {"sAMAccountName", NULL};
639 const char *longattrs[] = {"sAMAccountName", "description", NULL};
640 char *disp_fields[2] = {NULL, NULL};
642 if (argc == 0) {
643 if (c->display_usage) {
644 d_printf("Usage:\n");
645 d_printf("net ads user\n"
646 " List AD users\n");
647 net_display_usage_from_functable(func);
648 return 0;
651 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
652 return -1;
655 if (c->opt_long_list_entries)
656 d_printf("\nUser name Comment"
657 "\n-----------------------------\n");
659 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
660 LDAP_SCOPE_SUBTREE,
661 "(objectCategory=user)",
662 c->opt_long_list_entries ? longattrs :
663 shortattrs, usergrp_display,
664 disp_fields);
665 ads_destroy(&ads);
666 return ADS_ERR_OK(rc) ? 0 : -1;
669 return net_run_function(c, argc, argv, "net ads user", func);
672 static int net_ads_group_usage(struct net_context *c, int argc, const char **argv)
674 return net_group_usage(c, argc, argv);
677 static int ads_group_add(struct net_context *c, int argc, const char **argv)
679 ADS_STRUCT *ads;
680 ADS_STATUS status;
681 LDAPMessage *res=NULL;
682 int rc = -1;
683 char *ou_str = NULL;
685 if (argc < 1 || c->display_usage) {
686 return net_ads_group_usage(c, argc, argv);
689 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
690 return -1;
693 status = ads_find_user_acct(ads, &res, argv[0]);
695 if (!ADS_ERR_OK(status)) {
696 d_fprintf(stderr, "ads_group_add: %s\n", ads_errstr(status));
697 goto done;
700 if (ads_count_replies(ads, res)) {
701 d_fprintf(stderr, "ads_group_add: Group %s already exists\n", argv[0]);
702 goto done;
705 if (c->opt_container) {
706 ou_str = SMB_STRDUP(c->opt_container);
707 } else {
708 ou_str = ads_default_ou_string(ads, WELL_KNOWN_GUID_USERS);
711 status = ads_add_group_acct(ads, argv[0], ou_str, c->opt_comment);
713 if (ADS_ERR_OK(status)) {
714 d_printf("Group %s added\n", argv[0]);
715 rc = 0;
716 } else {
717 d_fprintf(stderr, "Could not add group %s: %s\n", argv[0],
718 ads_errstr(status));
721 done:
722 if (res)
723 ads_msgfree(ads, res);
724 ads_destroy(&ads);
725 SAFE_FREE(ou_str);
726 return rc;
729 static int ads_group_delete(struct net_context *c, int argc, const char **argv)
731 ADS_STRUCT *ads;
732 ADS_STATUS rc;
733 LDAPMessage *res = NULL;
734 char *groupdn;
736 if (argc < 1 || c->display_usage) {
737 return net_ads_group_usage(c, argc, argv);
740 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
741 return -1;
744 rc = ads_find_user_acct(ads, &res, argv[0]);
745 if (!ADS_ERR_OK(rc) || ads_count_replies(ads, res) != 1) {
746 d_printf("Group %s does not exist.\n", argv[0]);
747 ads_msgfree(ads, res);
748 ads_destroy(&ads);
749 return -1;
751 groupdn = ads_get_dn(ads, talloc_tos(), res);
752 ads_msgfree(ads, res);
753 rc = ads_del_dn(ads, groupdn);
754 TALLOC_FREE(groupdn);
755 if (ADS_ERR_OK(rc)) {
756 d_printf("Group %s deleted\n", argv[0]);
757 ads_destroy(&ads);
758 return 0;
760 d_fprintf(stderr, "Error deleting group %s: %s\n", argv[0],
761 ads_errstr(rc));
762 ads_destroy(&ads);
763 return -1;
766 int net_ads_group(struct net_context *c, int argc, const char **argv)
768 struct functable func[] = {
770 "add",
771 ads_group_add,
772 NET_TRANSPORT_ADS,
773 "Add an AD group",
774 "net ads group add\n"
775 " Add an AD group"
778 "delete",
779 ads_group_delete,
780 NET_TRANSPORT_ADS,
781 "Delete an AD group",
782 "net ads group delete\n"
783 " Delete an AD group"
785 {NULL, NULL, 0, NULL, NULL}
787 ADS_STRUCT *ads;
788 ADS_STATUS rc;
789 const char *shortattrs[] = {"sAMAccountName", NULL};
790 const char *longattrs[] = {"sAMAccountName", "description", NULL};
791 char *disp_fields[2] = {NULL, NULL};
793 if (argc == 0) {
794 if (c->display_usage) {
795 d_printf("Usage:\n");
796 d_printf("net ads group\n"
797 " List AD groups\n");
798 net_display_usage_from_functable(func);
799 return 0;
802 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
803 return -1;
806 if (c->opt_long_list_entries)
807 d_printf("\nGroup name Comment"
808 "\n-----------------------------\n");
809 rc = ads_do_search_all_fn(ads, ads->config.bind_path,
810 LDAP_SCOPE_SUBTREE,
811 "(objectCategory=group)",
812 c->opt_long_list_entries ? longattrs :
813 shortattrs, usergrp_display,
814 disp_fields);
816 ads_destroy(&ads);
817 return ADS_ERR_OK(rc) ? 0 : -1;
819 return net_run_function(c, argc, argv, "net ads group", func);
822 static int net_ads_status(struct net_context *c, int argc, const char **argv)
824 ADS_STRUCT *ads;
825 ADS_STATUS rc;
826 LDAPMessage *res;
828 if (c->display_usage) {
829 d_printf("Usage:\n"
830 "net ads status\n"
831 " Display machine account details\n");
832 return 0;
835 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
836 return -1;
839 rc = ads_find_machine_acct(ads, &res, global_myname());
840 if (!ADS_ERR_OK(rc)) {
841 d_fprintf(stderr, "ads_find_machine_acct: %s\n", ads_errstr(rc));
842 ads_destroy(&ads);
843 return -1;
846 if (ads_count_replies(ads, res) == 0) {
847 d_fprintf(stderr, "No machine account for '%s' found\n", global_myname());
848 ads_destroy(&ads);
849 return -1;
852 ads_dump(ads, res);
853 ads_destroy(&ads);
854 return 0;
857 /*******************************************************************
858 Leave an AD domain. Windows XP disables the machine account.
859 We'll try the same. The old code would do an LDAP delete.
860 That only worked using the machine creds because added the machine
861 with full control to the computer object's ACL.
862 *******************************************************************/
864 static int net_ads_leave(struct net_context *c, int argc, const char **argv)
866 TALLOC_CTX *ctx;
867 struct libnet_UnjoinCtx *r = NULL;
868 WERROR werr;
869 struct user_auth_info *ai = c->auth_info;
871 if (c->display_usage) {
872 d_printf("Usage:\n"
873 "net ads leave\n"
874 " Leave an AD domain\n");
875 return 0;
878 if (!*lp_realm()) {
879 d_fprintf(stderr, "No realm set, are we joined ?\n");
880 return -1;
883 if (!(ctx = talloc_init("net_ads_leave"))) {
884 d_fprintf(stderr, "Could not initialise talloc context.\n");
885 return -1;
888 if (!get_cmdline_auth_info_use_kerberos(ai)) {
889 use_in_memory_ccache();
892 werr = libnet_init_UnjoinCtx(ctx, &r);
893 if (!W_ERROR_IS_OK(werr)) {
894 d_fprintf(stderr, "Could not initialise unjoin context.\n");
895 return -1;
898 set_cmdline_auth_info_getpass(ai);
900 r->in.debug = true;
901 r->in.use_kerberos = get_cmdline_auth_info_use_kerberos(ai);
902 r->in.dc_name = c->opt_host;
903 r->in.domain_name = lp_realm();
904 r->in.admin_account = get_cmdline_auth_info_username(ai);
905 r->in.admin_password = get_cmdline_auth_info_password(ai);
906 r->in.modify_config = lp_config_backend_is_registry();
907 r->in.unjoin_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
908 WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE;
910 werr = libnet_Unjoin(ctx, r);
911 if (!W_ERROR_IS_OK(werr)) {
912 d_printf("Failed to leave domain: %s\n",
913 r->out.error_string ? r->out.error_string :
914 get_friendly_werror_msg(werr));
915 goto done;
918 if (W_ERROR_IS_OK(werr)) {
919 d_printf("Deleted account for '%s' in realm '%s'\n",
920 r->in.machine_name, r->out.dns_domain_name);
921 goto done;
924 /* We couldn't delete it - see if the disable succeeded. */
925 if (r->out.disabled_machine_account) {
926 d_printf("Disabled account for '%s' in realm '%s'\n",
927 r->in.machine_name, r->out.dns_domain_name);
928 werr = WERR_OK;
929 goto done;
932 d_fprintf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
933 r->in.machine_name, r->out.dns_domain_name);
935 done:
936 TALLOC_FREE(r);
937 TALLOC_FREE(ctx);
939 if (W_ERROR_IS_OK(werr)) {
940 return 0;
943 return -1;
946 static NTSTATUS net_ads_join_ok(struct net_context *c)
948 ADS_STRUCT *ads = NULL;
949 ADS_STATUS status;
951 if (!secrets_init()) {
952 DEBUG(1,("Failed to initialise secrets database\n"));
953 return NT_STATUS_ACCESS_DENIED;
956 set_cmdline_auth_info_use_machine_account(c->auth_info);
957 set_cmdline_auth_info_machine_account_creds(c->auth_info);
959 status = ads_startup(c, true, &ads);
960 if (!ADS_ERR_OK(status)) {
961 return ads_ntstatus(status);
964 ads_destroy(&ads);
965 return NT_STATUS_OK;
969 check that an existing join is OK
971 int net_ads_testjoin(struct net_context *c, int argc, const char **argv)
973 NTSTATUS status;
974 use_in_memory_ccache();
976 if (c->display_usage) {
977 d_printf("Usage:\n"
978 "net ads testjoin\n"
979 " Test if the existing join is ok\n");
980 return 0;
983 /* Display success or failure */
984 status = net_ads_join_ok(c);
985 if (!NT_STATUS_IS_OK(status)) {
986 fprintf(stderr,"Join to domain is not valid: %s\n",
987 get_friendly_nt_error_msg(status));
988 return -1;
991 printf("Join is OK\n");
992 return 0;
995 /*******************************************************************
996 Simple configu checks before beginning the join
997 ********************************************************************/
999 static WERROR check_ads_config( void )
1001 if (lp_server_role() != ROLE_DOMAIN_MEMBER ) {
1002 d_printf("Host is not configured as a member server.\n");
1003 return WERR_INVALID_DOMAIN_ROLE;
1006 if (strlen(global_myname()) > 15) {
1007 d_printf("Our netbios name can be at most 15 chars long, "
1008 "\"%s\" is %u chars long\n", global_myname(),
1009 (unsigned int)strlen(global_myname()));
1010 return WERR_INVALID_COMPUTERNAME;
1013 if ( lp_security() == SEC_ADS && !*lp_realm()) {
1014 d_fprintf(stderr, "realm must be set in in %s for ADS "
1015 "join to succeed.\n", get_dyn_CONFIGFILE());
1016 return WERR_INVALID_PARAM;
1019 return WERR_OK;
1022 /*******************************************************************
1023 Send a DNS update request
1024 *******************************************************************/
1026 #if defined(WITH_DNS_UPDATES)
1027 #include "dns.h"
1028 DNS_ERROR DoDNSUpdate(char *pszServerName,
1029 const char *pszDomainName, const char *pszHostName,
1030 const struct sockaddr_storage *sslist,
1031 size_t num_addrs );
1033 static NTSTATUS net_update_dns_internal(TALLOC_CTX *ctx, ADS_STRUCT *ads,
1034 const char *machine_name,
1035 const struct sockaddr_storage *addrs,
1036 int num_addrs)
1038 struct dns_rr_ns *nameservers = NULL;
1039 int ns_count = 0;
1040 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1041 DNS_ERROR dns_err;
1042 fstring dns_server;
1043 const char *dnsdomain = NULL;
1044 char *root_domain = NULL;
1046 if ( (dnsdomain = strchr_m( machine_name, '.')) == NULL ) {
1047 d_printf("No DNS domain configured for %s. "
1048 "Unable to perform DNS Update.\n", machine_name);
1049 status = NT_STATUS_INVALID_PARAMETER;
1050 goto done;
1052 dnsdomain++;
1054 status = ads_dns_lookup_ns( ctx, dnsdomain, &nameservers, &ns_count );
1055 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1056 /* Child domains often do not have NS records. Look
1057 for the NS record for the forest root domain
1058 (rootDomainNamingContext in therootDSE) */
1060 const char *rootname_attrs[] = { "rootDomainNamingContext", NULL };
1061 LDAPMessage *msg = NULL;
1062 char *root_dn;
1063 ADS_STATUS ads_status;
1065 if ( !ads->ldap.ld ) {
1066 ads_status = ads_connect( ads );
1067 if ( !ADS_ERR_OK(ads_status) ) {
1068 DEBUG(0,("net_update_dns_internal: Failed to connect to our DC!\n"));
1069 goto done;
1073 ads_status = ads_do_search(ads, "", LDAP_SCOPE_BASE,
1074 "(objectclass=*)", rootname_attrs, &msg);
1075 if (!ADS_ERR_OK(ads_status)) {
1076 goto done;
1079 root_dn = ads_pull_string(ads, ctx, msg, "rootDomainNamingContext");
1080 if ( !root_dn ) {
1081 ads_msgfree( ads, msg );
1082 goto done;
1085 root_domain = ads_build_domain( root_dn );
1087 /* cleanup */
1088 ads_msgfree( ads, msg );
1090 /* try again for NS servers */
1092 status = ads_dns_lookup_ns( ctx, root_domain, &nameservers, &ns_count );
1094 if ( !NT_STATUS_IS_OK(status) || (ns_count == 0)) {
1095 DEBUG(3,("net_ads_join: Failed to find name server for the %s "
1096 "realm\n", ads->config.realm));
1097 goto done;
1100 dnsdomain = root_domain;
1104 /* Now perform the dns update - we'll try non-secure and if we fail,
1105 we'll follow it up with a secure update */
1107 fstrcpy( dns_server, nameservers[0].hostname );
1109 dns_err = DoDNSUpdate(dns_server, dnsdomain, machine_name, addrs, num_addrs);
1110 if (!ERR_DNS_IS_OK(dns_err)) {
1111 status = NT_STATUS_UNSUCCESSFUL;
1114 done:
1116 SAFE_FREE( root_domain );
1118 return status;
1121 static NTSTATUS net_update_dns(TALLOC_CTX *mem_ctx, ADS_STRUCT *ads)
1123 int num_addrs;
1124 struct sockaddr_storage *iplist = NULL;
1125 fstring machine_name;
1126 NTSTATUS status;
1128 name_to_fqdn( machine_name, global_myname() );
1129 strlower_m( machine_name );
1131 /* Get our ip address (not the 127.0.0.x address but a real ip
1132 * address) */
1134 num_addrs = get_my_ip_address( &iplist );
1135 if ( num_addrs <= 0 ) {
1136 DEBUG(4,("net_update_dns: Failed to find my non-loopback IP "
1137 "addresses!\n"));
1138 return NT_STATUS_INVALID_PARAMETER;
1141 status = net_update_dns_internal(mem_ctx, ads, machine_name,
1142 iplist, num_addrs);
1143 SAFE_FREE( iplist );
1144 return status;
1146 #endif
1149 /*******************************************************************
1150 ********************************************************************/
1152 static int net_ads_join_usage(struct net_context *c, int argc, const char **argv)
1154 d_printf("net ads join [options]\n");
1155 d_printf("Valid options:\n");
1156 d_printf(" createupn[=UPN] Set the userPrincipalName attribute during the join.\n");
1157 d_printf(" The deault UPN is in the form host/netbiosname@REALM.\n");
1158 d_printf(" createcomputer=OU Precreate the computer account in a specific OU.\n");
1159 d_printf(" The OU string read from top to bottom without RDNs and delimited by a '/'.\n");
1160 d_printf(" E.g. \"createcomputer=Computers/Servers/Unix\"\n");
1161 d_printf(" NB: A backslash '\\' is used as escape at multiple levels and may\n");
1162 d_printf(" need to be doubled or even quadrupled. It is not used as a separator.\n");
1163 d_printf(" osName=string Set the operatingSystem attribute during the join.\n");
1164 d_printf(" osVer=string Set the operatingSystemVersion attribute during the join.\n");
1165 d_printf(" NB: osName and osVer must be specified together for either to take effect.\n");
1166 d_printf(" Also, the operatingSystemService attribute is also set when along with\n");
1167 d_printf(" the two other attributes.\n");
1169 return -1;
1172 /*******************************************************************
1173 ********************************************************************/
1175 int net_ads_join(struct net_context *c, int argc, const char **argv)
1177 TALLOC_CTX *ctx = NULL;
1178 struct libnet_JoinCtx *r = NULL;
1179 const char *domain = lp_realm();
1180 WERROR werr = WERR_SETUP_NOT_JOINED;
1181 bool createupn = false;
1182 const char *machineupn = NULL;
1183 const char *create_in_ou = NULL;
1184 int i;
1185 const char *os_name = NULL;
1186 const char *os_version = NULL;
1187 bool modify_config = lp_config_backend_is_registry();
1188 struct user_auth_info *ai = c->auth_info;;
1190 if (c->display_usage)
1191 return net_ads_join_usage(c, argc, argv);
1193 if (!modify_config) {
1195 werr = check_ads_config();
1196 if (!W_ERROR_IS_OK(werr)) {
1197 d_fprintf(stderr, "Invalid configuration. Exiting....\n");
1198 goto fail;
1202 if (!(ctx = talloc_init("net_ads_join"))) {
1203 d_fprintf(stderr, "Could not initialise talloc context.\n");
1204 werr = WERR_NOMEM;
1205 goto fail;
1208 if (!get_cmdline_auth_info_use_kerberos(ai)) {
1209 use_in_memory_ccache();
1212 werr = libnet_init_JoinCtx(ctx, &r);
1213 if (!W_ERROR_IS_OK(werr)) {
1214 goto fail;
1217 /* process additional command line args */
1219 for ( i=0; i<argc; i++ ) {
1220 if ( !StrnCaseCmp(argv[i], "createupn", strlen("createupn")) ) {
1221 createupn = true;
1222 machineupn = get_string_param(argv[i]);
1224 else if ( !StrnCaseCmp(argv[i], "createcomputer", strlen("createcomputer")) ) {
1225 if ( (create_in_ou = get_string_param(argv[i])) == NULL ) {
1226 d_fprintf(stderr, "Please supply a valid OU path.\n");
1227 werr = WERR_INVALID_PARAM;
1228 goto fail;
1231 else if ( !StrnCaseCmp(argv[i], "osName", strlen("osName")) ) {
1232 if ( (os_name = get_string_param(argv[i])) == NULL ) {
1233 d_fprintf(stderr, "Please supply a operating system name.\n");
1234 werr = WERR_INVALID_PARAM;
1235 goto fail;
1238 else if ( !StrnCaseCmp(argv[i], "osVer", strlen("osVer")) ) {
1239 if ( (os_version = get_string_param(argv[i])) == NULL ) {
1240 d_fprintf(stderr, "Please supply a valid operating system version.\n");
1241 werr = WERR_INVALID_PARAM;
1242 goto fail;
1245 else {
1246 domain = argv[i];
1250 if (!*domain) {
1251 d_fprintf(stderr, "Please supply a valid domain name\n");
1252 werr = WERR_INVALID_PARAM;
1253 goto fail;
1256 /* Do the domain join here */
1258 set_cmdline_auth_info_getpass(ai);
1260 r->in.domain_name = domain;
1261 r->in.create_upn = createupn;
1262 r->in.upn = machineupn;
1263 r->in.account_ou = create_in_ou;
1264 r->in.os_name = os_name;
1265 r->in.os_version = os_version;
1266 r->in.dc_name = c->opt_host;
1267 r->in.admin_account = get_cmdline_auth_info_username(ai);
1268 r->in.admin_password = get_cmdline_auth_info_password(ai);
1269 r->in.debug = true;
1270 r->in.use_kerberos = get_cmdline_auth_info_use_kerberos(ai);
1271 r->in.modify_config = modify_config;
1272 r->in.join_flags = WKSSVC_JOIN_FLAGS_JOIN_TYPE |
1273 WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE |
1274 WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED;
1276 werr = libnet_Join(ctx, r);
1277 if (!W_ERROR_IS_OK(werr)) {
1278 goto fail;
1281 /* Check the short name of the domain */
1283 if (!modify_config && !strequal(lp_workgroup(), r->out.netbios_domain_name)) {
1284 d_printf("The workgroup in %s does not match the short\n", get_dyn_CONFIGFILE());
1285 d_printf("domain name obtained from the server.\n");
1286 d_printf("Using the name [%s] from the server.\n", r->out.netbios_domain_name);
1287 d_printf("You should set \"workgroup = %s\" in %s.\n",
1288 r->out.netbios_domain_name, get_dyn_CONFIGFILE());
1291 d_printf("Using short domain name -- %s\n", r->out.netbios_domain_name);
1293 if (r->out.dns_domain_name) {
1294 d_printf("Joined '%s' to realm '%s'\n", r->in.machine_name,
1295 r->out.dns_domain_name);
1296 } else {
1297 d_printf("Joined '%s' to domain '%s'\n", r->in.machine_name,
1298 r->out.netbios_domain_name);
1301 #if defined(WITH_DNS_UPDATES)
1302 if (r->out.domain_is_ad) {
1303 /* We enter this block with user creds */
1304 ADS_STRUCT *ads_dns = NULL;
1306 if ( (ads_dns = ads_init( lp_realm(), NULL, NULL )) != NULL ) {
1307 /* kinit with the machine password */
1309 use_in_memory_ccache();
1310 if (asprintf( &ads_dns->auth.user_name, "%s$", global_myname()) == -1) {
1311 goto fail;
1313 ads_dns->auth.password = secrets_fetch_machine_password(
1314 r->out.netbios_domain_name, NULL, NULL );
1315 ads_dns->auth.realm = SMB_STRDUP( r->out.dns_domain_name );
1316 strupper_m(ads_dns->auth.realm );
1317 ads_kinit_password( ads_dns );
1320 if ( !ads_dns || !NT_STATUS_IS_OK(net_update_dns( ctx, ads_dns )) ) {
1321 d_fprintf( stderr, "DNS update failed!\n" );
1324 /* exit from this block using machine creds */
1325 ads_destroy(&ads_dns);
1327 #endif
1328 TALLOC_FREE(r);
1329 TALLOC_FREE( ctx );
1331 return 0;
1333 fail:
1334 /* issue an overall failure message at the end. */
1335 d_printf("Failed to join domain: %s\n",
1336 r && r->out.error_string ? r->out.error_string :
1337 get_friendly_werror_msg(werr));
1338 TALLOC_FREE( ctx );
1340 return -1;
1343 /*******************************************************************
1344 ********************************************************************/
1346 static int net_ads_dns_register(struct net_context *c, int argc, const char **argv)
1348 #if defined(WITH_DNS_UPDATES)
1349 ADS_STRUCT *ads;
1350 ADS_STATUS status;
1351 TALLOC_CTX *ctx;
1353 #ifdef DEVELOPER
1354 talloc_enable_leak_report();
1355 #endif
1357 if (argc > 0 || c->display_usage) {
1358 d_printf("Usage:\n"
1359 "net ads dns register\n"
1360 " Register hostname with DNS\n");
1361 return -1;
1364 if (!(ctx = talloc_init("net_ads_dns"))) {
1365 d_fprintf(stderr, "Could not initialise talloc context\n");
1366 return -1;
1369 status = ads_startup(c, true, &ads);
1370 if ( !ADS_ERR_OK(status) ) {
1371 DEBUG(1, ("error on ads_startup: %s\n", ads_errstr(status)));
1372 TALLOC_FREE(ctx);
1373 return -1;
1376 if ( !NT_STATUS_IS_OK(net_update_dns(ctx, ads)) ) {
1377 d_fprintf( stderr, "DNS update failed!\n" );
1378 ads_destroy( &ads );
1379 TALLOC_FREE( ctx );
1380 return -1;
1383 d_fprintf( stderr, "Successfully registered hostname with DNS\n" );
1385 ads_destroy(&ads);
1386 TALLOC_FREE( ctx );
1388 return 0;
1389 #else
1390 d_fprintf(stderr, "DNS update support not enabled at compile time!\n");
1391 return -1;
1392 #endif
1395 #if defined(WITH_DNS_UPDATES)
1396 DNS_ERROR do_gethostbyname(const char *server, const char *host);
1397 #endif
1399 static int net_ads_dns_gethostbyname(struct net_context *c, int argc, const char **argv)
1401 #if defined(WITH_DNS_UPDATES)
1402 DNS_ERROR err;
1404 #ifdef DEVELOPER
1405 talloc_enable_leak_report();
1406 #endif
1408 if (argc != 2 || c->display_usage) {
1409 d_printf("Usage:\n"
1410 "net ads dns gethostbyname <server> <name>\n"
1411 " Look up hostname from the AD\n"
1412 " server\tName server to use\n"
1413 " name\tName to look up\n");
1414 return -1;
1417 err = do_gethostbyname(argv[0], argv[1]);
1419 d_printf("do_gethostbyname returned %d\n", ERROR_DNS_V(err));
1420 #endif
1421 return 0;
1424 static int net_ads_dns(struct net_context *c, int argc, const char *argv[])
1426 struct functable func[] = {
1428 "register",
1429 net_ads_dns_register,
1430 NET_TRANSPORT_ADS,
1431 "Add host dns entry to AD",
1432 "net ads dns register\n"
1433 " Add host dns entry to AD"
1436 "gethostbyname",
1437 net_ads_dns_gethostbyname,
1438 NET_TRANSPORT_ADS,
1439 "Look up host",
1440 "net ads dns gethostbyname\n"
1441 " Look up host"
1443 {NULL, NULL, 0, NULL, NULL}
1446 return net_run_function(c, argc, argv, "net ads dns", func);
1449 /*******************************************************************
1450 ********************************************************************/
1452 int net_ads_printer_usage(struct net_context *c, int argc, const char **argv)
1454 d_printf(
1455 "\nnet ads printer search <printer>"
1456 "\n\tsearch for a printer in the directory\n"
1457 "\nnet ads printer info <printer> <server>"
1458 "\n\tlookup info in directory for printer on server"
1459 "\n\t(note: printer defaults to \"*\", server defaults to local)\n"
1460 "\nnet ads printer publish <printername>"
1461 "\n\tpublish printer in directory"
1462 "\n\t(note: printer name is required)\n"
1463 "\nnet ads printer remove <printername>"
1464 "\n\tremove printer from directory"
1465 "\n\t(note: printer name is required)\n");
1466 return -1;
1469 /*******************************************************************
1470 ********************************************************************/
1472 static int net_ads_printer_search(struct net_context *c, int argc, const char **argv)
1474 ADS_STRUCT *ads;
1475 ADS_STATUS rc;
1476 LDAPMessage *res = NULL;
1478 if (c->display_usage) {
1479 d_printf("Usage:\n"
1480 "net ads printer search\n"
1481 " List printers in the AD\n");
1482 return 0;
1485 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1486 return -1;
1489 rc = ads_find_printers(ads, &res);
1491 if (!ADS_ERR_OK(rc)) {
1492 d_fprintf(stderr, "ads_find_printer: %s\n", ads_errstr(rc));
1493 ads_msgfree(ads, res);
1494 ads_destroy(&ads);
1495 return -1;
1498 if (ads_count_replies(ads, res) == 0) {
1499 d_fprintf(stderr, "No results found\n");
1500 ads_msgfree(ads, res);
1501 ads_destroy(&ads);
1502 return -1;
1505 ads_dump(ads, res);
1506 ads_msgfree(ads, res);
1507 ads_destroy(&ads);
1508 return 0;
1511 static int net_ads_printer_info(struct net_context *c, int argc, const char **argv)
1513 ADS_STRUCT *ads;
1514 ADS_STATUS rc;
1515 const char *servername, *printername;
1516 LDAPMessage *res = NULL;
1518 if (c->display_usage) {
1519 d_printf("Usage:\n"
1520 "net ads printer info [printername [servername]]\n"
1521 " Display printer info from AD\n"
1522 " printername\tPrinter name or wildcard\n"
1523 " servername\tName of the print server\n");
1524 return 0;
1527 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1528 return -1;
1531 if (argc > 0) {
1532 printername = argv[0];
1533 } else {
1534 printername = "*";
1537 if (argc > 1) {
1538 servername = argv[1];
1539 } else {
1540 servername = global_myname();
1543 rc = ads_find_printer_on_server(ads, &res, printername, servername);
1545 if (!ADS_ERR_OK(rc)) {
1546 d_fprintf(stderr, "Server '%s' not found: %s\n",
1547 servername, ads_errstr(rc));
1548 ads_msgfree(ads, res);
1549 ads_destroy(&ads);
1550 return -1;
1553 if (ads_count_replies(ads, res) == 0) {
1554 d_fprintf(stderr, "Printer '%s' not found\n", printername);
1555 ads_msgfree(ads, res);
1556 ads_destroy(&ads);
1557 return -1;
1560 ads_dump(ads, res);
1561 ads_msgfree(ads, res);
1562 ads_destroy(&ads);
1564 return 0;
1567 static int net_ads_printer_publish(struct net_context *c, int argc, const char **argv)
1569 ADS_STRUCT *ads;
1570 ADS_STATUS rc;
1571 const char *servername, *printername;
1572 struct cli_state *cli;
1573 struct rpc_pipe_client *pipe_hnd;
1574 struct sockaddr_storage server_ss;
1575 NTSTATUS nt_status;
1576 TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish");
1577 ADS_MODLIST mods = ads_init_mods(mem_ctx);
1578 char *prt_dn, *srv_dn, **srv_cn;
1579 char *srv_cn_escaped = NULL, *printername_escaped = NULL;
1580 LDAPMessage *res = NULL;
1581 struct user_auth_info *ai = c->auth_info;
1583 if (argc < 1 || c->display_usage) {
1584 d_printf("Usage:\n"
1585 "net ads printer publish <printername> [servername]\n"
1586 " Publish printer in AD\n"
1587 " printername\tName of the printer\n"
1588 " servername\tName of the print server\n");
1589 talloc_destroy(mem_ctx);
1590 return -1;
1593 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1594 talloc_destroy(mem_ctx);
1595 return -1;
1598 printername = argv[0];
1600 if (argc == 2) {
1601 servername = argv[1];
1602 } else {
1603 servername = global_myname();
1606 /* Get printer data from SPOOLSS */
1608 resolve_name(servername, &server_ss, 0x20);
1610 nt_status = cli_full_connection(&cli, global_myname(), servername,
1611 &server_ss, 0,
1612 "IPC$", "IPC",
1613 get_cmdline_auth_info_username(ai),
1614 c->opt_workgroup,
1615 get_cmdline_auth_info_password(ai),
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, talloc_tos(), 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;
1804 const char *auth_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 auth_principal = get_cmdline_auth_info_username(c->auth_info);
1820 set_cmdline_auth_info_getpass(c->auth_info);
1821 auth_password = get_cmdline_auth_info_password(c->auth_info);
1823 if (argc < 1) {
1824 d_fprintf(stderr, "ERROR: You must say which username to change password for\n");
1825 return -1;
1828 user = argv[0];
1829 if (!strchr_m(user, '@')) {
1830 if (asprintf(&chr, "%s@%s", argv[0], lp_realm()) == -1) {
1831 return -1;
1833 user = chr;
1836 use_in_memory_ccache();
1837 chr = strchr_m(auth_principal, '@');
1838 if (chr) {
1839 realm = ++chr;
1840 } else {
1841 realm = lp_realm();
1844 /* use the realm so we can eventually change passwords for users
1845 in realms other than default */
1846 if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) {
1847 return -1;
1850 /* we don't actually need a full connect, but it's the easy way to
1851 fill in the KDC's addresss */
1852 ads_connect(ads);
1854 if (!ads->config.realm) {
1855 d_fprintf(stderr, "Didn't find the kerberos server!\n");
1856 ads_destroy(&ads);
1857 return -1;
1860 if (argv[1]) {
1861 new_password = (char *)argv[1];
1862 } else {
1863 if (asprintf(&prompt, "Enter new password for %s:", user) == -1) {
1864 return -1;
1866 new_password = getpass(prompt);
1867 free(prompt);
1870 ret = kerberos_set_password(ads->auth.kdc_server, auth_principal,
1871 auth_password, user, new_password, ads->auth.time_offset);
1872 if (!ADS_ERR_OK(ret)) {
1873 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1874 ads_destroy(&ads);
1875 return -1;
1878 d_printf("Password change for %s completed.\n", user);
1879 ads_destroy(&ads);
1881 return 0;
1884 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
1886 ADS_STRUCT *ads;
1887 char *host_principal;
1888 fstring my_name;
1889 ADS_STATUS ret;
1891 if (c->display_usage) {
1892 d_printf("Usage:\n"
1893 "net ads changetrustpw\n"
1894 " Change the machine account's trust password\n");
1895 return 0;
1898 if (!secrets_init()) {
1899 DEBUG(1,("Failed to initialise secrets database\n"));
1900 return -1;
1903 set_cmdline_auth_info_use_machine_account(c->auth_info);
1905 use_in_memory_ccache();
1907 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
1908 return -1;
1911 fstrcpy(my_name, global_myname());
1912 strlower_m(my_name);
1913 if (asprintf(&host_principal, "%s$@%s", my_name, ads->config.realm) == -1) {
1914 ads_destroy(&ads);
1915 return -1;
1917 d_printf("Changing password for principal: %s\n", host_principal);
1919 ret = ads_change_trust_account_password(ads, host_principal);
1921 if (!ADS_ERR_OK(ret)) {
1922 d_fprintf(stderr, "Password change failed: %s\n", ads_errstr(ret));
1923 ads_destroy(&ads);
1924 SAFE_FREE(host_principal);
1925 return -1;
1928 d_printf("Password change for principal %s succeeded.\n", host_principal);
1930 if (USE_SYSTEM_KEYTAB) {
1931 d_printf("Attempting to update system keytab with new password.\n");
1932 if (ads_keytab_create_default(ads)) {
1933 d_printf("Failed to update system keytab.\n");
1937 ads_destroy(&ads);
1938 SAFE_FREE(host_principal);
1940 return 0;
1944 help for net ads search
1946 static int net_ads_search_usage(struct net_context *c, int argc, const char **argv)
1948 d_printf(
1949 "\nnet ads search <expression> <attributes...>\n"
1950 "\nPerform a raw LDAP search on a ADS server and dump the results.\n"
1951 "The expression is a standard LDAP search expression, and the\n"
1952 "attributes are a list of LDAP fields to show in the results.\n\n"
1953 "Example: net ads search '(objectCategory=group)' sAMAccountName\n\n"
1955 net_common_flags_usage(c, argc, argv);
1956 return -1;
1961 general ADS search function. Useful in diagnosing problems in ADS
1963 static int net_ads_search(struct net_context *c, int argc, const char **argv)
1965 ADS_STRUCT *ads;
1966 ADS_STATUS rc;
1967 const char *ldap_exp;
1968 const char **attrs;
1969 LDAPMessage *res = NULL;
1971 if (argc < 1 || c->display_usage) {
1972 return net_ads_search_usage(c, argc, argv);
1975 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
1976 return -1;
1979 ldap_exp = argv[0];
1980 attrs = (argv + 1);
1982 rc = ads_do_search_all(ads, ads->config.bind_path,
1983 LDAP_SCOPE_SUBTREE,
1984 ldap_exp, attrs, &res);
1985 if (!ADS_ERR_OK(rc)) {
1986 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
1987 ads_destroy(&ads);
1988 return -1;
1991 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
1993 /* dump the results */
1994 ads_dump(ads, res);
1996 ads_msgfree(ads, res);
1997 ads_destroy(&ads);
1999 return 0;
2004 help for net ads search
2006 static int net_ads_dn_usage(struct net_context *c, int argc, const char **argv)
2008 d_printf(
2009 "\nnet ads dn <dn> <attributes...>\n"
2010 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2011 "The DN standard LDAP DN, and the attributes are a list of LDAP fields \n"
2012 "to show in the results\n\n"
2013 "Example: net ads dn 'CN=administrator,CN=Users,DC=my,DC=domain' sAMAccountName\n\n"
2014 "Note: the DN must be provided properly escaped. See RFC 4514 for details\n\n"
2016 net_common_flags_usage(c, argc, argv);
2017 return -1;
2022 general ADS search function. Useful in diagnosing problems in ADS
2024 static int net_ads_dn(struct net_context *c, int argc, const char **argv)
2026 ADS_STRUCT *ads;
2027 ADS_STATUS rc;
2028 const char *dn;
2029 const char **attrs;
2030 LDAPMessage *res = NULL;
2032 if (argc < 1 || c->display_usage) {
2033 return net_ads_dn_usage(c, argc, argv);
2036 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2037 return -1;
2040 dn = argv[0];
2041 attrs = (argv + 1);
2043 rc = ads_do_search_all(ads, dn,
2044 LDAP_SCOPE_BASE,
2045 "(objectclass=*)", attrs, &res);
2046 if (!ADS_ERR_OK(rc)) {
2047 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2048 ads_destroy(&ads);
2049 return -1;
2052 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2054 /* dump the results */
2055 ads_dump(ads, res);
2057 ads_msgfree(ads, res);
2058 ads_destroy(&ads);
2060 return 0;
2064 help for net ads sid search
2066 static int net_ads_sid_usage(struct net_context *c, int argc, const char **argv)
2068 d_printf(
2069 "\nnet ads sid <sid> <attributes...>\n"
2070 "\nperform a raw LDAP search on a ADS server and dump the results\n"
2071 "The SID is in string format, and the attributes are a list of LDAP fields \n"
2072 "to show in the results\n\n"
2073 "Example: net ads sid 'S-1-5-32' distinguishedName\n\n"
2075 net_common_flags_usage(c, argc, argv);
2076 return -1;
2081 general ADS search function. Useful in diagnosing problems in ADS
2083 static int net_ads_sid(struct net_context *c, int argc, const char **argv)
2085 ADS_STRUCT *ads;
2086 ADS_STATUS rc;
2087 const char *sid_string;
2088 const char **attrs;
2089 LDAPMessage *res = NULL;
2090 DOM_SID sid;
2092 if (argc < 1 || c->display_usage) {
2093 return net_ads_sid_usage(c, argc, argv);
2096 if (!ADS_ERR_OK(ads_startup(c, false, &ads))) {
2097 return -1;
2100 sid_string = argv[0];
2101 attrs = (argv + 1);
2103 if (!string_to_sid(&sid, sid_string)) {
2104 d_fprintf(stderr, "could not convert sid\n");
2105 ads_destroy(&ads);
2106 return -1;
2109 rc = ads_search_retry_sid(ads, &res, &sid, attrs);
2110 if (!ADS_ERR_OK(rc)) {
2111 d_fprintf(stderr, "search failed: %s\n", ads_errstr(rc));
2112 ads_destroy(&ads);
2113 return -1;
2116 d_printf("Got %d replies\n\n", ads_count_replies(ads, res));
2118 /* dump the results */
2119 ads_dump(ads, res);
2121 ads_msgfree(ads, res);
2122 ads_destroy(&ads);
2124 return 0;
2127 static int net_ads_keytab_flush(struct net_context *c, int argc, const char **argv)
2129 int ret;
2130 ADS_STRUCT *ads;
2132 if (c->display_usage) {
2133 d_printf("Usage:\n"
2134 "net ads keytab flush\n"
2135 " Delete the whole keytab\n");
2136 return 0;
2139 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2140 return -1;
2142 ret = ads_keytab_flush(ads);
2143 ads_destroy(&ads);
2144 return ret;
2147 static int net_ads_keytab_add(struct net_context *c, int argc, const char **argv)
2149 int i;
2150 int ret = 0;
2151 ADS_STRUCT *ads;
2153 if (c->display_usage) {
2154 d_printf("Usage:\n"
2155 "net ads keytab add <principal> [principal ...]\n"
2156 " Add principals to local keytab\n"
2157 " principal\tKerberos principal to add to "
2158 "keytab\n");
2159 return 0;
2162 d_printf("Processing principals to add...\n");
2163 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2164 return -1;
2166 for (i = 0; i < argc; i++) {
2167 ret |= ads_keytab_add_entry(ads, argv[i]);
2169 ads_destroy(&ads);
2170 return ret;
2173 static int net_ads_keytab_create(struct net_context *c, int argc, const char **argv)
2175 ADS_STRUCT *ads;
2176 int ret;
2178 if (c->display_usage) {
2179 d_printf("Usage:\n"
2180 "net ads keytab create\n"
2181 " Create new default keytab\n");
2182 return 0;
2185 if (!ADS_ERR_OK(ads_startup(c, true, &ads))) {
2186 return -1;
2188 ret = ads_keytab_create_default(ads);
2189 ads_destroy(&ads);
2190 return ret;
2193 static int net_ads_keytab_list(struct net_context *c, int argc, const char **argv)
2195 const char *keytab = NULL;
2197 if (c->display_usage) {
2198 d_printf("Usage:\n"
2199 "net ads keytab list [keytab]\n"
2200 " List a local keytab\n"
2201 " keytab\tKeytab to list\n");
2202 return 0;
2205 if (argc >= 1) {
2206 keytab = argv[0];
2209 return ads_keytab_list(keytab);
2213 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2215 struct functable func[] = {
2217 "add",
2218 net_ads_keytab_add,
2219 NET_TRANSPORT_ADS,
2220 "Add a service principal",
2221 "net ads keytab add\n"
2222 " Add a service principal"
2225 "create",
2226 net_ads_keytab_create,
2227 NET_TRANSPORT_ADS,
2228 "Create a fresh keytab",
2229 "net ads keytab create\n"
2230 " Create a fresh keytab"
2233 "flush",
2234 net_ads_keytab_flush,
2235 NET_TRANSPORT_ADS,
2236 "Remove all keytab entries",
2237 "net ads keytab flush\n"
2238 " Remove all keytab entries"
2241 "list",
2242 net_ads_keytab_list,
2243 NET_TRANSPORT_ADS,
2244 "List a keytab",
2245 "net ads keytab list\n"
2246 " List a keytab"
2248 {NULL, NULL, 0, NULL, NULL}
2251 if (!USE_KERBEROS_KEYTAB) {
2252 d_printf("\nWarning: \"kerberos method\" must be set to a "
2253 "keytab method to use keytab functions.\n");
2256 return net_run_function(c, argc, argv, "net ads keytab", func);
2259 static int net_ads_kerberos_renew(struct net_context *c, int argc, const char **argv)
2261 int ret = -1;
2263 if (c->display_usage) {
2264 d_printf("Usage:\n"
2265 "net ads kerberos renew\n"
2266 " Renew TGT from existing credential cache\n");
2267 return 0;
2270 ret = smb_krb5_renew_ticket(NULL, NULL, NULL, NULL);
2271 if (ret) {
2272 d_printf("failed to renew kerberos ticket: %s\n",
2273 error_message(ret));
2275 return ret;
2278 static int net_ads_kerberos_pac(struct net_context *c, int argc, const char **argv)
2280 struct PAC_DATA *pac = NULL;
2281 struct PAC_LOGON_INFO *info = NULL;
2282 TALLOC_CTX *mem_ctx = NULL;
2283 NTSTATUS status;
2284 int ret = -1;
2285 struct user_auth_info *ai = c->auth_info;
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 set_cmdline_auth_info_getpass(ai);
2301 status = kerberos_return_pac(mem_ctx,
2302 get_cmdline_auth_info_username(ai),
2303 get_cmdline_auth_info_password(ai),
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;
2336 struct user_auth_info *ai = c->auth_info;
2338 if (c->display_usage) {
2339 d_printf("Usage:\n"
2340 "net ads kerberos kinit\n"
2341 " Get Ticket Granting Ticket (TGT) for the user\n");
2342 return 0;
2345 mem_ctx = talloc_init("net_ads_kerberos_kinit");
2346 if (!mem_ctx) {
2347 goto out;
2350 set_cmdline_auth_info_getpass(ai);
2352 ret = kerberos_kinit_password_ext(get_cmdline_auth_info_username(ai),
2353 get_cmdline_auth_info_password(ai),
2355 NULL,
2356 NULL,
2357 NULL,
2358 true,
2359 true,
2360 2592000, /* one month */
2361 &status);
2362 if (ret) {
2363 d_printf("failed to kinit password: %s\n",
2364 nt_errstr(status));
2366 out:
2367 return ret;
2370 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2372 struct functable func[] = {
2374 "kinit",
2375 net_ads_kerberos_kinit,
2376 NET_TRANSPORT_ADS,
2377 "Retrieve Ticket Granting Ticket (TGT)",
2378 "net ads kerberos kinit\n"
2379 " Receive Ticket Granting Ticket (TGT)"
2382 "renew",
2383 net_ads_kerberos_renew,
2384 NET_TRANSPORT_ADS,
2385 "Renew Ticket Granting Ticket from credential cache"
2386 "net ads kerberos renew\n"
2387 " Renew Ticket Granting Ticket from credential cache"
2390 "pac",
2391 net_ads_kerberos_pac,
2392 NET_TRANSPORT_ADS,
2393 "Dump Kerberos PAC",
2394 "net ads kerberos pac\n"
2395 " Dump Kerberos PAC"
2397 {NULL, NULL, 0, NULL, NULL}
2400 return net_run_function(c, argc, argv, "net ads kerberos", func);
2403 int net_ads(struct net_context *c, int argc, const char **argv)
2405 struct functable func[] = {
2407 "info",
2408 net_ads_info,
2409 NET_TRANSPORT_ADS,
2410 "Display details on remote ADS server",
2411 "net ads info\n"
2412 " Display details on remote ADS server"
2415 "join",
2416 net_ads_join,
2417 NET_TRANSPORT_ADS,
2418 "Join the local machine to ADS realm",
2419 "net ads join\n"
2420 " Join the local machine to ADS realm"
2423 "testjoin",
2424 net_ads_testjoin,
2425 NET_TRANSPORT_ADS,
2426 "Validate machine account",
2427 "net ads testjoin\n"
2428 " Validate machine account"
2431 "leave",
2432 net_ads_leave,
2433 NET_TRANSPORT_ADS,
2434 "Remove the local machine from ADS",
2435 "net ads leave\n"
2436 " Remove the local machine from ADS"
2439 "status",
2440 net_ads_status,
2441 NET_TRANSPORT_ADS,
2442 "Display machine account details",
2443 "net ads status\n"
2444 " Display machine account details"
2447 "user",
2448 net_ads_user,
2449 NET_TRANSPORT_ADS,
2450 "List/modify users",
2451 "net ads user\n"
2452 " List/modify users"
2455 "group",
2456 net_ads_group,
2457 NET_TRANSPORT_ADS,
2458 "List/modify groups",
2459 "net ads group\n"
2460 " List/modify groups"
2463 "dns",
2464 net_ads_dns,
2465 NET_TRANSPORT_ADS,
2466 "Issue dynamic DNS update",
2467 "net ads dns\n"
2468 " Issue dynamic DNS update"
2471 "password",
2472 net_ads_password,
2473 NET_TRANSPORT_ADS,
2474 "Change user passwords",
2475 "net ads password\n"
2476 " Change user passwords"
2479 "changetrustpw",
2480 net_ads_changetrustpw,
2481 NET_TRANSPORT_ADS,
2482 "Change trust account password",
2483 "net ads changetrustpw\n"
2484 " Change trust account password"
2487 "printer",
2488 net_ads_printer,
2489 NET_TRANSPORT_ADS,
2490 "List/modify printer entries",
2491 "net ads printer\n"
2492 " List/modify printer entries"
2495 "search",
2496 net_ads_search,
2497 NET_TRANSPORT_ADS,
2498 "Issue LDAP search using filter",
2499 "net ads search\n"
2500 " Issue LDAP search using filter"
2503 "dn",
2504 net_ads_dn,
2505 NET_TRANSPORT_ADS,
2506 "Issue LDAP search by DN",
2507 "net ads dn\n"
2508 " Issue LDAP search by DN"
2511 "sid",
2512 net_ads_sid,
2513 NET_TRANSPORT_ADS,
2514 "Issue LDAP search by SID",
2515 "net ads sid\n"
2516 " Issue LDAP search by SID"
2519 "workgroup",
2520 net_ads_workgroup,
2521 NET_TRANSPORT_ADS,
2522 "Display workgroup name",
2523 "net ads workgroup\n"
2524 " Display the workgroup name"
2527 "lookup",
2528 net_ads_lookup,
2529 NET_TRANSPORT_ADS,
2530 "Perfom CLDAP query on DC",
2531 "net ads lookup\n"
2532 " Find the ADS DC using CLDAP lookups"
2535 "keytab",
2536 net_ads_keytab,
2537 NET_TRANSPORT_ADS,
2538 "Manage local keytab file",
2539 "net ads keytab\n"
2540 " Manage local keytab file"
2543 "gpo",
2544 net_ads_gpo,
2545 NET_TRANSPORT_ADS,
2546 "Manage group policy objects",
2547 "net ads gpo\n"
2548 " Manage group policy objects"
2551 "kerberos",
2552 net_ads_kerberos,
2553 NET_TRANSPORT_ADS,
2554 "Manage kerberos keytab",
2555 "net ads kerberos\n"
2556 " Manage kerberos keytab"
2558 {NULL, NULL, 0, NULL, NULL}
2561 return net_run_function(c, argc, argv, "net ads", func);
2564 #else
2566 static int net_ads_noads(void)
2568 d_fprintf(stderr, "ADS support not compiled in\n");
2569 return -1;
2572 int net_ads_keytab(struct net_context *c, int argc, const char **argv)
2574 return net_ads_noads();
2577 int net_ads_kerberos(struct net_context *c, int argc, const char **argv)
2579 return net_ads_noads();
2582 int net_ads_changetrustpw(struct net_context *c, int argc, const char **argv)
2584 return net_ads_noads();
2587 int net_ads_join(struct net_context *c, int argc, const char **argv)
2589 return net_ads_noads();
2592 int net_ads_user(struct net_context *c, int argc, const char **argv)
2594 return net_ads_noads();
2597 int net_ads_group(struct net_context *c, int argc, const char **argv)
2599 return net_ads_noads();
2602 /* this one shouldn't display a message */
2603 int net_ads_check(struct net_context *c)
2605 return -1;
2608 int net_ads_check_our_domain(struct net_context *c)
2610 return -1;
2613 int net_ads(struct net_context *c, int argc, const char **argv)
2615 return net_ads_noads();
2618 #endif /* WITH_ADS */